How to ship higher quality apps by adopting continuous deployment
Fabien
February 16, 2023
Photo by Brian Suman on Unsplash
A mobile release train is the concept of shipping an app at regular intervals, ideally every week, independently of feature development and feature readiness. This is the closest we can get to Continuous Deployment on mobile.
In other words, every week, at a fixed time, the train (the release) is leaving the station. You’re either onboard (your feature has been merged) or you’re not: too bad, but no worries, just catch the next train!
In the above example, 3 features made it into v1.0, but the next one (feature 4) wasn’t merged in time and will have to wait for v1.1. It’s not a big deal as long as the release cycle is short.
You might have already noticed a problem with this concept: in practice, we don’t want to wait until a feature is complete to merge it. Instead, we would like to have small, independent pull requests that are easy to review and are unlikely to create conflicts. How to deal with that issue? Enter feature flags.
Each new feature should be behind a feature flag: this is a check that tells us if the feature is ready for public release. If the feature is not ready, we display the old UI to the user, or we hide the entry point of the feature. If it is ready, we display the new feature.
if (features.feature1.isReady) {
// show new UI
} else {
// show old UI
}
Feature flags are a requirement for adopting release trains, but one could start with a simple list of flags (booleans) hardcoded in the code! No need for a complex system to get started. One simple solution is to turn all feature flags on if the user’s email domain is your company.
if (user.email.endsWith("@mycompany.com")) {
for (feature in features) {
feature.isReady = true;
}
}
Another option is to turn it on based on whether the build is an internal build or a production build.
A question people often ask is whether they should have a release candidate branch. The idea is to create a branch “Release candidate v1.0” that you then test, and fix bugs on, before releasing. That technique can work fine if you are moving slowly and rely mostly on manual QA, but it’s not ideal.
Once you’ve fixed the bugs on your Release Candidate branch, you will have to merge those fixes back into your main one. You can either cherry-pick the fixes one by one, or merge the whole branch back. But if you have developed a lot of new code on your main branch since then, you’ll have to deal with conflicts.
A better strategy is to instead adopt the policy that main is always stable. Meaning that you should always be able to ship your main branch at any time. Obviously, automated tests are a big help here, but if you use feature flags, you will still be able to test a new feature manually before it’s released. Simply don’t flip the switch until you’re satisfied that the feature works as intended. You can send a version of your app with the flag turned on to whoever is going to test it.
This technique is used at scale by most tech companies like Uber, Shopify, Lyft, and many others.
The main reasons are:
To recap, here are the main properties we would like our release strategy to have:
One key component to achieving this is automation:
Wolfia can set up a Release Train for your app automatically, contact us if you’re interested!