Tech Blog

Feature Flags Made Easy

Jul 5, 2011 at 8:20 AM by | 4 Comments | Permalink

I recently participated in the ILTechTalk week. Most of the talks discussed issues like Scalability, Software Quality, Company Culture, and Continuous Deployment (CD). Since the talks were hosted at Outbrain, we got many direct questions about our concrete implementations. Some of the questions and statements claimed that Feature Flags complicate your code. What bothered most participants was that committing code directly to trunk requires addition of feature flags in some cases and that it may make their code base more complex.

While in some cases, feature flags may make the code slightly more complicated, it shouldn’t be so in most cases. The main idea I’m presenting here is that conditional logic can be easily replaced with polymorphic code. In fact, conditional logic can always be replaced by polymorphism.

Enough with the abstract talk…

Suppose we have an application that contains some imaginary feature, and we want to introduce a feature flag. Below is a code snippet that developers normally come up with:

Could not embed GitHub Gist 1060044: API rate limit exceeded for 66.147.242.195. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)

While this is a legitimate implementations in some cases, it does complicate your code base by increasing the cyclomatic complexity of your code. In some cases, the test for activation of the feature may recur in many place in the code, so this approach can quickly turn into a maintenance nightmare.

Luckily, implementing a feature flag using polymorphism is pretty easy. First, let’s define an interface for the imaginary feature and two implementations (old and new):

Could not embed GitHub Gist 1060044: API rate limit exceeded for 66.147.242.195. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)

Now, let’s use the feature in our application, selecting the implementation at runtime:

Could not embed GitHub Gist 1060044: API rate limit exceeded for 66.147.242.195. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)

Here, we initialized the imaginary feature member by reflection, using a class name specified as a system property. The createImaginaryFeature() method above is usually abstracted into a factory but kept as is here for brevity. But we’re still not done. Most of the readers would probably say that the introduction of a factory and reflection makes the code less readable and less maintainable. I have to agree — and apart from that, adding dependencies to the concrete implementations will complicate the code even more. Luckily, I have a secret weapon at my disposal. It is called IoC, (or DI). When using an IoC container such as Spring or Guice, your code can be made extremely flexible, and implementing feature flags becomes a walk in the park.

Below is a rewrite of the PolymorphicApplication using Spring dependency injection:

Could not embed GitHub Gist 1060044: API rate limit exceeded for 66.147.242.195. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)
Could not embed GitHub Gist 1060044: API rate limit exceeded for 66.147.242.195. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)

The spring code above defines an application and 2 imaginary feature implementations. By default, the application is initialized with the oldImaginaryFeature, but this behavior can be overridden by specifying a -DimaginaryFeature.implementation.bean=newImaginaryFeature command line argument. Only a single feature implementation will be initialized by Spring, and the implementations may have dependencies.

Bottom line is: with a bit of extra preparation and correct design decisions, feature flags shouldn’t be a burden on your code base. By extra preparation, I mean extracting interfaces for your domain objects, using an IoC container, etc, which is something we should be doing in most cases anyway.

 

Eran Harel is a Senior Software Developer at Outbrain.

 

Posted in Dev Methods, , , , | 4 Comments

4 Comments

  1. Jul 5, 2011 at 9:20amKen Egozi says

    Ken Egozi

    Most certainly, an IoC is a great way to achieve feature flags. I had a similar implementation using Castle Windsor. It used a (overridable) structured convention for alternative discovery, and optionally a per-user decision for the feature-flag (making it also a basis for an A/B test platform).

    What do you use for A/B testing on outbrain?

  2. Jul 5, 2011 at 11:28amShlomy Boshy says

    Shlomy Boshy

    To Ken’s question about AB-testing:

    In Outbrain we have an infrastructure for AB-testing.
    Each process has a set of properties it works with.
    We can define a set of values for a property, each will be given as the property value in a specific probability.

    E.g. for property X we can define:
    X=3 in probability 0.2
    X=5 in probability 0.5
    X=7 in probability 0.3

    We can define an “AB-Testing set” for multiple properties
    e.g.
    (X,Y,Z) = (1,4,7) in probability 0.4
    (X,Y,Z) = (2,5,8) in probability 0.6

    In a specific request we will get all values for all properties from the specific set – (1,4,7) or (2,5,8)
    [but not a combination of them]
    in the probabilities above

    and we can define multiple sets definitions like this at once.

    This works for all property types, including strings, booleans etc.
    and can be used in combination with feature flags

    This way we can test a new algorithm on 1% of the data,
    and even try multiple values for properties of algorithms in different precentages to see which works best

  3. Jul 5, 2011 at 12:56pmUri Goldstein says

    Uri Goldstein

    Just wondering – what would be the equivalent of IoC based feature flags in dynamic languages?

  4. Jul 5, 2011 at 1:56pmeran says

    eran

    @Uri I don’t much code in dynamic languages, but let me try to answer anyway.

    To the best of my knowledge there are IoC frameworks for most if not all dynamic languages. For example there’s a springpython framework (http://springpython.webfactional.com/).

    Regardless, I think that in a dynamic language it is pretty easy to implement feature flags. While in a statically typed language like Java, dynamically selecting a class / method to execute requires the use of ugly reflective code, in python you can do that with a single line of code.

Add a Comment

never made public