A new feature toggling library for PHP


Adding features to an existing application can seem straightforward, but what if the system you need the feature in is already running in production and the feature needs small bug fixes from time to time? Or what if developing a feature takes longer than a standard release cycle, so it can’t be rolled out yet?

A widely used solution for this problem is "feature branches". With the support of a source code management system (such as git, mercurial, etc) a new branch is created, adding the new feature to the codebase, while diverging from the mainline. A common branch model is git-flow. More information on feature branches can be found on Martin Fowler's bliki: FeatureBranches.

Feature branches

A drawback of the feature branch approach is that when a feature is living too long in its own branch, rebasing and merging it with the main branch of your codebase is getting harder every day. So how can we develop new features on the mainline branch of our code repository, without exposing those features to everyone on a deploy? A possible solution is to use feature toggles. (Or feature bits, feature flipping, switches, ...)

The idea of feature toggling, is to allow features to be disabled or enabled, usually at runtime. Additionally, feature flipping is used to expose new features to a subset of users, allowing for A/B testing or gradually rolling out new features. Flickr was one of the first to blog about this approach. Others have also blogged and talked about the subject.

For our applications we'd like to be able to do feature toggling at runtime. We want to be able to toggle features live and enable features based on user id, the current time or for a percentage of users, without the need to do a deploy.

Meet Qandidate\Toggle

Toggle bytton

At Qandidate.com we developed a feature toggle library that allows us to easily work with feature toggles. The goal was to minimize the barrier to use the toggles and be able to flip toggles at runtime, so we added an API with a Redis backend and a graphical user interface to flip the switches.

A toggle has a name and a status. You can simply enable or disable the toggle, but most of the time you want a feature to be available for a subset of your users. We call this conditionally active.

// A toggle is by default conditionally active
$toggle = new Toggle('toggling', $conditions);

// To set a toggle always active
$toggle->activate(Toggle::ALWAYS_ACTIVE);

Checking values: operators

A condition has an operator to check against a runtime value. Currently we have the following operators built-in: GreaterThan, GreaterThanEqual, LessThan, LessThanEqual, InSet and Percentage.

$operator = new LessThan(42);
var_dump($operator->appliesTo(42)); // false
var_dump($operator->appliesTo(21)); // true

$operator = new InSet(array(42, 1337));
var_dump($operator->appliesTo(21)); // false
var_dump($operator->appliesTo(42)); // true

Toggle Operator

Context

So, we now know how operators work, but we still need to figure out how to get the toggle to check the operators with our runtime values. The library introduces the concept of a Context object. The Context allows you to set values at runtime to check against your conditions. This can be anything and depends on your application. You can for example set a user id to create feature toggles for specific users, toggle features based on the current timestamp or enable a feature just for users that signed up more than a 2 years ago.

$context = new Context();
$context->set('user_id', 1337);

Test a condition against the context

Now what?

Operators and some context alone is not enough, we need to bring those together so the Toggle can determine if it is active or not. The OperatorCondition does just that. It takes a key and an operator as constructor arguments. By passing the Context to the holdsFor method, it can check the operator against the Context value for given key.

$operatorCondition = new OperatorCondition('user_id', new LessThan(42));
$context = new Context();
$context->set('user_id', 1337);
var_dump($operatorCondition->holdsFor($context)); // false

Putting it all together

Now we've seen all the components, but we still have not seen the complete picture. With the ToggleManager you can check against a collection of toggles. The manager will check, for a specific toggle if any of the conditions match with the given context.

// Create the ToggleManager
$manager = new ToggleManager(new InMemoryCollection());

// .. initialize the conditions

$toggle = new Toggle('toggling', array($condition1, $condition2));
$manager->add($toggle);

// .. initialize the context

if ($manager->active('toggling', $context)) {
   // awesome feature
}

For a full example check out github examples/basic.php.

Stay tuned

You now have a working solution that can be used with the InMemoryCollection. In a future post we will publish our open-source REST API to toggle your features without the need for a deploy. To make your life easier, we will then also open-source our AngularJS frontend with that.

 

For now, check the code out at github.com/qandidate-labs/qandidate-toggle!

Update: We open sourced our feature toggle API and the UI to manage them. Also check out our blog post about it.

 

Sneak preview