09 Mar 2016 Comment

Done right, feature toggles are a powerful way of postponing the activation of features in a continuous delivery workflow.

Done wrong, though, they can be a burden, bringing unnecessary complexity, obscuring broken code and becoming difficult to remove when the time comes.

The difference between whether feature toggles are a help or a hindrance hinges on two key things: when you apply them and where in your codebase they’re managed.

The wrong time

The wrong time to apply feature toggling is when you’re guarding against “unfinished” code that “just isn’t working yet.”

When you do this, you’re using feature toggles as a substitute for VCS branches. In this case, you’d be better-served by sticking to feature branching; that way, at least, you have a clear distinction between what is and isn’t “ready to go” (unmerged means unfinished) and, after all, it’s a tried and tested workflow and this is what it’s for!

The presence of a switch makes the implication that flipping it will turn something on and (most of the time, at least) doesn’t give the impression that things will start blowing up the minute someone tries it out.

Hiding a mountain of unfinished and broken code behind a wall of feature toggles results in a misleading illusion of production-readiness, which undermines the purpose of continuous delivery and, in an environment where safe, rapid changes are taken for granted, can be dangerous.

If you’re doing mainline development, strive to keep all features complete and working in every commit. If you’re tempted to implement a feature toggle because you’re committing unfinished code, consider whether the feature can’t be decomposed into smaller, working pieces and whether it isn’t really a symptom of a more fundamental problem in your workflow.

The right time

The right time to apply feature toggles, then, is when you want to keep your main branch - and production revision - as close to the development revision as possible (and this is a good thing to want to do) but external factors are preventing you from enabling the code in production.

Perhaps the business isn’t ready for the feature to be enabled, or you have third-party dependencies that aren’t yet complete. Maybe your new feature is a replacement for an old one and - while it works - it’s not yet sophisticated enough to be a suitable replacement.

In this scenario, a feature toggle is a way to get your working code into production as soon as possible in spite of the fact that the world isn’t ready to put it to use. A way of integrating code early and of mitigating dependencies that might otherwise force you to maintain stagnating branches. It isn’t a mechanism for subversive feature branching.

The wrong place

Once you have decided that a feature toggle is a good idea, you’re going to want an elegant and maintainable implementation. This largely comes down to handling your feature toggles in the right place.

A naïve approach is to simply have consumers of a feature check whether or not it’s switched on before invoking it:

public void CompleteTask(task)
{
    _taskManager.Complete(task)

    if (_features.Enabled("Notifications"))
    {
        _notifications.Notify("Task complete.");
    }
}

This is sub-optimal because it permeates your feature toggling throughout your application.

Consumers become responsible for handling concerns beyond their scope, tests cases multiply, a single missing conditional in a myriad of toggles can leak features into production prematurely and removing the feature toggles later becomes a significant task, involving changing the behaviour of every single component that depends on a toggled feature.

It also means that when a toggle is disabled, the feature itself is not the only code that’s turned off: all execution paths in every component that depend on the feature are also switched off, which spreads the potential for unexpected behaviour when the toggle is enabled.

This approach bleeds your feature toggling mechanism into every other component that comes anywhere near it. This is a recipe for a mistake.

Another option is to implement the toggle as a responsibility of the feature or service to be toggled:

public class EmailNotifications : INotifications
{
    private bool _enabled;

    public EmailNotifications(bool enabled)
    {
        _enabled = enabled;
    }

    public void Notify(string message)
    {
        if (_enabled)
            SendMail(message);
    }
}

This is a small improvement, though still far from ideal: every toggleable feature has to know about the fact that it can be switched on or off, which still adds unnecessary complexity, prohibits good encapsulation and means that simply adding or removing a toggle for a feature requires a functional change to the feature itself… not exactly the smooth transition you’re looking for.

The right place

The right place to implement a feature toggle is at your composition root.

If your feature is properly encapsulated, you can build your feature’s consumers to treat them as though they’re always on and simply have two implementations of the feature - one that affects the behaviour of the application and one that doesn’t:

public class EmailNotifications : INotifications
{
    public void Notify(string message)
    {
        SendMail(message)
    }
}

public class NotificationsDisabled : INotifications
{
    public void Notify(string message)
    {
        // Nothing to see here...
    }
}

Once you have all of the behaviour of the feature properly encapsulated, you need only turn the feature on or off by registering the appropriate implementation in your IoC container (or other choice of composition mechanism):

if (_feature.Enabled("Notifications"))
{
    Register<EmailNotifications>()
        .As<INotifications>();
}
else
{
    Register<NotificationsDisabled>()
        .As<INotifications>();
}

Of course, if you have multiple toggles, you’ll probably want to wrap this logic up in something reusable.

What this now gives you is a single point of activation for a feature toggle. Your features don’t need to know whether or not they are switched on and, more importantly, nor do the components that rely on them.

This means that when the feature is enabled, no component’s behaviour has to change. As far as they are concerned, consumers of the feature have been interacting with it all along. Crucially, this means that these interactions have been running in production since the feature was created and, when the feature is switched on, the only code now executing that wasn’t already is contained in a single place - inside the feature itself.

From the perspective of your tests, you can completely disregard the fact that the toggle exists: your tests will simply cover the interaction between the consumer of the feature and the (mocked or stubbed) feature’s contract. Adding or removing feature toggles has no implications for your test cases because it has no implications for any code other than the feature toggle.

Finally, when it comes time to remove the toggle, it’s a single, simple change that is completely transparent to the rest of the codebase.

So…

Before you implement that feature toggle, ask yourself: is this the right time and place?