Branching Strategies
Chris Birchall
2013/06/21
#m3_dev
Branching strategies
Feature Branches
vs
Branch By Abstraction
Feature Branches
● master branch is used for rollouts
● Little work done directly on master
● For every feature/bugfix, cut a branch
● To rollout a feature, merge to master
master
feature A
feature B
Feature Branches: Problems
Merging is HARD WORK
Merging is HARD WORK
Sometimes impossible for git/svn to auto-merge
master
feature A
feature B
BOOM!
Me
class
FooService
interface
FooService
class
DefaultFooService
class
CachingFooService
changed class to interface
Other dev
class
FooService
● altered a bunch of existing methods
● added a bunch of new methods
BOOM!
Real life example (happened last week)
Took over an hour to merge manually
Feature Branches: Problems
Merging is SCARY
Merging is SCARY
Do you trust your tools to merge correctly?
Have had problems with buggy tools (e.g. git-svn)
Feature Branches: Problems
Merging is A CHANGE
to the codebase
Merging is A CHANGE to the codebase
Merging counts as a change to the codebase
→ Need to perform manual tests before rollout
End up doing same tests before and after merge
Feature Branches: Problems
Feature branches are not
subject to CI
Feature branches are not subject to CI
Jenkins is only working against master
Manually creating a job per feature branch is silly
Can automate it, but it's complicated and brittle
Feature Branches: Problems
Feature branches go ROGUE
Feature branches go ROGUE
Branch can diverge massively from master
Becomes impossible to merge safely
Branch lives for weeks, months, ...
A solution?
Branch by Abstraction
Branch by Abstraction
The name is misleading...
Using B by A, we DON'T BRANCH!
NO BRANCHES == No MERGING
Branch by Abstraction
● All dev is done on master
● Incomplete work is disabled using feature flags
● master is always stable, ready for rollout
● Changes performed by introducing abstraction
Making a change using B by A
1. Add abstraction layer around the code you want to
change. (Extract interfaces, etc.)
2. Add the new implementation, but keep using the
old implementation in production.
3. Flip the switch! (Update flags, switch Guice modules, etc.)
4. Remove old implementation if no longer needed
Example: Switching to a new auth API
1. Refactor concrete class LoginService into
interface + impl class
class
LoginService
interface
LoginService
class
LegacyLoginServic
e
Update surrounding code to use LegacyLoginService
(Maybe add a factory to provide the implementation?)
Example: Switching to a new auth API
2. Add new implementation (+ unit tests, of course!)
interface
LoginService
class
LegacyLoginServic
e
Add feature flag to allow switching between implementations in
test environment
interface
LoginService
class
LegacyLoginServic
e
class
NewLoginService
Example: Switching to a new auth API
3. Flip the switch!
Update the value of the feature flag in production
Example: Switching to a new auth API
4. Remove old implementation
interface
LoginService
class
LegacyLoginServic
e
interface
LoginService
class
DefaultLoginServic
e
class
NewLoginService
Refactor (change class names, etc.) if necessary
Example: Switching to a new auth API
Finished!
Remember:
● All this happened on master
● Codebase was stable throughout the process
● Both new and old impls were subject to CI
● No merging!
Branch by Abstraction: Prerequisites
● Reasonably good, modular codebase
○ Easy to introduce abstractions
● Good devs!
○ Can be trusted not to break the build
● A good suite of unit tests
● A feature flag system
○ Ideally, well-integrated with toolchain
○ e.g. enable features using checkboxes in Jenkins
Thank you!
Further reading:
http://paulhammant.com/blog/branch_by_abstraction.html/

Branching Strategies: Feature Branches vs Branch by Abstraction