The Agile Architect
Enabling Agility with Branch By Abstraction
After tearing down code branching strategies in a previous column, our Agile Architect demonstrates a different way to support parallel software development that fosters greater agility and speeds development.
- By Mark J. Balbes, Ph.D.
- April 21, 2017
In a recent column, "Inhibiting Agility with Code Branches," I wrote about the evolution of tools to foster parallel development of a single application. These tools create islands of stability called code branches for the different parallel development efforts. Once these efforts are completed, these branches are merged back into the main code base. However, the longer that these branches live, the more opportunity there is for them to diverge significantly from the code in other branches and the more effort it takes to merge together the different branches and resolve any conflicts.
This works against the agile practice of ruthless refactoring that fosters an environment where the design of the code is continually improved as knowledge of the system and features evolve. If developers know that refactoring code on a branch will lead to a lot of complexity in their later efforts to merge the code, they may avoid the refactoring.
So if agile parallel development was difficult before we had source code control tools and branching support, and agile parallel development is difficult with these tools, what are we to do?
Applying Agile Thinking
Before we get into a specific solution, I want to remind you of two common thought patterns in agile.
The first is to always ask when the last responsible moment is to address a problem. By waiting until you can wait no more without creating a larger problem, you buy yourself the opportunity to learn and thus create a better solution.
The other concept is to adopt techniques that naturally lead you to higher quality software. Test Driven Development (TDD) is an example of this. With TDD, we write our tests before our code. One of the many benefits of this is to ensure that our code is inherently testable and to drive good code design.
With the problem of supporting multiple parallel development efforts, we can ask ourselves when is the last responsible moment? If you answered, once all the code is written and you know everything there is to know to solve the problem, you've answered incorrectly. Why? Because you don't know everything you need to know to solve the problem. You only know enough to solve it on your isolated branch. And you've created the new problem of having to merge divergent code across potentially many branches.
So what would it look like if we tried to solve the problem up front? We would want a solution that:
- Allows for parallel development of different features
- Allows for releasing different features at different times
- Allows for ruthlessly refactored code to be shared as quickly as possible, preferably as soon as the code commit is made
- Has a beneficial effect on the design of the code
Branch By Abstraction meets all of these criteria. I won't tell you there can't be other solutions. I just haven't seen any.
Branch By Abstraction
Branch By Abstraction is accomplished by introducing an abstraction through which you can show or hide the functionality of the new code. This enables all development to be done on a single shared code base without regard to how many features are in flight nor when each feature will be released.
In other words, all code when committed should be ready to go to production but any features not yet complete will not be available to use.
The steps for Branch By Abstraction are simple. Making it work is hard.
For a new feature:
- Introduce an abstraction that encapsulates the new feature.
- Create a mechanism to toggle the feature on or off.
- Build your feature behind the abstraction.
- (Optional) Remove the feature toggle.
To replace an existing feature:
- Refactor the existing feature to a new abstraction if one does not already exist.
- Create a mechanism to toggle the feature between the new and old implementations of the abstraction.
- Build your feature behind the abstraction.
- Remove the old implementation.
- (Optional) Remove the feature toggle.
In development, toggle the feature on. In production, toggle it off until the feature is done. This means that, depending on the sophistication of your build tools, you may be deploying all code to production whether it gets executed or not. For automated, exploratory and other types of testing, the feature is toggled on or off depending on circumstances. If you are planning to release with the feature off, you will want to test with the feature off. Similarly, if you are releasing with the feature on, you will test with the feature on.
How Is This Not Big Design Up Front?
Some of you are probably thinking at this moment that this is just a return to the Big Design Up Front methodologies that have failed us in the past. Indeed, if you do it wrong, it could be. But of course, you won't.
In the case of a new feature, you don't have to come up with the complete or even correct abstraction up front. You just have to come up with enough of the abstraction to get you started. Then you evolve it over time like any other code.
In the case of an existing feature, you already have existing code to help you. As with any refactoring, you start by refactoring the existing code to an abstraction. As you start to develop the new implementation of the feature, the abstraction again may have to evolve, possibly requiring more refactoring on the old and new implementations.
In both cases, there is an assumption that you already have well tested code that can be safely refactored. If you don't, you have bigger issues than choosing a code branching strategy.
How Does This Affect Deployment?
There is a myth that in order to do Branch By Abstraction, you have to have in place mature continuous deployment. This is false. Just like with any branching strategy, you can choose how you promote code into production, whether it is a manual staged process or completely automated. (Note that this column is not discussing the use of version control tools for code promotion. That's a different conversation.)
It is true that you need good continuous integration practices. But this is true of any branching strategies that support parallel development. If your team is not regularly sharing code through numerous updates and commits, then you are in for a world of hurt.
Final Thoughts
Branch By Abstraction is difficult. It takes time to learn how to do it effectively. We often say that TDD ensures that code is testable because we write the tests first. The same is true for Branch By Abstraction. Code development is parallelizable because we make it that way first.
To read more about Branch By Abstraction and Feature Toggles, see
About the Author
Dr. Mark Balbes is Chief Technology Officer at Docuverus. He received his Ph.D. in Nuclear Physics from Duke University in 1992, then continued his research in nuclear astrophysics at Ohio State University. Dr. Balbes has worked in the industrial sector since 1995 applying his scientific expertise to the disciplines of software development. He has led teams as small as a few software developers to as large as a multi-national Engineering department with development centers in the U.S., Canada, and India. Whether serving as product manager, chief scientist, or chief architect, he provides both technical and thought leadership around Agile development, Agile architecture, and Agile project management principles.