Skip to content

Latest commit

 

History

History
99 lines (79 loc) · 3.66 KB

README.md

File metadata and controls

99 lines (79 loc) · 3.66 KB

Scientist

Build Status Coverage Status js-standard-style NPM Version

A Javascript library for carefully refactoring critical paths. Influenced heavily from github/scientist.

Scientist is built with and accepts Promises (or Functions that return Promises) in any experiment.

How to Science!

Here's a quick and dirty example of how to Science!

var Experiment = require('node-scientist').Experiment

var experiment = new Experiment('getData')
// use: the control. value will be returned by `.run`.
experiment.use(function () { return Promise.resolve().return(true) })
// try: the candidate. value will be reported in `.publish`.
experiment.try(function () { return Promise.resolve().delay(10).return(false) })
// run: run the experiment.
experiment.run()
  .then(function (result) {
    // result === true, from `.use`.
  })

Science within Models

var Scientist = require('node-scientist')

function MyModel () {}
util.inherits(MyModel, Scientist)

MyModel.prototype.myMethod = function (cb) {
  var experiment = this.science('myMethod', { Experiment: MyExperiment })
  // use: the control. value will be returned by `.run`
  experiment.use(function () { return Promise.resolve().delay(10).return(7) })
  // try: the candidate. value will be reported in `.publish`.
  experiment.try(function () { return Promise.resolve().delay(5).throw(new Error('foo')) })
  // run: run the experiment.
  // NOTE: bluebird allows `.asCallback`, which can help in models w/ callbacks.
  experiment.run().asCallback(cb)
}

var m = new MyModel()
m.myMethod(function (err, value) {
  // err === undefined, candidate error is not passed through.
  // value === 7, from `.use`.
})

Publishing Results

A very simple publisher that will print results to the screen.

var Experiment = require('node-scientist').Experiment
var find = require('101/find')

function MyExperiment (name) {
  Experiment.call(this, name)
}
util.inherits(MyExperiment, Experiment)

/**
 * Publisher function. Takes a result, must return a Promise.
 * @param {Result} result Result object from Scientist.
 * @return {Promise} Promise resolved when publishing is done.
 */
MyExperiment.prototype.publish = function (result) {
  var control = find(result.observations, hasProperties({ name: 'control' }))
  var candidate = find(result.observations, hasProperties({ name: 'candidate' }))
  console.log('Results:')
  console.log('Correctness (were the candidates correct?):', !result.mismatched() ? 'yes' : 'no')
  console.log('Values (control, candidate):', control.value, candidate.value)
  console.log('Candidate Time:', candidate.duration)
  console.log('Control Time:', control.duration)
  console.log('Improvement Time (+larger is better):', control.duration - candidate.duration)
  return Promise.resolve(true)
}

This publisher is used like so:

// as the first case, with just an Experiment:
var experiment = new MyExperiment('foobar')

// if you want to include the Scientist in the model:
SomeModel.prototype.myMethod = function (cb) {
  var experiment = this.science('myMethod', { Experiment: MyExperiment })
  // and continue with the experiment...
}