advanced 2 min answer

A codebase has 300 feature flags. What went wrong and how do you fix it without breaking anything?

feature-flagstechnical-debtlifecyclecombinatoricscleanup
Show the full answer Hide the answer

What is being tested

Whether you understand flag debt as a lifecycle failure, and whether your cleanup is safe rather than bold.

What went wrong

No expiry and no owner at creation. A release flag with no removal date becomes permanent by default, because removing it is nobody's job and carries a small risk with no visible reward.

The compounding costs:

  • Combinatorial complexity. Even ten independent boolean flags is 1,024 configurations, of which you have tested a handful. Production is running a combination nobody has ever run.
  • Code complexity. Conditionals throughout, with dead branches still compiled and still read.
  • Nobody can reason about behaviour without checking flag state, so incident diagnosis gets slower.
  • The flag service is a hard dependency on a critical path.

The fix, safely

1. Inventory and classify. Four kinds with different correct lifetimes:

Kind Correct lifetime Action
Release Days to weeks Remove — most of the 300
Experiment Duration of the experiment Remove when concluded
Operational (degradation, load shedding) Long-lived by design Keep, document
Permission / entitlement Permanent Not really a flag; move into the entitlement model

2. Find the trivially removable. Flags that have been fully on or fully off in every environment for months. These are the majority and their removal is mechanical.

3. Remove in small batches, one behaviour per change, deployed and observed. Not a single cleanup release touching a hundred flags — that is the change most likely to cause the incident you were trying to avoid.

4. Delete the dead branch too. Removing the flag while keeping both code paths achieves nothing.

5. For each remaining flag, find an owner and a decision. If nobody can say what it does, that is itself the finding, and the safest resolution is to observe its evaluation for a period before removing it.

Preventing recurrence

  • Every flag has an owner and an expiry date at creation, enforced by the flag system.
  • Flags past expiry fail a build or appear in a report that someone owns. This is the mechanism that makes removal happen; nothing else does.
  • Removal is part of the feature's definition of done, not a follow-up ticket that is never prioritised.
  • Limit concurrent flags on any one code path, which bounds the combinatorial problem.

The dependency question worth raising

What happens when the flag service is unavailable? The answer must be a safe default cached locally — not a failure, and not an unbounded wait. A flag system on the critical path with no local fallback has converted a release mechanism into a single point of failure.