Many development teams are used to making heavy use of branches in version control. Distributed version control systems make this even more convenient. Thus one of the more controversial statements in Continuous Delivery is that you can’t do continuous integration and use branches. By definition, if you have code sitting on a branch, it isn’t integrated. One common case when it seems obvious to use branches in version control is when making a large-scale change to your application. However there is an alternative to using branches: a technique called branch by abstraction.
Branch by abstraction: a pattern for making large-scale changes to your application incrementally on mainline.
The example Paul Hammant provides in his original blog entry on this technique is moving from Hibernate to iBatis. As it so happens, Go, the continuous integration and agile release management platform I work on, is presently moving from iBatis to Hibernate, and has been doing so for over a year now. We are also slowly moving our UI over from Velocity and JsTemplate to JRuby on Rails.
Both of these changes are being done slowly and incrementally, at the same time as developing new features, while checking in to mainline on our Mercurial repository multiple times a day. How do we do it?
Moving from iBatis to Hibernate
The team decided to move from iBatis to Hibernate for two reasons: first, we were able to use its ORM efficiently since we had control of our database schema, which saved us writing lots of custom SQL, and second, because its second-level cache helped performance.
Of course we didn’t want to move the whole codebase over at once. So as we started adding new functionality that required new calls to the database, we added these new calls using Hibernate, moving over old calls that used iBatis as required.
It is relatively straightforward to update the persistence logic incrementally because the Go codebase uses a standard layered architecture, with controllers using services that in turn use repositories. Because all the database access code is encapsulated in repository classes using the repository pattern, it’s a simple case of incrementally changing one repository class at a time from using iBatis to Hibernate. The service layer has no idea of the underlying persistence framework.
Moving from Velocity and JsTemplate to JRuby on Rails
We also wanted to move over from a Java-based UI stack to a JRuby on Rails stack, both because it was much easier to write tests for this stack, and because it speeded up UI development. Again, this change was made incrementally. When we created a new page in the application, we would create it using the JRuby on Rails stack, linking to the new page from the rest of the application once it was ready.
We would also move pages over whenever we wanted to make substantial changes to them. Again, the new version of the page would be developed using the new stack, and then we’d switch URIs in the rest of the application to point to the new version of the page once it was ready. At this point, we would remove the old version of the page. So while most of the UI in Go is now implemented using JRuby on Rails, there are still a couple of pages that use the old Java stack.
However you’d never know by looking at the pages, because they have identical styling. You have to look at the URI. Any URI that starts /go/tab is routing through the old Velocity stack. All the other URIs are routed via Rack to JRuby on Rails, which in turn calls through to the same Java service layer that the old UI also uses.
How branch by abstraction works
Branch by abstraction involves making large-scale changes to your system incrementally as follows:
- Create an abstraction over the part of the system that you need to change.
- Refactor the rest of the system to use the abstraction layer.
- Create new classes in your new implementation, and have your abstraction layer delegate to the old or the new classes as required.
- Remove the old implementation.
- Rinse and repeat the previous two steps, shipping your system in the meantime if desired.
- Once the old implementation has been completely replaced, you can remove the abstraction layer if you like.
In the iBatis/Hibernate example, the abstraction layer is the repository layer, which hides the implementation details of which persistence framework is being used. In the JRuby on Rails example, the abstraction layer is the servlet engine, which can dispatch either to the JRuby on Rails framework (using Rack) or to standard Java servlets by matching on the URI.
While Go is a relatively small project – it has less than ten developers, and it’s only been going for a few years – the same principles apply on projects of all sizes, and teams in ThoughtWorks have used this pattern successfully even on large and distributed projects.
Admittedly, branch by abstraction can add more overhead to the development process, especially in the case that the codebase is poorly structured. You need to think hard and move a bit slower in order to make changes incrementally in this fashion. But in many cases the upside is worth the extra effort, and the larger the restructuring, the more important it is to consider using branch by abstraction.
The key benefit of branch by abstraction is that your code is working at all times throughout the re-structuring, enabling continuous delivery. That means your release schedule is completely decoupled from your architectural changes, and thus you can stop working on the restructuring at any point to do something else that is higher priority, such as putting out a release with an exciting new feature you just thought up.
Branch by abstraction compared with branching in version control
Branch by abstraction is a somewhat misleading name, because of course it represents an alternative to using branching in version control when making large-scale changes to your system. Teams often use version control branches to make large-scale changes so that they can continue to develop functionality and fix bugs on mainline. The problem of course is that the merge back to mainline is guaranteed to be painful, and the amount of pain is a function both of how big the change you want to make is, and the amount of work you do on mainline in the meantime1.
That means that the stronger the forces are that push you towards using a version control branch, the more painful it is going to be at the end when you have to merge. If you’re also using branches for features, the situation is made even worse. In general, using branches for features or large-scale changes is a bad idea for several reasons, of which the most important are that it prevents both continuous delivery and refactoring2. Martin Fowler has excellent articles on why feature branching is bad, and how to use feature toggles as an alternative.
That doesn’t mean that all branching in version control is bad. It’s OK to branch in order to spike out an idea that you’re going to throw away. It’s also OK to branch upon releasing, provided you only use the release branch for small, critical bug-fixes. However teams who are practicing continuous deployment usually don’t bother with this, since it’s typically easier to fix any problems on mainline and roll forward than it is to roll back, because the delta between releases is so small.
The only other time it might be permissible to use branching is if your codebase uses the big ball of mud pattern. In this scenario even creating an abstraction layer can be hard. In order to do this, you must first find a “seam” (typically in the form of a set of interfaces if you’re using a statically typed OO language) that you can put the abstraction layer over. If a seam was not readily available, you would normally create one through a series of refactorings, but if that’s not possible for some reason then you might have to resort to creating a branch to get into a position to do this. Of course, this is an extreme move.
Relationship to other patterns
Relationship to refactoring. Refactoring has been defined as “a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior”. In this sense, both of the examples given above of branch by abstraction are also examples of refactorings. Crucially though branch by abstraction is effectively a programme of related refactorings, which taken together result in a large-scale change to the architecture of the application. Along with the ability to release your software at any time, the ability to refactor is perhaps the most important benefit of developing on mainline.
Relationship to feature toggles. People often confuse branch by abstraction with feature toggles. Both are patterns that allow you to make changes to your system incrementally on mainline. The difference is that feature toggles are intended to allow the development of new features, while keeping those features invisible to users when the system is running. Feature toggles are thus used at deploy time or run time to choose whether a particular feature or set of features is visible in the application.
Branch by abstraction is a pattern for making large-scale changes to an application incrementally, and is thus a development technique. Branch by abstraction can of course be combined with feature toggles, such that – for example – you could switch between the iBatis and Hibernate implementations of a particular set of data access calls to compare the performance of them at runtime. But typically, the choice of implementation is chosen by the developers and either hard-coded or baked in at build time, perhaps through your dependency injection configuration.
Relationship to strangler application. The strangler application pattern involves incrementally replacing a whole system (usually legacy) with a completely new one. Thus it operates at a higher level of abstraction than branch by abstraction, which is for incrementally changing the implementation of a component of your system. The lines between the two start to blur if you have a service-oriented architecture.
Isn’t this just good object-oriented design? Yes. Code which follows the SOLID principles makes it very easy to apply this pattern, in virtue in particular of following the dependency inversion principle and the interface segregation principle (ISP). The ISP is important because it provides a nice level of granularity at which to switch out implementations. As my colleague David Rice points out, branch by abstraction is the only sensible way to change the implementation of some particular component. Martin Fowler makes the same point by sometimes defining a component as some part of a system that can be swapped out for another implementation.
1 Another argument that is sometimes put forward is that distributed version control systems make merging so easy we shouldn’t be afraid of branching. This is misleading for two reasons. Firstly, as Martin Fowler points out, automated merge tools are incapable of catching semantic conflicts. Second, the longer the branch exists, the harder it is to merge, even with the best tools in the world. You don’t have to look too far on GitHub to find projects with forks that everyone would like to see merged, but have diverged so far from mainline that merging them would require substantial amounts of integration work.
2 Of course there are exceptions to every rule. Branches (other than for releases and spikes) are OK if you are working in a small, experienced team, and the branches are very short lived (less than one day).




Jez,
Regarding the relationship of BBA to refactoring: It’s worth pointing out that avoiding/reducing branching in version control will also removes a major impediment to refactoring in any given branch. Teams that employ feature branches always have to weigh the benefits of refactoring (for example, renaming a class or package in Java) with the risk and pain of having to merge those changes into the other branches.
Quite right Dante. That point is so important I’ve edited the post to add it in. Thanks!
[...] blog by Jez Humble (author of the book) where you can enjoy his latest post, Make Large Scale Changes Incrementally with Branch By Abstraction. It’s well worth the time spent reading. And one more feed to be added to your Google [...]
> Isn’t this just good object-oriented design? Yes.
While it seems reasonable to me to say “if you use good OO design you can probably easily use BBA”, I can’t find a reason why a codebase would need to implement OO to be able to do BBA?
Hey Dieter
Yes, you’re right, an OO language is definitely not a pre-requisite for using this technique. You can of course do the same thing with any language that lets you conveniently implement an abstraction layer.
I mainly wrote this last point because there is always someone who says “isn’t this just x”, where (in this case) good object oriented design is an especially likely candidate for x.
[...] Branch by abstraction – great article. [...]
Why call it “branch”? I was half-way through before I realized this post is not about version control branches. Something like “Legacy Adapter” would’ve been easier to grok (for me, at least).
Otherwise, great post. This is an important pattern that more devs should consider for use.
[...] http://continuousdelivery.com/2011/05/make-large-scale-changes-incrementally-with-branch-by-abstract... http://paulhammant.com/blog/branch_by_abstraction.html [...]
It can also be pointed out that “branching space” (just like code “design space”) is an area where many of the same principles of refactoring apply:
If we have many branches we can refactor our branching structure to be more simple and streamlined. And in fact the same four rules of “simple code” that Kent Beck defined for refactoring can also apply to branching, so we get four rules for simple codelines: passes all the tests, minimizes duplication, clearly expresses (abstracts) all [evolutionary] intent, and minimizes length+duration of branches.
The bottom line (in lean terms) is that branches (including your mainline) are your “flow” of (valued) code changes, and should be streamlined to optimize the throughput of that flow for the whole system (not just one feature or team). The ability to branch was created to solve the problem of concurrent maintenance & development of multiple versions at the same time.
We can create branches for “streams” of parallel development, but that doesnt make it a good fit for that purpose, and we need to look at the overall flow (how it all integrates back together) before presuming to “optimize” via branching. Branching was meant to solve problems of variability over time & space, and is ill-suited to solve problems of variability in design or functionality:
That’s where we need to use refactoring to (code) design patterns instead of branching, and is why branch-by-abstraction is typically a better alternative than feature-branching: because the “abstraction” branch allows us to manage design/functional variation in the *code*, but in an “evolutionary” fashion that is isolated from the current/legacy design and functionality that everything else is still dependent upon at that time+place.
Branching by abstraction is an excellent approach. Definitely one of my favorites, I try to champion it when I have the chance.
I recall applying this philosophy a few years back before hearing it coined for overseeing a multi-month project of switching gobes of unfactored procedural (Sphaghetti) code from the existing schema into DAO objects and from there intonew properly factored and cached schemas all the while allowing ongoing changes on the same branch and avoiding the constant headache of merging svn branches and hand resolving conflicting changes to code changes on some of those core areas.
[...] Make Large Scale Changes Incrementally with Branch By Abstraction – Continuous integration doesn’t work well with branches but as this article shows, you can manage even large-scale refactorings without branches using “branch by abstraction,” an approach reminding me of Fowler’s “strangler application” (an incremental replacement of a legacy system). The idea is: 1. Create an abstraction over the part of code to be changed; 2. Refactor the code to use it; 3. Implement new functionality using the new way / step by step move old functionality too, the abstraction layer delegating either to the new or old implementation … . It may be more work but: 1) your software is always working and deliverable; 2) (side-effect) in the end it will be more decoupled [...]
[...] Make Large Scale Changes Incrementally with Branch By Abstraction | Continuous Delivery. GA_googleAddAttr("AdOpt", "1"); GA_googleAddAttr("Origin", "other"); [...]
[...] git and feature branching. As I mentioned, we moved away from this and towards feature toggles and branch by abstraction. This is what happened when we [...]
[...] what alternative does he propose? Martin suggests applying Feature Toggle and Branch by Abstraction. I’ll leave it to you to read the background, but the removal of branching and merging from [...]
[...] several presentations and articles aggressively touting the superiority of feature toggles over feature branches, I decided to examine the two techniques a little more [...]
[...] several presentations and articles aggressively touting the superiority of feature toggles over feature branches, I decided to examine the two techniques a little more [...]
[...] http://continuousdelivery.com/2011/05/make-large-scale-changes-incrementally-with-branch-by-abstract... [...]
I tend to go a step further and break away from the O/RM at the UnitOfWork layer. All repositories depend on an IUnitOfWork implementation I have an InMemoryUnitOfWork, EfUnitOfWork, and an NHibernateUnitOfWork. When I need to switch between (e.g. had to integrate with an Oracle Server so I needed NHibernate, but wanted to prototype rapidly with SQLCompact. Once I got everything in place, I implemented my FluentNhibernate mapping and configured my Dependency Injection container to return an NHibernateUnitOfWork and it just worked.
The advantage I had in the .NET world was LINQ which is a framework native Query Object implementation. I’m not sure if Java has something equivalent but it would work wonders for portability.
[...] Para esto creo que es especialmente útil mantener el código anterior y el actual, y no empezar a refactorizar machacando el código existente. Dos técnicas nos pueden ayudar a esto: Feature toggles y Branch by abstraction. [...]
[...] branch-by-abstraction to make complex or larger scale changes to to your application incrementally while keeping the [...]
[...] Dit artikel is afkomstig van een externe website. Bron: http://continuousdelivery.com/2011/05/make-large-scale-changes-incrementally-with-branch-by-abstract... [...]
Composition over abstraction, for sure.