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 the addition of feature flags in some cases and that it may make their codebase 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:
[gist id=1060044 file=IfElseApplication.java]
While this is a legitimate implementation 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 any 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):
[gist id=1060044 file=ImaginaryFeature.java]
Now, let’s use the feature in our application, selecting the implementation at runtime:
[gist id=1060044 file=PolymorphicApplication.java]
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:
[gist id=1060044 file=SpringPolymorphicApplication.java]
[gist id=1060044 file=ApplicationContext.xml]
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.
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?
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
(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
Just wondering – what would be the equivalent of IoC based feature flags in dynamic languages?
@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.