github / scientist
git clone https://github.com/github/scientist.git
v1.6.5 · 1y ago
🔥 on GitHub Trending today
:microscope: A Ruby library for carefully refactoring critical paths.
+1
stars, 24h · #546
—
stars, 7 days
—
stars, 30 days
7.8k
★ total
508
forks · 17 open issues
Star history starts 2026-10-20; the chart appears after the second daily snapshot.
LanguageRuby
LicenseMIT
Created2014-02-05 (12y ago)
Last push4d ago
Watchers436
OwnerOrganization
Seen on GitHub Trending
- 2026-10-20 — #11 daily in ruby · +1 ★
GitHub topics
Links
README excerpt
# Scientist! A Ruby library for carefully refactoring critical paths. ## How do I science? 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. [code] Wrap a `use` block around the code's original behavior, and wrap `try` around the new behavior. `experiment.run` 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 wall time and cpu time of all behaviors in seconds, * Compares the result of `try` to the result of `use`, * Swallow and record exceptions raised in the `try` block when overriding `raised`, and * Publishes all this information. The `use` block is called the **control**. The `try` block is called the **candidate**. Creating an experiment is wordy, but when you include the `Scientist` module, the `science` helper will instantiate an experiment and call `run` for you: [code] If you don't declare any `try` blocks, none of the Scientist machinery is invoked and the control value is always returned. ## Making science useful The examples above will run, but they're not really *doing* anything. The `try` blocks don't run yet and none of the results get published. Replace the default experiment implementation to control execution and reporting: [code] When `Scientist::Experiment` is included in a class, it automatically sets it as the default implementation via `Scientist::Experiment.set_default`. This `set_default` call is skipped if you include `Scientist::Experiment` in a module. Now calls to the `science` helper will load instances of `MyExperiment`. ### Controlling comparison Scientist compares control and candidate values using `==`. To override this behavior, use `compare` to define how to compare observed values instead: [code] If either the control block or candidate block raises an error, Scientist compares the two observations' classes and messages using `==`. To override this behavior, use `compare_errors` to define how to compare observed errors instead: [code] ### Adding context Results aren't very useful without some way to identify them. Use the `context` method to add to or retrieve the context for an experiment: [code] `context` takes a Symbol-keyed Hash of extra data. The data is available in `Experiment#publish` via the `context` method. If you're using the `science` helper a lot in a class, you can provide a default context: [code] The `widget-permissions` and `widget-destruction` experiments will both have a `:widget` key in their contexts. ### Expensive setup If an experiment requires expensive setup that should only occur when the experiment is going to be run, define it with the `before_run` method: [code] ### Keeping it clean Sometimes you don't want to store the full value for lat