avatarAbhishek Gautam, September 22, 2021

Feature Toggle and Feature Branching

Branching is Integration's Credit card, You've got to pay that debt off sometime

TODO: provide alt

One of the lesson which software industry borrowed from manufacturing is that too much inventory is bad and sometimes code which we haven't deployed is also an inventory. So our branch management strategy would play important role in rate of release of high quality application. In this article we will be discussing about feature branching, branch-by abstraction & feature flags/toggles.

The goal which we want to achieve when it comes to branch management strategy is that “We want to isolate the work of multiple developers but at the same time we also want to integrate their changes frequently to ensure stable builds and quality releases.”

The problem with feature branches is that we are deferring integration with the changes other developers are making which leads to big merges and Big Merges also leads to commit race!

Pain of Merge = fn(size_of_merge, duration_since_last_merge);

Merging long lived branch , refactoring commits is very hard because source control tools are aware of textual changes and not the semantic changes you have made to your code. This can discourage developers to do refactoring if they are working on a certain branch for several days. So now we are in a situation where we want to integrate often and feature branches have their own issue.

Some of the things which we should keep in mind is:

  1. Long-lived branches are bad!
  2. Cherry picking bug fixes to release branch is bad
  3. Releasing 1/2 of a feature is bad

So we have another option Trunk-based development (Coding close to master)” where developers collaborate on code in a single branch called ‘trunk’ and resist us from creating long lived branches hence avoiding merge-hell resulting in stable build and you get to live happily ever after :)

Merge-Hell

Trunk based development is key enabler of Continuous Integration and by extension Continuous Delivery. Instead of keeping your code isolated from end user, keep your features away from end user until you are ready to use release them using feature branch. Also we should Treat every check-in as a release candidate.

Trunk Based Development at Scale

So by this we are integrating often and making small changes to the branch and due to this we will not have a problem of big merge and get fast-feedback if our commit breaks the trunk but then we are checking in incomplete changes so we need to have some mechanism to control it and for that we use Feature Toggles can be used which hides the partially implemented features in the running system. So we no longer do Feature branching, but instead we do Branch-by abstraction but for this we will have to create an abstraction point in our code.

In branch by abstraction we have a high-level API or some interface which controls the behavior and then we implement features behind a flag which are not stored on branch, ready to be merged or cherry-picked later but it is in the trunk as soon as possible.

We can use feature toggle to hide/show which abstractions we want to use in our production systems. There are many ways we can implement it like have a configuration for every feature or using flags or we can use our own flag based system to turn features on/off during runtime.

A big selling point of features flags is that it allows developers to practice CI rather than feature branching. Also your master is always stable and shippable , per-feature betas, decoupling features and releases. But few important point to note is that:

  1. Use a flag as few places as Possible.
  2. Remove then once you are done.

Other benefits we can gain out of it is that we can use this for A/B testing.

With feature management, the decision to release certain features to users becomes business decision rather than technical decision where we can also release few things to only a certain set of users. This may have business use cases such as supporting regional launches.

Now in a fairly large team, it would not make sense to deploy every single developers every single commit to production as some may have bugs, some may need more testing or it would consume a lot of resources to trigger huge number of deployments, so in that case we can follow release flow branching structure where we create a new branch every sprint which we dispose off at end of each sprint.

Release Flow Branching Structure

When we release software infrequently we have a two-fold problem where at one hand we take a long time between releases and each release have a larger change which means the release is inherently more risky and any release remediation will be more complicated because there is lot’s of stuff which has changed. Your release process is being less-used and there might be problems which you might not be aware of and you are not learning if your customer is liking your features of not.

Where as if you release more frequently the delta is lesser so risk is much smaller and much less likely and which can be easily be fixed and deployed and we have better feedbacks and learning from it and our release processes are mostly working fine.

Data from Puppet Labs State of DevOps report states that trunk based development predicts higher throughput and better stability and even higher job satisfaction and lower rates of burnout.

So the key take-aways would be:

INTEGRATE OFTEN🧩, STAY CLOSE TO TRUNK🌳, KEEP THE BATCH SIZE SMALL📉 & SHIP OFTEN🚢


Further Learning here & HAPPY LEARNING !!! 🎇🎆🎉