Modesty is a really simple metrics and a/b testing framework that doesn't really do all that much. It was inspired by assaf's Vanity (github.com/assaf/vanity).
A metric keeps track of things that happen, and ties in and disaggregates many different types of data. Define a metric with:
Modesty.new_metric :foo
Your metric will now be available as Modesty.metrics[:foo]
.
You can track it with
Modesty.track! :foo`,
You can get a raw count with
Modesty.metrics[:foo].count`.
You can track multiple counts with Modesty.track! :foo, 7
,
or, if you prefer, Modesty.track! :foo, :count => 7
.
Simple, huh?
You can also pass in any sort of data when you track your metric. For example,
Modesty.track! :product_page_viewed, :with => {:product_id => 500, :seller_id => 278}
This provides you with a few more granular methods.
m = Modesty.metrics[:product_page_viewed]
m.unique :product_ids # => number of unique product_ids that were tracked
m.all :product_ids # => the actual ids that were tracked
m.aggregate_by :product_ids # => a hash of {product_id => tracks for this product id}
m.distribution_by :product_ids # => equivalent to aggregate_by(:product_ids).values.histogram
TODO: submetrics
To save you some hassle, Modesty keeps around a global identity in Modesty.identity
.
You can set the identity with Modesty.identify! id
,
where id
is either an integer (i.e. the id of the current user) or nil
for guests.
When the identity is present, all metrics tracked will get a :user
parameter passed in.
This makes it really easy to call m.unique :users
and such,
without having to pass it in every time.
To override this, just call Modesty.track! :metric, :with => {:user => other_user}
.
If you're using Rails, I recommend putting a before_filter
on ApplicationController
that does something akin to Modesty.identify! viewer.id
.
Experiments are really the point of Modesty. With an experiment, you separate your users into experiment groups and track how each group performs on a given set of metrics. Modesty will ensure that
- each group contains roughly the same number of users
- Each user has a consistent experience
- All specified metrics can be disaggregated by experiment group.
Here's how you make an experiment:
Modesty.new_experiment :button_size do |e|
e.metrics :conversion, :view
e.alternatives :huge, :medium, :small
end
Then, you can do something like this (in a controller, say)
button_size = Modesty.experiment :button_size do |e|
e.group :huge do
9001
end
e.group :medium do
1337
end
e.group :small do
2
end
end
This code will use Modesty.identity
to determine the appropriate experiment group,
and run the corresponding block.
All your tracking data will automagically be disaggregated into
Modesty.metrics[:conversion/:button_size/:huge]
Modesty.metrics[:conversion/:button_size/:medium]
Modesty.metrics[:conversion/:button_size/:small]
TODO.
##Datastores and config
Right now there are two datastores available: Redis and a sweet mock Redis for testing. To switch between them, use
Modesty.data = :redis
Modesty.data = :mock
If you need to pass in more options, use
Modesty.set_store :redis, :port => 8888, :host => '123.123.123.1'
By default, Modesty looks in configy/modesty.yml for something like:
datastore:
type: redis
port: 6739
host: localhost
paths:
experiments: modesty/experiments
metrics: modesty/metrics
In this, the default setup, Modesty will look for experiments
in #{Rails.root}/modesty/experiments, and metrics in #{Rails.root}/modesty/metrics.
If no config file is found, or you omit something, Modesty will use these settings.
Everything in the datastore:
stanza (sans type: redis) will be passed as options to Redis.new.
Have fun!