Trunk-based development is one way to ship stable software quickly. Trunk-based development is easy: merge new code into your
master branch. It may be a shift from your current development process. It may feel like an important safety net has been moved out from under you. On merging a pull request into trunk, all the reviewers agree, "This is ready for production." The transition to trunk-based development feels precarious and negligent at times. We'll talk about one way to mitigate the risks of frequent merges to
master: Feature flags.
First, why would anyone want to move to trunk-based development? The are benefits to both the product and engineers:
- Reduce communication overhead - Trunk-based development removes the overhead of long-lived feature branches,
develop, and release branches. Removing this overhead speeds up delivery as we'll illustrate in a narrative below.
- Deliver value to your users more quickly - With trunk in a continually updating and production-ready state, you can deploy as often as is appropriate.
- Ship your work - As an engineer it feels good to have people use what you've created. It also follows that it feels bad to have your work languish in a long-lived feature branch.
Feature flags let us keep trunk in a deployable state. Work that is not complete, still stablilizing, or experimental can be toggled on and off with a feature flag. Think of feature flags as an
if statement that you can dynamically change at runtime. While the work may not be 100% complete, it can still add value. A small parcel of value is worth more than nothing. Code that sits on an undeployed branch has no impact.
A dev story like your own
Buildtime release management is value-less work. How many of you have had a similar conversation:
|Release Manager (RM):||Ok, we're cutting the 2.7.0 release for the new mega menu. What do we have in
|Dev1:||The mega menu passed tests today. Ready to go!|
|Dev2:||Um, did my hotfix make it out yesterday?|
|Dev2:||Stan from Analytics noticed we weren't tracking conversions right. Sure enough we changed one of his IDs out from under him. I merged a quick fix for it.|
|RM:||Fine, that will go out with 2.7...|
|Dev3||The carousel upgrade is nearly ready to go... but isn't there yet. Our latest PR merged to
The release manager grumbles, cherry picks commits, and builds a 2.7.0 release. This didn't add value to the product. This restacked completed work. The software team in our story has partially-completed work that adds value now. The team will scrutinize this work again later when they consider their next release. So the cycle continues.
Feature flags let you break the cycle. Deploy the partially-completed work behind a feature flag. Don't show it to anyone. Show it to a select group of stakeholders or an alpha-tester cohort. Get feedback or not at your discretion. Deploy the work now and worry about releasing it later.
The parable of the grocery bagger
Imagine you were at a grocery store. People shop, stream through checkout lines, and baggers pack bags. Imagine if the bagger packed every bag twice. First they put everything in a bag as it came down the belt. Then they removed everything from the bag after some amount of groceries made it past the scanner. Surveying what was available, they restacked the bag to their liking. This is what we do with release management. We sort and resort.
You might think that there's value in our double-packed bags. The bagger may have put all the heaviest items on the bottom. The bagger may have a gift for packing groceries in a way that will optimize unpacking them at your home. Feature flags give similar gifts. Feature flags let you ship your software in the order that it's complete and make it available when you need it.
A small, simple step
Taking the step from 0 to 1 may seem difficult for trunk-based development. Start small! The next time you're working on a branch for more than two days ask yourself, "How could I stop now and merge this?" It may be as simple as putting your work behind a hard-coded
if (false) statement. That may not add value to end-users, but other developers could change the statement to
if (true). They'd be able to see your work on their local development machines. You'd be able to merge your work to trunk. There would be no wasted air-traffic control done to create a release.
A change like this may seem too small to be of value. Try it! We're entrenched in our habits. Institutional release cycles and git flows have served us well, but shouldn't blind us. There are leaner processes to ship software. Adopt one small step and see how it works for you.