This extension is application component that provides integration with Swivel. Swivel is a system for tracking feature flags and managing users into cohorts which can be easily assigned to the various features, allowing for canary releases and easy A/B testing.
Requirements ¶
The Yii2-Swivel extension is built for Yii 2.0+ - If you need swivel for Yii 1.1+ versions, check out yii-swivel instead.
This extension can be installed by requiring the package via composer:
composer require "dhluther/yii2-swivel":"~1"
Usage ¶
Add the swivel component to your application components list. When a user accesses the site, they will be randomly assigned a bucket (from 1 to 10). If your users are registered and have persistent data, you should assign them a permanent bucket id and then configure the SwivelComponent's 'userBucketProperty' property to pull the proper value from your Yii::$app->user model. (Note: You can override the guest bucket assignment of the component by putting a custom getXXX method on your web user model). If that property is not defined, it will store the user's random bucket assignment to the session.
'swivel' => [
'class'=>'dhluther\swivel\SwivelComponent'
],
If you need to know what bucket the current user has been assigned to, you can access it via Yii::$app->swivel->bucketIndex
The swivel features can be used to toggle between callable methods, or you can use it for simple A or B responses, i.e.,
protected function getFeatureEnabled()
{
return Yii::$app->swivel->returnValue( 'NewFeature2016', true, false );
}
The above will return true if the current user is in a bucket that has been enabled for NewFeature2016, otherwise it will return false. If you're testing multiple new features, or need more complex responses, you can chain the options together rather than using the simplified ternary version:
/**
* If the user is part of a cohort that has the NewFeature.dark enabled,
* return the name of the theme for that cohort. If the user is part of
* the cohort that has NewFeature.ocean enabled, return that proper name
* for everyone else, return the default theme name.
*/
protected function getThemeSet()
{
return Yii::$app->swivel
->forFeature('NewFeature')
->addValue('NewFeature.dark', 'darkTheme')
->addValue('NewFeature.ocean','oceanTheme')
->defaultValue('lightTheme')
->execute();
}
Or, if we're trying out new features on a model or something more complex, we can use swivel to determine the proper method to be called. The parameter passed to the behavior for the feature can be any callable.
/**
* Anyone who is part of the Search.New cohort will get to try out our new
* advanced search method, while a few select people are going to get a really
* souped up search method to try that marketing swears will be a big hit,
* and everyone else gets our original search that we've been using for years.
*/
public function search()
{
return Yii::$app->swivel->forFeature('Search')
->addBehavior('Search.New', [ $this, 'advancedSearch' ] )
->addBehavior('Search.Super', [ $this, 'superSearch' ])
->defaultBehavior( [ $this, 'originalSearch' ] )
->execute();
}
public function advancedSearch()
{
// new search method here that we want to roll out soon
}
public function superSearch()
{
// marketing's pet project search here that we're only going to give to
// a few people.
}
public function originalSearch()
{
// our original search function that is tried and true
}
For the above, my feature set in the database might look like: ~~~ | slug | buckets | | ------------ | ----------- | | Search | 1,2,3,4,5 | <-- 50% of total users getting new feature | Search.New | 1,2,3,4 | <-- 40% get the Search.New feature | Search.Super | 5 | <-- 10% get the Search.Super feature ~~~ My other 50% of users (cohorts 6,7,8,9,10) will get the original search and don't require an entry in the swivel table.
Full implementation details are available on the project page and the associated Wiki therein.
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.