May 2014
Volume 29 Number 5
ALM Rangers : Software Development with Feature Toggles
Feature toggles as a software development concept let you pursue parallel, concurrent feature development as an alternative to branching for parallel development (also called feature branches). Feature toggles are sometimes called feature flags, feature switches, feature flippers or conditional features. Feature toggles let you continuously integrate features while they’re under development. You can use feature toggles to hide, disable or enable individual features during runtime.
As with all software development techniques, you would use feature toggles in conjunction with version control (such as Microsoft Team Foundation Server). Using feature toggles by themselves doesn’t imply eliminating all branches from a comprehensive version control plan. One distinction of feature toggles is that all changes are checked into the main branch (mainline) instead of a development branch.
A feature is disabled or hidden from all users until you start feature development. During development, you can enable the feature for development and unit testing, and disable it for all other users. Quality Assurance (QA) testers can also enable features they want to test. Until the feature is complete and fully tested according to the Definition of Done (DoD) and passes quality tests, it will be hidden or disabled in the released software. You can dynamically change the value of a feature toggle without creating and deploying a new build.
Starting with a comparison of feature branches and feature toggles, I’ll suggest alternative techniques for implementing feature toggles in code. Using a sample Windows calculator application, I’ll illustrate how to hide or show features at run time using feature toggles.
Continuous Integration
Using feature toggles, you can do continuous integration—all development work is checked into the main branch and continuously integrated with all other code in that branch. On every check-in, code in the main branch is built and tested on a build server using automated Build Verification Tests (BVTs).
As stated in the Microsoft patterns & practices book on continuous delivery (“Building a Release Pipeline with Team Foundation Server 2012” [2013]), “By continuous delivery, we mean that through techniques such as versioning, continuous integration, automation, and environment management, you will be able to decrease the time between when you first have an idea and when that idea is realized as software that’s in production” (bit.ly/1kFV0Kx).
You can use automated unit tests to test your code prior to checking it into the main branch. If a check-in breaks a build on the build server, you’ll have to fix the code before the check-in is allowed. If a feature in the build doesn’t pass QA testing, you can hide it from deployment or release until it does.
Feature toggles give you runtime isolation of a feature being developed until it’s complete, tested and ready for release. Using feature toggles with continuous integration, you work directly in the main branch. Code is checked in to the main branch, while keeping this branch stable for builds and deployments (see Figure 1).
Figure 1 Feature Toggles Support Continuous Integration of Parallel Development
Feature Toggles in Use
Figure 2 shows an example of feature toggles at work in a sample Windows Calculator Form. This also illustrates the challenges of parallel concurrent feature development.
Figure 2 Sample Windows Calculator Showing Three New Features
This example compares managing parallel development using feature branches to using feature toggles. There are three new features (Keypad, Advanced Functions and Memory Functions) being developed in parallel as the basic calculator is deployed.
Feature Toggle Patterns
There are many usage patterns in which you can use feature toggles to allow for continuous integration of all code, including pending or incomplete code. Using feature toggles can increase a team’s development speed by reducing or eliminating the need for parallel development branches and the ensuing branching and merging tasks, which can be extremely time-consuming and error-prone.
Here’s a list of typical scenarios where you could consider feature toggles:
- Hiding or disabling new features in the UI
- Hiding or disabling new components in the application
- Versioning an interface
- Extending an interface
- Supporting multiple versions of a component
- Adding a new feature to an existing application
- Enhancing an existing feature in an existing application
Branching for Feature Isolation
With a feature branching strategy, your team can isolate concurrent or parallel development of specific features—or groups of features—into separate feature branches. Feature branches give you significant flexibility in terms of when to move a release into production. You don’t have to wait until all features are ready in order to do a full deployment.
You can easily merge individual features or groups of features into the main branch when they’re complete according to the DoD. You can create new feature branches as needed, and delete them once the feature is complete. Features aren’t merged to the main branch until they meet the DoD. Following the example, Figure 3 shows three new feature branches providing isolation during parallel development.
Figure 3 Branching for Feature Isolation
For more guidance on various feature branching scenarios, you can refer to the ALM Rangers e-book on branching strategies at aka.ms/vsarsolutions.
Feature Toggles vs. Feature Branches
Using feature toggles lets you and your team pursue continuous integration, continuous deployment and continuous release practices. These practices permit more frequent feature code integration as they’re developed in parallel when compared to feature branches. At the same time, feature toggles also support runtime isolation of features under development and not ready for release.
With feature toggles, all pending changes are checked into the main branch. Each check-in is pended until an automated build process builds all code from the main branch on a build server, and successfully runs automated BVTs. This is the process known as continuous integration.
At run time, feature toggles hide or bypass features that are in the build, but not ready for release. Depending on how you plan to implement a feature, the effort to use feature toggles may sometimes be overly complex. On the other hand, hiding features from the UI can be straightforward.
When using feature branches, all development is checked into the associated feature branch and isolated from code in the main branch or other feature branches. You can’t merge a new or enhanced feature with the main branch or other feature branches until the feature is Code Complete, passes required quality tests or meets the DoD. Only at that point is the feature integrated (merged) with the main branch. Therefore, code isolation and continuous integration are at somewhat opposite ends of the “integration spectrum.”
Enabling a new feature in a deployment is relatively easy and risk free. Simply activate the associated feature toggles to visible and enabled. The effort to release a new feature using feature branches is much more complicated. You have to merge the feature into the main branch. This is often a time-consuming and challenging process.
Removing a Feature
In some projects, you’ll have to remove or back out incomplete features. Rolling back individual changesets to roll back a feature (cherry picking changes) is also complicated, labor-intensive and might require significant code rework.
It’s imperative to isolate features from the main branch until you decide to release those features. In any event, backing out a feature from a release just before the release is scheduled is risky and error-prone. Using feature toggles, you check all code for all features into the main branch. Feature toggles simply hide or disable select features from runtime or release.
Implementation Choices
There are multiple approaches to persisting the state of an application’s feature toggles. Here are two fairly straightforward approaches:
- Use Application Settings to define feature toggles (deployed in the XML Application Configuration file when the application is built).
- Store feature toggles as rows in a database table.
Define Feature Toggles Not only is it easier to define feature toggles in the configuration file using the Settings Designer, but you don’t need to do anything in your application to save the state of the feature toggles when the application ends. The sample Settings file shown in Figure 4 defines feature toggles.
Figure 4 This Sample ConfigSettings File Stores Feature Toggle State for the Windows Calculator
Store Feature Toggles As Database Rows To use a feature toggle database table to store the feature toggle state, the application will require two settings files. The CommonSettings settings file defines options used by the application. The DatabaseSettings settings file controls whether feature toggles are defined and persisted in a database table (when True) or in a Settings file (when False). The FeatureToggleSettings file provides the names for each of the feature toggles you’ll store in the database (see Figure 5).
Figure 5 Feature Toggle Names Stored in the Database Table As Rows
The approach used in the sample Windows Calculator is to dynamically create feature toggle rows. When the application runs for the first time, the table will be empty. At run time, all feature toggle names are checked to see if they’re enabled. If any aren’t already in the table, the application will add them to the table. The sample FeatureToggle table in Figure 6 shows all feature toggle rows added.
Figure 6 FeatureToggle Table After Initial Run
Implementation-Independent Concepts
When you use a feature toggle to disable a feature, code in the application hides or disables the controls based on the value of the feature toggle (True/False) associated with that feature. You can choose to hide the feature completely from the UI for features under development, or to show the feature as disabled. When you release the feature, it will be visible and enabled.
Figure 7 shows the Windows Calculator with only the keypad feature visible and enabled. The memory functions and advanced functions features are visible, but disabled.
Figure 7 Windows Calculator with Keypad Feature Visible and Enabled, and the Memory and Advanced Functions Features Visible and Disabled
The first step in this sample application creates a new FeatureToggleDemo database, followed by creating a simple FeatureToggle table. When you download the sample application, you will find three SQL files for: Creating the FeatureToggle Database, creating the FeatureToggle Table, and creating the two stored procedures used by the application to load values from and save them back to the FeatureToggle table.
After creating the FeatureToggle table, there’s no need to add any FeatureToggle rows prior to running the application for the first time. The application uses a FeatureToggle class library to encapsulate all of the application logic for accessing and updating the feature toggles.
The following code shows private fields used to hold the state of the feature toggles:
private Boolean _IsKeyPadFeatureEnabled = false;
private Boolean _IsKeyPadFeatureVisible = false;
private Boolean _IsMemoryFeatureEnabled = false;
private Boolean _IsMemoryFeatureVisible = false;
private Boolean _IsAdvancedFeatureVisible = false;
private Boolean _IsAdvancedFeatureEnabled = false;
The code in Figure 8 shows how to set Private Fields from feature toggle values stored in a ConfigSettings file.
Figure 8 Feature Toggle Values Stored in a ConfigSettings File
private void GetFeatureTogglesFromSettings()
{
_IsKeyPadFeatureEnabled =
Properties.ConfigSettings.Default.KeyPadFeatureEnabled;
_IsKeyPadFeatureVisible =
Properties.ConfigSettings.Default.KeyPadFeatureVisible;
_IsMemoryFeatureEnabled =
Properties.ConfigSettings.Default.MemoryFeatureEnabled;
_IsMemoryFeatureVisible =
Properties.ConfigSettings.Default.MemoryFeatureVisible;
_IsAdvancedFeatureEnabled =
Properties.ConfigSettings.Default.AdvancedFeatureEnabled;
_IsAdvancedFeatureVisible =
Properties.ConfigSettings.Default.AdvancedFeatureVisible;
tbMode.Text = Constants.configSettings;
}
The code in Figure 9 shows how to set Private Fields from feature toggle values stored in the FeatureToggle database table.
Figure 9 Set Private Fields from Stored Feature Toggle Values Stored in a Database Table
private void GetFeatureTogglesFromStore()
{
_IsKeyPadFeatureEnabled = FeatureToggles.FeatureToggles.IsEnabled(
Properties.FeatureToggleSettings.Default.KeyPadFeatureEnabled);
_IsKeyPadFeatureVisible = FeatureToggles.FeatureToggles.IsEnabled(
Properties.FeatureToggleSettings.Default.KeyPadFeatureVisible);
_IsMemoryFeatureEnabled = FeatureToggles.FeatureToggles.IsEnabled(
Properties.FeatureToggleSettings.Default.MemoryFeatureEnabled);
_IsMemoryFeatureVisible = FeatureToggles.FeatureToggles.IsEnabled(
Properties.FeatureToggleSettings.Default.MemoryFeatureVisible);
_IsAdvancedFeatureEnabled = FeatureToggles.FeatureToggles.IsEnabled(
Properties.FeatureToggleSettings.Default.AdvancedFeatureEnabled);
_IsAdvancedFeatureVisible = FeatureToggles.FeatureToggles.IsEnabled(
Properties.FeatureToggleSettings.Default.AdvancedFeatureVisible);
tbMode.Text = Constants.databaseSettings;
}
The code in Figure 10 shows how the application evaluates feature toggles and sets the Visible and Enabled properties of the Windows Calculator feature using wrapper methods.
Figure 10 Using Wrapper Methods to Set the Visible and Enabled Properties of the Windows Calculator
private void EvaluateFeatureToggles()
{
this.tbVersion.Text = Properties.CommonSettings.Default.Version;
if (Properties.CommonSettings.Default.DatabaseSettings)
{
GetFeatureTogglesFromStore();
}
else
{
GetFeatureTogglesFeatureToggleFromSettings();
}
if (_IsAdvancedFeatureEnabled)
{
_IsAdvancedFeatureVisible = true;
}
SetAdvancedFeatureEnabled(_IsAdvancedFeatureEnabled);
SetAdvancedFeatureVisible(_IsAdvancedFeatureVisible);
}
The following code shows a wrapper function to hide or show UI elements associated with the Advanced Functions feature:
private void SetAdvancedFeatureVisible(bool state)
{
this.btnBkspc.Visible = state;
this.btnSqrt.Visible = state;
this.btnPercent.Visible = state;
this.btnReciprocal.Visible = state;
this.btnPlusMinus.Visible = state;
}
The Windows Calculator takes advantage of a reusable class library to encapsulate all processing associated with the FeatureToggle table. Using this class library, the code that uses the ConfigSettings file is almost identical to the code using a FeatureToggle database table.
Wrapping Up
The benefit of feature toggles is that new or enhanced features are checked in to the main branch, so they can be continuously integrated and tested with the existing codebase at build time. Previously, code from new or enhanced features was generally not integrated with the codebase until closer to the release deadline, which is risky, challenging and fraught with peril. Both feature toggles and feature branches are viable approaches you can use to achieve a stable release with only completed features that have passed necessary QA tests. The choice to use one or the other depends on your needs and your development processes in place.
Bill Heys is a senior ALM consultant with Design Process and Solutions. He was previously a senior ALM consultant with Microsoft. He is a member of the Microsoft Visual Studio ALM Rangers, lead developer on the Rangers Branch and Merge guidance and a contributor to the release of the Rangers Version Control guidance. Reach him at bill.heys@live.com.
THANKS to the following technical experts for reviewing this article: Michael Fourie (independent consultant), Micheal Learned (Microsoft), Matthew Mitrik (Microsoft) and Willy-Peter Schaub (Microsoft)