Add callback concept and use it for segmentation
There's actually a couple ways we might want to define segmentation logic.
This is the one that made the most sense to consider first, and it's been built on top of ActiveSupport::Callbacks
(e.g. before_filter
in ActionController
and after_commit
in ActiveRecord
etc.)
Anyway, here are some of the ways we might want to implement segmentation logic over time:
- assign a variant if the segment callback returns true (the one that's implemented here)
- after a variant is assigned, determine if the subject should be included in the test at all
Both options seem to have value, and probably have different performance implications. This work is primarily a spike on how we can / should probably approach 1. For option 2, I'm unsure what to call this, but ultimately this comes down to a performance question and what we might end up doing the most. So I'm going to let this emerge over time, and we should keep it in the back of our heads.
Documentation will come later, when it's all resolved and I think we can finalize the concepts a bit.
To expand on the behavior of this a bit more, this is an early terminating callback chain. Meaning that as soon as one hits, we say that's the variant we're going to provide. There's probably some useful discussion there as well, but here's a couple examples:
segment :jeremy, variant: :variant1
segment :account_age, variant: :variant2
private
def jeremy
context.actor.username == 'jejacks0n'
end
def account_age
context.actor.created_at <= 2.weeks.ago
end
note: the example here isn't fully accurate yet, but will be in terms of looking up missing methods in context values.
My account age will never be checked if my user was to be given to this experiment, which means I'd never make it into variant2
. This choice is driven by performance, and if you want to change the priority, you'd just swap the order of calls to segment.
I think early termination is a better behavior than the alternative, which I guess I'd call "additive", and so that's why I've taken that approach here.