š Move Quickly With Your App By Adopting FeatureĀ Flags
Iāve recently been involved with a mobile app project that required frequent public releases from a master branch that contained a mixture of complete, stable features and other features that are still under heavy development. The latter features are in no shape to be shipped to the publicāāāso how do you keep these out of the public release but readily accessible for development? One potential solution, and one that my younger naive self might have attempted, would be to maintain a feature branch for each feature that was in active development, with a view to keeping these branches un-merged until the entire feature is complete and ready to use. This is a viable solution and works for some teams, but is not without some problems.
A Fork In TheĀ Road
Branches become stale the longer they are open, and if there is a lot of commit activity on the master branch it becomes quite a burden to stay in sync with with the upstream changes. It also means that the resultant pull/merge request will be huge because a feature will have been developed in its entirety before attempting to merge back into the master branch.
You can and should use branchesāāābut focus on continuously integrating with your master branch. This lends itself to much smaller merge/pull requests which can result in higher quality code reviews and less overhead of staying in sync with concurrent branches. How do we go about introducing incremental changes to a codebase without exposing partially complete functionality?
Flagged For Completion š³ļø
Feature flags are a simple solution to a complex problem. By offering up some basic boolean flags, you can hide partially complete features from the public eye, yet leave them readily accessible to other developers whilst leaving your master branch in a continuously deployable state. In the project I recently worked on our feature flags took a very simple form in a centrally located file (examples given are ES6 but you can adapt this to any language):
export const MY_SCHEDULE = false
export const MY_MESSAGES = false
export const MY_ACCOUNT = true
This file is then imported into the relevant places and used to show or hide functionality. In our case this was as simple as hiding menu items if the feature wasnāt currently complete:
import * as featureFlags from './featureFlags'
...
<View>
{featureFlags.MY_SCHEDULE ? <MyScheduleButton.../> : null}
{featureFlags.MY_MESSAGES ? <MyMessagesButton.../> : null}
{featureFlags.MY_ACCOUNT ? <MyAccountButton.../> : null}
</View>
...
Granted, features arenāt always quite as clear-cut as this and will sometimes require checking the flags in various places.
This is a particularly basic example with hard-coded feature flags, but thereās plenty of scope for taking this further. For instance, in addition to hiding in-development features, you could:
- Read the feature flags from an external data source such as an API
- Enable/disable features for certain users of your app
- Use feature flags to A/B test complete features against subsets of users
- Gradually roll out potentially risky features
In my particular case, weāre taking advantage of feature flags to allow us to continuously integrate incomplete features into the master branch of an app that is frequently released to the public, however, Iām excited to explore the additional opportunities that feature flags offer.
However you decide to implement feature flags, Iād recommend starting with something simple and only build in the complexity as-and-when you need itāāāno doubt there are fully featured libraries for managing more complex scenarios.
Have you used feature flags in any of your projects?