Here’s How You Solve a Matrix of Feature Flags

Feature flags are used in software to enable or disable different behaviors of an app. In a normal scenario, flags exist in the app until a feature goes live. At that point, the flag is enabled in test and production environments and can be safely removed.

But, what happens when an app needs behaviors to be enabled in one location but disabled in another? What happens when flags become dependent on each other due to their long lifespan? This combination of factors can arise during a project and create unnecessary complexity that could be avoided.

Part 1: No flag

We were building an app for a manufacturing company to use on the factory floor. In the early stages of the project, we worked without feature flags. This kept development fast and simple. There were fewer pesky if checks and the branching logic they entail. We were forced to add flagging when different factory sites needed different configurations. This created the first interaction of our feature flag structure.

Part 2: Factory Specific Flags

We already kept a record in our database for each factory location the app was used in. So we added a factoryConfig connected to each site’s ID. The initial table had some flags in it and looked like this:

A table with 2 rows, one for each different factory site. Each site has a different combination of feature flags enabled.

Adding a Flag

Each column is a specific feature, and then each row is a different production site. This worked until we were asked, “Can you add a feature to track how often we sweep the floor when floor tasks are being performed?” Yes we could, but we didn’t want the new feature to be visible until we were ready. So we added another column to track how often the floor was swept. With the new feature flag, the table looks like so:

A table with 2 rows. The first row is site A the second is site B. Site B has enableFloorTasks and trackSweepingTheFloor enabled. Site A has both disabled.
The flag was easy to add but now we have a problem. What happens if we enable the trackSweepingTheFloor flag but leave enbaleFloorTasks disabled? Like so:

A table with 1 row for each site. Site B now has enableFloorTasks disabled but trackSweepingTheFloor set to true. Site A still has both disabled.

What should the app do in this case? If we want to know if we should track floor sweeping, we need to check that the site has those tasks enabled in the first place. If the site isn’t doing floor tasks, then we shouldn’t do tracking even if the flag isn’t enabled.

Fixing the Problem

The code now needs to be built to handle this situation. If we put the combinations of enableFloorTasks and trackSweepingTheFloor in a matrix we get the following:

A punnet square with an option for enableFloorTasks and another option for trackFloorSweeping. There are 4 possible combinations where each flag is either true or false.
Where all four combinations need to be factored into the development of the feature to make sure we don’t get to an invalid page or cause a crash. However, only 3 combinations can be described as behaviors the user can see. Replacing the TRUEs and FALSEs in the above matrix we get:

A punnet square with an option for enableFloorTasks and another option for trackFloorSweeping. Instead of displaying the possible combinations of true and false the chart has english text describing the app's behavior. when both flags are enabled users need to track when they sweep the floor and do tasks on the floor. When only floor tasks are enabled then users only need to perform tasks without tracking when they sweep. When both are disabled then they dont need to track sweeping or perform tasks. When only sweeping is enabled they need to track sweeping without doing anything on the plant floor.
The app should support the green cases but the red case hasn’t been asked for so it would be a waste of dev time to support an invalid case.

Part 3: Modeling the dependency

Since the trackSweepingTheFloor is dependent on the enableFloorTask flag then we should include that behavior in our data model the solution we went with was to create an enum where each valid state is represented as a name and replaced the overall flag with it. EnableFloorTasks can now have a value of “Off,” “Tasks without sweeping,” and “Tasks with sweeping.” In the location config table, it looks like so:

Now the app knows based on one config value what should and should not be displayed for a site. The enum flag also leaves room for expansion if other sites need other special behaviors.

Feature Flags aren’t always an on/off switch

As a project grows and has to support more stakeholders those stakeholders might want customized behaviors. Instead of trying to track which combination of behaviors each stakeholder wants through a series of on/off switches. Making a named group that represents each stakeholder may be easier to track and refine when developing and communicating about a feature.

Conversation

Join the conversation

Your email address will not be published. Required fields are marked *