You are on page 1of 25

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
feature A

master

feature B

Feature Branches: Problems

Merging is HARD WORK

Merging is HARD WORK

Sometimes impossible for git/svn to auto-merge

feature A

!
M
O

BO

master

feature B

Real life example

(happened last week)

Me
class
FooService

interface
FooService

class
DefaultFooService

changed class to interface

class
CachingFooService

Other dev
class
FooService

altered a bunch of existing methods


added a bunch of new methods

Took over an hour to merge manually

!
M
O
BO

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

interface
LoginService

class
LegacyLoginServic
e

class
NewLoginService

Add feature flag to allow switching between implementations in


test environment

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

class
NewLoginService

interface
LoginService

class
DefaultLoginServic
e

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/

You might also like