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.
Here's a quick and dirty example of how to Science!
varExperiment=require('node-scientist').Experimentvarexperiment=newExperiment('getData')// use: the control. value will be returned by `.run`.experiment.use(function(){returnPromise.resolve().return(true)})// try: the candidate. value will be reported in `.publish`.experiment.try(function(){returnPromise.resolve().delay(10).return(false)})// run: run the experiment.experiment.run().then(function(result){// result === true, from `.use`.})varScientist=require('node-scientist')functionMyModel(){}util.inherits(MyModel,Scientist)MyModel.prototype.myMethod=function(cb){varexperiment=this.science('myMethod',{Experiment: MyExperiment})// use: the control. value will be returned by `.run`experiment.use(function(){returnPromise.resolve().delay(10).return(7)})// try: the candidate. value will be reported in `.publish`.experiment.try(function(){returnPromise.resolve().delay(5).throw(newError('foo'))})// run: run the experiment.// NOTE: bluebird allows `.asCallback`, which can help in models w/ callbacks.experiment.run().asCallback(cb)}varm=newMyModel()m.myMethod(function(err,value){// err === undefined, candidate error is not passed through.// value === 7, from `.use`.})A very simple publisher that will print results to the screen.
varExperiment=require('node-scientist').Experimentvarfind=require('101/find')functionMyExperiment(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){varcontrol=find(result.observations,hasProperties({name: 'control'}))varcandidate=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)returnPromise.resolve(true)}This publisher is used like so:
// as the first case, with just an Experiment:varexperiment=newMyExperiment('foobar')// if you want to include the Scientist in the model:SomeModel.prototype.myMethod=function(cb){varexperiment=this.science('myMethod',{Experiment: MyExperiment})// and continue with the experiment...}