Using Feature Flags to Enable Nearly Continuous Deployment for Mobile Apps

And, what in the world is nearly continuous deployment, anyway?

Kris Wong
VMware 360
5 min readJun 1, 2020

--

For those of you who are familiar with deploying SaaS applications, websites, or any other type of application on your own infrastructure, you are likely familiar with the idea of continuous deployment. However, the idea of continuous deployment doesn’t apply very well when we talk about products that are deployed at customer sites, or through the Play/App stores. In these instances, mobile app teams have to deal with the app submission process, review periods, blackout dates, not to mention our users have to actually update the app on their devices. With regard to delivering new value to customers as frequently as is reasonable — what release cadence should we strive for? This concept is what I am referring to as nearly continuous deployment.

IMHO, a two-week release cadence is about as frequently a mobile app can reasonably release. Any more often than this, and you’re bound to bump against app store review timelines, which can easily stretch to a week or more. Depending on the overhead associated with releasing in your organization, as well as your customer expectations, two weeks may be too frequent. Also, the more steps in your release process, the more you will need to automate in order to achieve a two-week cadence. All this considered, we have found that a cadence between two weeks and one month is a good target. This will help ensure that you are delivering value regularly while not accumulating too much code churn in each release.

So how do we effectively remove the dependency on delivering certain features in certain release versions? And, how do we reduce developer overhead by not allowing new feature code to age on branches, getting further and further behind the code in the main development branch? Enter feature flags.

What is a feature flag?

Simply put, a feature flag allows you to isolate new feature code from the rest of the production code flows. It’s a boolean value that indicates whether the new feature is enabled or disabled. Once a feature reaches a certain point of stability, the feature flag can be used to enable the feature for certain customers, allowing them to test it and provide feedback.

So how does this work?

The first step in creating a new feature flag is identifying the touch points within the app’s codebase that the new feature will impact. The goal is to minimize the number of touch points, which reduces the likelihood of human error in keeping the new feature code isolated. Depending on the amount of refactoring that is planned, you may need to duplicate certain classes, leaving a non-refactored version along with a newly refactored version. You should name these classes accordingly. You could use a “v1” and “v2” suffix for the class names, which makes it clear that there are two versions of the class, in order to support a new feature. Alternatively, you could name the existing class with a “Legacy” prefix, and then create the new class with the existing class name. You will also need to extract out a common interface that the calling code can depend on. You can then create a simple factory class that creates the correct implementation based on the feature flag.

A case study — Boxer’s new conversation screen

VMware Workspace ONE productivity apps — including VMware Boxer — make heavy use of feature flags to support our monthly release cadence. Let’s take a look at one recent feature to illustrate the points that have been made above. Both Boxer for iOS and Boxer for Android have recently released a new conversation view feature — the screen that is shown when you click on a conversation from your inbox. It includes all the messages within the conversation, allows you to expand and contract them, and read the content of the email messages. Due to the nature of email, and the wide variety of techniques used when authoring email with rich content (using HTML, CSS, and Javascript), it’s difficult to render all messages well on a mobile device screen. These conversation view components had grown organically since our first versions and were showing many signs of age. It was time for a total rewrite, starting at ground zero with the screen’s architecture.

Boxer Conversation Screen

When starting the implementation of this feature, the existing conversation screen (view controller/fragment) was renamed and a new one was created with a matching API. Anywhere this screen was referenced in the existing codebase, a factory class was used to create the correct version of the screen, based on the state of the feature flag. This allowed us to keep our pull requests small (because it was OK if the new flow was broken by a pull request), and target them to the main development branch, without affecting production users. This, in turn, kept the overhead associated with developing such a large feature to a minimum and expedited code reviews because reviewers did not have to review huge pull requests.

Our feature flags are available to be enabled and disabled within the apps’ settings screens, based on the type of build that is being run on the device. We distinguish between Dev, Beta, and GA (generally available) versions. This allows developers to play with new features as they are being developed. Once a feature is complete and has undergone internal testing, it can be made available for beta testers to enable. This supports internal beta testing and allows us to work with customers who may be interested in the feature, so we can collect early feedback. Given the size and level of importance of the conversation view feature, we went through several rounds of this — across a few monthly releases, before we enabled the feature for all production users. If a production user were to have an issue once a new feature is GA, they can disable the feature to return to the previous experience until we have a chance to investigate the issue and release a fix. After some number of releases (different for each feature) with the feature enabled for GA, we can remove the old code and the feature flag from the codebase.

Summary

In this post we discussed the idea of nearly continuous delivery:

  • Delivering regular value to customers with a two-week to one-month release cadence.
  • Reducing overhead and enabling early feedback by keeping pull requests small, and targeting the main development branch, using feature flags.

We also discussed what feature flags are, and how they are used, including a case study. This post covered one small piece of VMWare End-User Computing’s overall DevOps transformation. To read about another aspect of this transformation, please check out Joe Zollo’s post entitled Ephemerally Yours.

--

--

Kris Wong
VMware 360

Software engineer+architect. Entrepreneur. Real estate investor.