Imagine the horror: A new version of the app you’ve rolled out to a million daily active users has introduced a serious client-side bug, resulting in significant drop-offs. It’s already taken days, if not months, to release it on the app store. Repeating the release cycle to launch the new version will eat up precious time—and users will have to actually update the app on their devices to get the fix.
From issue 10
I test in prod
Testing in production is a superpower. It’s our inability to acknowledge it that’s the trouble.
This is where feature flags come in handy. A simple mechanism to enable or disable features based on established parameters, feature flags can give mobile teams superpowers. If you’ve ever wondered why you didn’t get the shiny new app update your friend told you about, or why the buggy feature you saw yesterday has vanished today without an update, feature flags are probably the answer.
Feature flags or toggles can reduce the risks that come with deployment, freeing teams from having to rely on app update cycles to disable features in the event of serious bugs or crashes. They can also help control the complete life cycle of new features. For example, you can use them to collect feedback from a percentage rollout that slowly exposes experiments to a select group of users. If teams want to test in production (yes, that happens), feature flags can also validate app updates in the real world while minimizing risk.
But as your codebase scales, feature flags can become a serious source of technical debt. That’s why they should come with a shelf life, only used for major rollouts or when you need to observe feature metrics and analytics funnels for market feedback. By following a few best practices, you can keep your app performant as your feature experiments scale.
Sunsetting feature flags
When a new feature behind a flag goes 100 percent live, you should have a system in place to clean up the dead execution path and sunset the old feature. Some developers might find this advice controversial: If you’ve worked with feature flags before, you may recall times when your team had to revive a dead feature on the fly due to a sudden business requirement, and an old feature flag was helpful in relaunching it.
If you share this concern, evaluate which features are most likely to be relaunched, and keep any related flags around for a while. Otherwise, aim to remove retired flags that are clogging up your codebase with conditionals and dead code.
The more feature flags you have, the more frequently you’ll need to QA test your app. If multiple teams are working on their own features gated by distinct flags, put checks in place to ensure features are properly hidden when the flags are off.
Say you’re tweaking an existing feature for users on your paid “pro” plan, and you’ve released the changes behind a feature flag. In this scenario, it’s crucial to verify that the changes aren’t visible to users on your free or trial plans. This requires coming up with a variety of test cases to ensure the changes are properly gated and functionalities don’t break when two distinct flags are turned on at the same time.
Implementing a versioning strategy
From issue 14
On web API versioning
A practical approach to understanding backward compatibility, versioning strategy, and how to strike a functional balance.
Your flags may also need to support versioning. Imagine you’re replacing your app’s current payments platform with Stripe (maybe you’ve heard of them?), with the migration running as an experiment for a chosen demographic. Initially, you’re able to release the feature with a flag
enable_stripe_payment set to
true on the server. But let’s say the migration code update turns out to be incompatible with certain Android devices, and some users are reporting intermittent crashes. With a proper feature flagging system in place, you can quickly turn off the flag from the server and users will continue receiving the old payment code.
Now your app team is ready to deploy a hotfix. But this time you can’t simply change
true again because users on the old version of the app will experience the original bugs. Instead, you’ll create a version for the flag and release the fix with a new flag version,
enable_stripe_payment_v2, on the client.
At this point, the process of maintaining these flags on the server becomes more complex. If the cycle continues for more versions, you’ll have to maintain not only several feature flags, but also several versions per flag. If these flags are maintained by just one team, this could be manageable. But throw in multiple stakeholders, such as product managers and engineers from other teams, and feature flag management can become exponentially more unwieldy.
In these cases, having a central repository of flags or a feature flag management system with proper documentation of each flag (including version history, control management, and flag life cycle) can help prevent a situation where someone enables a flag on the server that activates a half-implemented feature on the client.
Putting it all together
By sunsetting feature flags, testing rigorously, and implementing an approachable versioning strategy with a well-documented flag management system, mobile teams can unlock the benefits of feature flags while avoiding the frustrations of a congested codebase. With these practices in mind, your team will be able to release features with more control and confidence, while skirting the long wait for app store approvals.