The Quiet Work of Removing Feature Flags

Feature flags are one of those tools that everyone agrees are useful right up until the point where they're not being used for anything — they're just there, silently complicating the codebase.

This was a quiet week in terms of new features. Two pull requests, both doing the same kind of thing: removing flags that had outlived their purpose. It's the sort of work that doesn't generate much excitement but, done consistently, makes a meaningful difference to how a codebase feels to work in.

What feature flags are actually for

The case for feature flags is well-understood. You decouple your deployment from your release — the code goes out, but the behaviour is gated behind a flag that you can flip remotely. This gives you the ability to run gradual rollouts, do A/B experiments, or kill a feature instantly without touching production. For a platform processing complex travel bookings, with lots of moving parts and no tolerance for downtime, that kind of control is genuinely valuable.

The problem is that flags don't clean themselves up. Once a feature has fully shipped, once the experiment has concluded and the "enabled" behaviour is the only behaviour you want, the flag becomes noise. It's a conditional in the code with only one meaningful branch. It's a name in a config file that nobody remembers adding. It's a test that exercises a code path that no longer exists in production.

Why this work is worth doing deliberately

The risk with flag sprawl isn't any one flag in particular. It's the accumulation. Once you have a dozen old flags in a codebase, each with their own conditional logic and test coverage, a new engineer reading the code has no easy way to know which flags are live, which have been retired, and which are permanent configuration that will never change. The code looks more complex than it actually is.

There's also a subtler problem: old flags can interact with new flags. Two conditionals that were each simple on their own can combine into behaviour that nobody anticipated and that no test covers. Flag cleanup isn't just tidiness — it reduces the combinatorial surface of the system.

The best time to remove a flag is shortly after the feature it was protecting has fully shipped and proven stable. The second best time is now. Keeping a habit of retiring flags when they're done means the codebase stays navigable, and the next engineer who needs to understand how the functionality works doesn't have to trace through a conditional that was only ever going one way.

Sometimes the most useful thing you can ship in a week is less code than you started with.