Skip to content

Basic usage

Josh Hiles edited this page Dec 23, 2023 · 1 revision

Let's pretend you're changing the way you handle permissions in a large web app. Tests can help guide your refactoring, but you really want to compare the current and refactored behaviors under load.

using GitHub;

...

public bool CanAccess(IUser user)
{
    return Scientist.Science<bool>("widget-permissions", experiment =>
    {
        experiment.Use(() => IsCollaborator(user)); // old way
        experiment.Try(() => HasAccess(user)); // new way
    }); // returns the control value
}

Wrap a Use block around the code's original behavior, and wrap Try around the new behavior. Invoking Scientist.Science<T> will always return whatever the Use block returns, but it does a bunch of stuff behind the scenes:

  • It decides whether or not to run the Try block,
  • Randomizes the order in which Use and Try blocks are run,
  • Measures the durations of all behaviors,
  • Compares the result of Try to the result of Use,
  • Swallows (but records) any exceptions raised in the Try block, and
  • Publishes all this information.

The Use block is called the control. The Try block is called the candidate.

If you don't declare any Try blocks, none of the Scientist machinery is invoked and the control value is always returned.