In an ideal world, we could test software easily. In the real world, things are quite messy.
Sometimes it isn’t easy to test a new feature integrated with the whole system. Sometimes there’s a risk in releasing a feature, and we must release it in a controlled manner.
To help us with this, feature flags are a must.
What are Feature Flags?
Feature Flags, also known as Feature Switches, Feature Toggles, and so on, are a simple mechanism to remotely configure an application.
Let’s pretend that you need to release feature X in production. You merge your feature branch into the main branch and start the deployment process. Suddenly, some minutes after releasing your feature, you figure out that you also released a new bug that is impacting the purchasing conversion.
Now you panic and try to revert your changes as fast as possible, but if the feature depends on front-end code, you will have to deal with clients using cached versions if your caching expiration mechanism isn’t configured correctly. Until then, you will need to deal with your manager (or even C-level people) calling or messaging you on Slack.
A controlled rollout comes to the rescue.
Imagine a new situation where, instead of releasing your new feature for all users at once, you configure a feature flag in your feature branch to only enable the new feature for a set of users. You then merge your feature branch into the main branch and proceed to deploy in production.
For most users, nothing has happened. But for selected users—and this selection could include only you, or only your team—the new deployment released the new feature. You then test in production and verify that the feature contains a bug. Instead of panicking, you create a new Jira issue and start working on a solution.
Which story do you want to be part of? The one where you messed up the application, or the one where you released a new feature securely, without downtime and without making customers mad?
How to use Feature Flags?
This depends on the project’s tech stack. Currently, I’m using Firebase Remote Config as a feature flag platform. Our team creates a new feature flag when we need to release a new feature that we want to roll out securely, when we need to test in production, or even when we have a feature so big that we must deliver parts of it and incrementally release more pieces.
For this last use case, having feature flags is pretty useful. You can split the feature into many pieces and merge them as soon as they are developed, tested, and reviewed. No more gigantic merges, but instead many small incremental merges.
To give you a more concrete example, let’s pretend that we are implementing a new feature on the checkout page that displays other products that are similar to the ones in the user’s current cart.
For that, we could create a feature flag called view_similar_products_at_checkout. I like to have a dedicated React custom hook to validate the feature flag status. Let’s create the feature flag and give it the value of an array containing only my email, for example ["my-email@domain.com"].
When the application accesses this feature flag, it will receive the array containing the user emails with access to this new feature.
To make the code easier to read, I’ll create a hook called useFeatureViewSimilarProductsAtCheckout that returns a boolean value indicating if the authenticated user has access to this feature:
function useFeatureViewSimilarProductsAtCheckout() {
let currentUser = useCurrentUser()
let featureFlags = useFeatureFlags()
let value = featureFlags.get("view_similar_products_at_checkout")
if (!value) return false
if (value === "*") return true
return value.includes(currentUser.email)
}
In this example, useCurrentUser returns the current logged-in user object, where we can access the email through the email property. useFeatureFlags returns an object where we can query for a feature flag value; in line 4, we get the value of view_similar_products_at_checkout.
Then we consider three cases: one where the feature flag doesn’t exist. By default, we will keep the feature disabled and return false. When the feature flag value is the string "*" we know that the feature is enabled for any user, so we return true. Otherwise, the feature value is an array of emails, and we just need to check if the current user’s email is included in the list of enabled users for this feature.
This code is straightforward and a quite powerful abstraction. We now just need to call this React hook and verify whether we show the new products section at checkout or not.
There are plenty of ways to release code in production in a safe manner. Feature flags are one of them. They are easy to adopt, and the outcome is quite generous. Also, there are many ways to implement them. The example I gave doesn’t depend on any specific platform, and this is intentional. You can use many ways to manage feature flags and their values.
I’ve mentioned using Firebase Remote Config, but you can implement a mechanism that depends on Redis to store feature flags, or even a database table.
By adopting feature flags, I’m certain that your development process will become much better, and you will be happier at your job delivering more features and only causing a positive impact in production.