Partial deployment with feature switches

What

The idea of feature switches is neither new nor complicated; devop’s darlings Etsy and Flickr have been talking about them in the context of continuous deployment for a while.

Essentially, what it boils down to is merging part-complete features into your master code branch before the work is ready for some, or all, users. These features are then kept “in the dark” until such time as the feature is completely ready, when it’s switched on for all to see.

Why

There are a number of reasons why you might want to implement feature switches into your applications.

  • Reducing the size of integrations, and the problems associated with “big bang” integrations
  • Switching off features that depend on third parties, in case they go down
  • Shutting down non-core features of the application, if you start to get overrun with users
  • Testing features with subsets of users

You could argue that some of these reasons for wanting to use feature switches could also be solved by merging the master branch back into your feature branch frequently. Well, we do this too, but sometimes you really want to integrate your code properly with the other developers, but you’re just not quite ready for users to see the feature yet.

Moreover, with more advanced feature switches, you can test features with subsets of users, such as staff only, before rolling them out to your wider user base, something that is difficult to do any other way.

How

The first application where we’ve introduced feature switches is one of our Catalyst-based applications. Really, all we’ve done is add a <Feature> ... </Feature> block to our config along with a Moose role that provides a $self->features attribute.  Any class can consume the role, which really just provides the contents of the config block via the features attribute .

So, you can write code like:

package Foo;
use Moose;
with 'App::Role::WithFeatureSwitch'; 

sub foo {
    my ( $self ) = @_;
    return unless $self->features->{my_awesome_feature};
    ....
}

1;

As well as flipping code features on and off in our models and controllers, we realised it would be equally as valuable to be able to switch features on and off in our templates.

We use Template Toolkit within our Catalyst application, and in the Template Toolkit configuration it’s possible to inject variables that are available globally to all templates. So that’s what we do:

package App::View::Web;
use strict;
use base 'Catalyst::View::TT';
use App::Config; 

# Make the features hash available so you can flip features
__PACKAGE__->config({
    VARIABLES => { features => App::Config->config->{Feature} } 
});

1;

Now, any template can add [% IF features.my_awesome_feature %] ... [% END %] and conditionally display features.

So this is easy! Anyone could whip up something similar for their language or framework of choice. It’s just conditional blocks based on config values.

Where next?

It might be nice to move the features out of the config and into a data store, so they can be flipped on and off via an admin panel without requiring an application restart. For now, we’re happy with our humble start as it already does what we need.

It might also be interesting to have features switchable based on the type of user, but again this is not something we need right now.

We’ll be starting to make use of our simple feature switch – when it makes sense – to let teams deliver features incrementally, and help us move towards more frequent deployments.

Print Friendly

Leave a Reply