DEV Community

Cover image for Fun with Feature Flags
Matt Eland
Matt Eland

Posted on • Updated on

Fun with Feature Flags

Feature flags are a simple technique that let you toggle whether a new piece of functionality is available in your software or some aspect of how it behaves.

In this article, I'll discuss why this isn't as crazy of an idea as it sounds, how you can implement a simple feature flag, the different types of feature flags and different ways of triggering each one,

Note: If the term "flag" is confusing you, think of it as a toggle or switch instead. It refers to a boolean (true / false) variable, not a piece of fabric flapping in the wind.

Why use feature flags?

At first glance the idea of a flag sounds a bit odd - after all, if you didn't want a feature to be available, why is it in the code to begin with?

First of all, what works fine for one user may not work right with broader sets of data or interactions in a production environment. You may want to define a beta users only type of feature flag where a feature is only enabled for a subset of users until it is proven to be working without errors.

Beta Users getting access to new code before other users

Secondly, many products have a carefully-coordinated "go live" date. You might want the new code out in production ahead of time to mitigate any extra risks, and then activate a feature once a certain magical date arrives.

Finally, if you frequently release code to production, branch management can be difficult if large features (also called epics) take a long time to complete. You spend more time managing different branches and lose productivity and opportunities to find bugs earlier on in the cycle. Feature flags let you release partial features in an offline state in production, but test them in QA or beta environments before the full feature is ready.

Implementing a Feature Flag

So, what does a feature flag actually look like?

private static IResumeAnalyzer GetResumeAnalyzer()
{
    // Check whatever configuration management this application uses
    if (ConfigHelper.GetBoolean("UseNewAnalyzer"))
    {
        return new RewrittenAnalyzer();
    }
    else
    {
        return new ResumeAnalyzer();
    }
}
Enter fullscreen mode Exit fullscreen mode

In the example above, we pull a setting from whatever configuration file our application framework relies on. If the value of the UseNewAnalyzer is set to true, then the RewrittenAnalyzer will be used, otherwise the legacy version will be used.

Extremely simple code, but the net effect lets us change one file and the application behaves completely differently. Depending on your language and deployment environment, the application may not even need to be restarted.

Ways to Configure Feature Flags

Feature flags don't have to be driven off of a configuration file. There's a number of other options which may make sense in different scenarios.

Common triggers for feature flags include:

  • Based on values in configuration files (see above example)
  • Based on values in a database table
  • Becoming active or inactive on a certain date (or between a range of dates)
  • Only active for beta users
  • Only active a certain percentage of the time or for a random subset of users (typically used with A/B testing)
  • Based on values returned by an external web service call
  • Managed by an external service such as Launch Darkly

Objections to Feature Flags

Okay, so feature flags make it easier to deploy code offline or to a certain subset of users. That sounds good for quality, but what's the trade off?

Nothing is free, and with feature flags you pay for the price in a few key areas:

Testing

Testing becomes more difficult and lengthy as you now need to make sure you test activating a feature and deactivating a feature. I've seen teams try to adopt feature flags before and only test the feature in an active state, then see a preview environment grind to its knees when the feature was deployed in an offline state.

Additionally, if various features interact with one another and each one has a toggle, you should test all different combinations of different feature states. This is a key reason why I strongly recommend removing old feature flags for features that are now fully online in production or are permanently retired.

Database Schema

If you have a new feature that relies on a database migration script that impacts an existing table, you need to think about how old data will work if the feature is offline, what happens if the feature needs to go from online to offline (or vice versa), and various other concerns.

Usually the best thing to do is to migrate the data with deployment of the new feature toggle - even if that was going to be in an offline state, but this may not be possible in all cases.

Alternatively, you can store a feature version in a column on a table that is being modified so you can distinguish between which rows are associated with the new feature vs the legacy way of doing things. This helps you control migration to and from the new feature state, but the cost of complexity is high.

Configuration Management

The overhead of more configuration means that it's now a little bit harder to administer every environment and track the state of every feature in every environment, potentially leading to confusion or other issues.

Next Steps

Ultimately feature flags are a good thing to consider for major long-lived beta features that need to go out early or for somewhat risky changes which may need a quick rollback option without a code change / deployment.

If you want to learn more about Feature Flags in C#, see my article on FeatureToggle.

While I do use feature flags in some cases, I prefer using the Scientist series of libraries in order to test the effects of new code in production without risking impacting a user.

Using Scientist to run an experiment featuring a legacy and new version of a routine

See my article on Victimless Canary Testing with Scientist .NET for more details on that process.


Cover Photo by Paul on Unsplash

Oldest comments (13)

Collapse
 
seangwright profile image
Sean G. Wright • Edited

I think this is an important topic that is easy to ... well, just not know about!

Thanks for adding this topic to your collection of posts!

Launching new features "darkly" (code is in the app, but a feature flag has it turned off) will allow teams to continue to keep code merging into master, deploying, running tests on new code without requiring it to be fully completed.

One thing I would add is (and I realize you aren't recommending this practice - you just wrote some example code) is to move the Feature Flag logic out of a static global class.

Those static helper classes aren't testable and are often directly tied to volatile dependencies (ex: database, file system, app-settings.json/AppSettings.config).

Instead either supply a feature service behind an interface:

public interface IFeatureService
{
   bool IsFeatureEnabled(string featureName);
}

// or ...

public interface IFeatureService
{
   bool IsFeatureEnabled<TContext>(TContext featureContext);
}

Where you can abstract away logic to determine if the feature is enabled by checking an API, database, or environment configuration.

This approach is helpful when features need to be dynamic based on the execution context (ex: not the same for every user).

The other option is to create very specific feature 'configuration' classes that are populated in your composition root when using Inversion of Control and a Dependency Injection container.

public class UserDiscountFeature
{
    public bool IsEnabled { get; }

    public UserDiscountFeature(bool isEnabled)
    {
        IsEnabled = isEnabled;
    }
}

These can be populated per-request or as a singleton for the lifetime of the app, but they tend to not change often.

For example, the feature is off today, but we update the configuration value in the database tomorrow, and then it's on for everyone.


ASP.NET Core has feature management baked in, so the patterns are established - we just have to choose our implementation!

Collapse
 
integerman profile image
Matt Eland

I had not worked with Microsoft.FeatureManagement before. My go-to with .NET has been FeatureToggle despite some of the odd syntax, because it makes spelling mistakes in configurations a non-issue by erroring early and by giving you strongly-typed solutions. I'll have to look into feature management more.

Collapse
 
seangwright profile image
Sean G. Wright

The error-ing early part is something I always lean towards when possible.

IoC containers like SimpleInjector verify your container by building everything in it 1 time at startup.

If you include your Feature configuration types in your container then the verification step will throw an exception if values can't be found in app settings or the database (assuming your classes guard against invalid parameters).

I haven't used FeatureToggle - I'll have to check it out.

Thread Thread
 
integerman profile image
Matt Eland
Thread Thread
 
seangwright profile image
Sean G. Wright

I appreciate you writing that up!

Collapse
 
baileyjs78 profile image
baileyjs78 • Edited

I agree that feature flags should be treated as a class, not a static or magic string. It makes deleting (cleaning up) them so much easier. In my opinion, the technical debt of deleting old flags is the biggest draw back for their use, however I still think it is worth it.

I've been part of a team working on an open source feature flag management project with a UI (think of a simple launch darkly, for free). We are in the process of simplifying the code base (remove sql, use core 3) right now. This has allowed our non developers (management, qas) to manage feature flags without having to have access to code.

github.com/NSIAppDev/Moggles
shameless plug

Collapse
 
seangwright profile image
Sean G. Wright

Thanks for the link - I'm gonna check this out.

Btw I think you typod the URL, it's missing an 's'

Collapse
 
baileyjs78 profile image
baileyjs78

Thanks, I fixed it

Collapse
 
thatzacdavis profile image
Zachary Davis

Launch Darkly is the best!

Collapse
 
integerman profile image
Matt Eland

I reached out to them for a bit more info after they contacted me on something else but they never replied.

Collapse
 
thatzacdavis profile image
Zachary Davis

Oh bummer, what were you wondering about it?

Thread Thread
 
integerman profile image
Matt Eland

It was a longer response to a sales inquiry from downloading an eBook they advertised on LinkedIn. The key paragraph I sent was:

I have to admit that I have looked at LaunchDarkly in the past for some personal game development hobbyist projects and found your prices prohibitive so I stopped evaluating you for my own needs, but as a community representative, I'd love to see a blurb on the specific value you offer over the multitude of configuration-based feature flag libraries available. Feel free to send me a sales spiel for me to take in as I'd love to be able to present more perspectives in the matter.

I think they just wrote me off, since I never got a reply.

Collapse
 
ivarconr profile image
Ivar Conradi Østhus • Edited

Hi, I am the author of Unleash, the open source feature flags service with client SDKs for most popular languages. Could be a great option when you want to change your toggles remotely,dto gradual rollout etc.

unleash.github.io/