Avoid bugs in production: The use of feature flags

Pedro Alvarez
7 min readDec 16, 2021

--

Image from https://www.dreamstime.com/illustration/spaceship-control-room.html

When you are working on a huge app which impacts the life of thousands or maybe millions of people, certainly you need to be extremely careful with the content you are deploying in production. Depending on what you are really delivering to your users, it may cost money to them or even a big process to your company depending on the regulations. The first mechanism you should use to avoid bugs in your app is tests. Unit tests detect some errors in the separated parts like classes, functions and modules, integrated tests check the parts of your application working together and UI tests check how the user may interact with your interface in each scenario. But the point is: Tests only detect the existence of errors, never the lack of them(write this phrase 10 times in your notes please). Sometimes your Quality Assurance team may not find some impacting bugs and it brings some percentage of chance of your app to cause big problems. The thing is: how to totally avoid it?

It brings the needing for a way of turning off some feature or maybe some part of your code that doesn't actually work as we expected. We need a way for the management team to control what must be visible for the users in production and what must not. Also, imagine you have some legacy code that needs some refactoring for updating a feature. You will do that a lot of times in your career as a mobile developer. So, we present you the concept of feature flags. Feature flags are pieces of data that are stored remotely in a way that your company can decide whether it should be part of your app on that time or not. Usually, they are booleans indicators. This article illustrates the concepts around Feature Flags and Feature Toggle, and it may not bring a lot of Swift code since the main idea is to show you the core concept.

Scenario: I need to hide an entire flow

Imagine the following scenario: You have a payment app that provides the users a use case for bill payments. You have a menu screen with some buttons in kind of a list(we are not caring about the design) and one of them relies on the bill payment feature:

When you click the Bill Payment button it starts a new flow of screens according to the steps of a bill payment. But imagine that this flow was discovered with some bugs in production that totally impact on the process. Of course developers at the same time shall start fixing the bugs in order to deliver a good experience to the users, but that may take some hours and we don't want to compromise the users with their transactions, so we need to disable this feature to them. Yeah, but so we need to release a new version instantly hiding this option? No, we just disable the feature flag for that flow. There are multiple tools for that like Firebase and AppsFlyer, but what you should know is that you can change this information inside your project without touching the Swift code, just like the back-end. What happens is that you set the flag to true or false in your feature flag tool according to your desire to display that feature. This task is known as Feature Toggle.

So how can this impact in the experience we are delivering to our user? How to cancel the flow? Well, we just need to take the feature flag information to our code to decide if the button should be visible or not:

The button is hidden by default and we only present it if the flag is activated

We are not covering here how should we implement a pattern for feature flags, but we usually have an enum for all kinds of features we need to control and there may be a function that tells us from the remote configuration service if the flag is active. We described a scenario where we want to control if a flow must be visible through a widget. Let's take a look in the other cases

Scenario: Legacy code

Feature flags are also very useful when we are dealing with legacy structures inside our app. Let's suppose we have a class that is very old in our project but not written in good patterns. That class belongs to the monolith of our project, it doesn't have a contract and our code is totally confused. Also, this class is not tested. Let's call our class by Dinosaur. TheDinosaurmakes some heavy logic operations through a lot of complex business rules, and it is currently working in the shape it's designed, so changing any line of this code might result in a bug.

Since the Dinosaurclass is used through the entire app, the impacts of a possible bug are huge. Take a look:

Dinosaur is the oldest class inside our app and the method as the name says makes really complex logic operations. We want to change a few lines of code in that function, but we care if we are delivering a viable result to our users, so, we must keep the old function body in some place. Let's split that:

We divided our logic into two new methods: one for the old implementation that's currently in production and the other one for the new implementation which we are providing. But wait, are we going to use both? No, we are not, we need to check which implementation we need through the feature flag:

As we see, we kept the old function header and we are retrieving the feature flag information. If we got the flag as true for the new business logic, we execute our new function. If we get our flag as false, we shall execute the old one. It's important because if we have the new logic in production and we detect some errors, we can just disable it remotely and go to the old flow.

Scenario: Custom data

Let's imagine the following scenario: you have an app that have some UI configurations that you want to change depending on the year time. You may want a different layout for Christmas time, one for Easter and other for some commemorative date. Instead of making the development team change the layout in a release process, the product team can change those configurations theirselves. You just need to define in your color palette the primary colors by fetching in the feature flags:

This way you are picking a color string through a feature flag and setting it directly in your custom label. What's the advantage with that? You can configure remotely multiple types of data, since colors to strings, fonts, and any custom data making your app's layout and identity configurable by hand. You don't need a new deployment in your back-end to that and even less from the front.

This customization can also be applied when you decide to display a new feature as a button or anything like. You can set a feature as temporary our seasonal, you can decide whenever you want to make it visible.

Scenario: Migrating services

Imagine you have an API that attends to any kinds of feature inside your app. At some point, the development team decide we want a new service that may attend your project at some specific contexts our maybe you just want a whole migration. Instead of saving all the URL's and endpoints data inside your front-end, you can just take the base URL(or even the entire path) from a feature flag which can be configured:

We are picking the base URL from a remote flag

At this way, we can just choose our endpoint from a remote resource.

When should I place feature flags in my project?

  1. You added a new feature/flow in your application that is not really essential and may be hidden if impacting your user experience
  2. You added a new feature that is seasonal or temporary. You need to choose if it may appear in there or not.
  3. You are adding new code that may strongly impact the features that already work. Add flags around the new code through an if-elsestatement, with some way of changing back to the previous content.
  4. There is some data that you want to change often, like colors, layout or maybe some business rules that are not fixed

Conclusion

In this article we illustrated how does the Feature Flag resource work. It basically consists in some data and configurations which the team can manage manually to change some features in your app without the need of a release for that. It makes the development process much faster and secure, and there is no panic when some bugs are found in production. I strongly recommend you to exercise this concept by creating a new flag to each new piece of code that may impact your users, in a way that you can roll back to the previous configuration. I hope you enjoyed ;)

--

--

Pedro Alvarez

Mobile Engineer | iOS | Android | KMP | Flutter | WWDC19 scholarship winner | Blockchain enthusiast