A Minimalistic Approach to Feature Flagging Your Web App

The Purpose

It is a common occurrence that a product’s web application needs to enable/disable features depending upon the circumstances.

Some use cases include:

  1. Wanting to merge features for an in-progress project without showing/releasing them to customers in production
  2. Wanting to preview in-progress work in staging environment
  3. Pausing features without removing them from source code

Here’s an example:

// Home.jsx

function Home() 
  if (!devFlags.beta) 
     return ...;

  return ...;

There are three things we need to do to make this work well:

  1. Set a pattern for configuring dev flags locally
  2. Set a pattern for overriding dev flags in an environment
  3. Set a pattern for how to consume dev flags in the code

Configuring Dev Flags Locally

Dev flags are just configuration, so you can think of them as a single object that can be consumed anywhere in the codebase:

export default 
  beta: true, // if true, show the features for the beta launch

However, we will need to specify the “defaults” that control the live production experience and the “overrides” that control the local environment.

For example, imagine you want the dev flag object to return beta: false in production (before its release), but beta: true locally so that you can develop features before the release.

First, create a dev-flags-default.js file that controls the live production experience (the default experience):

// dev-flags-defaults.js
export default 
  beta: false, // Don't show beta features in production

Next, create a dev-flags-overrides.js file that can specify the overrides fo the local experience:

// dev-flags-overrides.js
export default 
  beta: true, // Show beta features as you develop

NOTE: You’ll want to add this file to the .gitignore since the overrides should always be specific to the environment (more on that later).

Finally, expose a dev-flags.js file (the file that will be consumed by other files in the codebase):

// dev-flags.js
import defaults from './dev-flags-defaults.js';
import overrides from './dev-flags-overrides.js';


Now, you will be able to control what features to render based upon whether you are in a production or local environment.

Configuring Dev Flags Based on Environment

The code above expects a dev-flags-overrides.js file in every environment.

Obviously, you can add it manually to each local environment and instruct all the developers to do so via documentation.

However, we’ll have to think about how this will work when the app is deployed to various environments (i.e. staging and production).

In the deployment pipeline, you’ll need a step for adding the dev-flags-overrides.js file with the overrides appropriate to the environment.

For production, you can create a dev-flags-overrides.js file that returns an empty object.

For staging, you can copy the defaults and enable them as needed.

Consuming Dev Flags

Once you have the dev flags patterns set up per environment, you can start writing code that toggles features based on a flag.

Since dev flags frequently control revealing features of an in-progress project, you’ll want to make the !devFlags.someFlag code easy to cleanup (since it will eventually go away:

// Home.jsx

import devFlags from './dev-flags.js';

// Bad
function Home() 
  if (devFlags.someFlag) 
     return ...;

  return ...;

// Good
function Home() 
  if (!devFlags.someFlag) 
     return ...;

  return ...;

Then to release a feature, you can cleanup the dev flags by deleting the !devFlags.flag code (as opposed to copy and pasting the code in the if block in the bad example).

Sometimes, you may wish to enable a dev flag to release a feature/project as opposed to cleaning it up.

This may be nice so that you can quickly enable the feature, make sure everything is sound, and then delete the flag and all its references in a later commit.

🎉 Now you have an organized pattern for enabling/disabling features by environment. If you don’t have something like this in your codebase, follow the steps above (it’s just a few small files).

Source link