Skip to content
Michael Best edited this page Feb 3, 2023 · 3 revisions

What's Science all about?

Do you have an old project? Maybe a project that you think can be improved?

It's sometimes difficult to improve upon existing code, without running the risks of breaking functionality. That's where Scientist comes in. Scientist lets your run your existing code, and your newly proposed code in parallel. Comparing the results of both to ensure that your functionality remains consistent. It's a sharp knife in the refactorer's toolkit.

Until you're happy that your new code is functioning as it should be, Scientist will continue to execute your old code. Your application won't feel any different.

Case Study

Let's imagine that we have the following snippet of code in our website.

$template = 'Welcome to the site, <name>!';

$name = 'Dayle';

echo str_replace('<name>', 'Dayle', $template);

What a lovely greeting app! Except.. well. It could be better, couldn't it? I wonder if using a preg_replace() might make it better? A little faster maybe?

Why don't we create an experiment to find out? Let's extract our code into two callbacks to prepare it for our Scientist.

/**
 * We'll create a control callable. This will contain
 * the code that we know and trust.
 */
$control = function($template, $name) {
  return str_replace('<name>', $name, $template);
};

/**
 * Next, let's create a trial callable. It's our
 * potentially risky, potentially awesome code.
 */
$trial = function($template, $name) {
 return preg_replace('/\<name\>/', $name, $template); 
};

Wrapping our existing code in a closure is a great way of making a callback that can be used with scientist. We could always use the array callback notation to call a class method instead, if we so wished.

We've created two callables. One contains our old code, and the other contains our new preg_replace() powered code. We've got the makings of a fine experiment, so let's set up the laboratory and do some science.

/**
 * First we need to create a new Laboratory instance.
 * Here's where we're going to be doing our science.
 */
$lab = new \Scientist\Laboratory;

/**
 * Let's define a new experiment, and pass it our
 * control and trial callables.
 */
$experiment = $lab->experiment('Greet a user by name.')
  ->control($control)
  ->trial('Use preg_replace.', $trial);

/**
 * Next, we'll run the experiment, passing our
 * parameters in. We can use the result to
 * greet our user.
 */
echo $experiment->run($template, $name);

There's a few things happening here. Let's step through them slowly.

On line seven we're created a brand new Laboratory instance.

$lab = new \Scientist\Laboratory;

We need one of these to define a new experiment.

Next, we use the Laboratory to define a new experiment. We pass an experiment name to the experiment() method, the control callable to the control() method, and the trial callable to the trial() method along with a helpful trial name.

We could provide as many alternate trials as we like, but for simplicity sake, I'll only be using one in this example. We'd just keep chaining the trial() methods.

Finally, we run() the experiment.

echo $experiment->run($template, $name);

The parameters we pass to the run() method will be given to both our control and trial callables. It's done by magic! We don't need to worry about that.

Let's examine a few facts.

  • All control and trial callables will be executed when an experiment runs.
  • Only the control method will return a value from the experiment.
  • The trial callables will never output values to the rest of the codebase.
  • Trial callables will have their output compared with the control's, automatically.

The result of run() will be the output from our control callable. The code that we know and trust. The code that's safe to run for our users.

Our trials will be executed too, but instead of using the result, it will be compared with the control, and stored (using Journals) for later examination.

We can continue to examine the results from our experiment. The speed of the trials, whether the resulting values match reliably, whether they use too much memory, and tweak our experiment code as needed until the trial is an identically (or better) performing match for the control.

At this point, we can safely remove our experiment, and run only the new, now successful 'trial' code.

We have not, at any point, exposed our users to the experimental code until we are absolutely certain that it functions as it's supposed to.

That is Science.

Clone this wiki locally