A software development project split across separate tracks that multiple teams support is a great way to increase speed for delivering new features. Countless times in the past, however, I’ve seen release dates pushed back, preventing users from getting the features they need to perform their jobs. These delays have largely been the result of development teams simultaneously working on multiple large epics in the same code base. If one team hits a roadblock or needs more time to successfully complete development and testing, the other features are held hostage by the slower development. By using agile version control, we can harness the power of multiple development tracks while reducing the dependencies that arise when working and deploying code from the same code base.
There are multiple branching strategies agile teams have successfully used, such as release branching, feature branching, and task branching, each having its own distinct advantages and disadvantages. In this article, I discuss feature branching and the benefits it can have for larger development efforts where parallel development takes place. You can read more on the other branching strategies at Atlassian’s website.
Provisioning Branches: Teams should have guidelines for branching and merging to best facilitate multi-track development within a sprint or across multiple sprints. This enables them to work on multiple independent feature sets and minimizing changes to the delivery timeline. Let’s say we have Scrum A and Scrum B who are developing feature X and feature Y, respectively. Provisioning branches for each team to work in while maintaining a clean trunk, where only “done” features reside, gives each team the space they need to develop the features and keeps the trunk in a state that is reliably clean and deployable at any time.
Daily Merges: Each day, the trunk should be merged into Scrum A and Scrum B’s branches to make sure they are always working against the latest baseline. Once Scrum A completes a user story that makes up feature X, the code is then merged into the trunk and becomes part of the stable baseline of code. Before any merge, it is critical to tag the merge target, in this case the trunk, to be an immutable snapshot in time for the code. Any conflicts that arise as a result of merging, either into a branch or back into the trunk, should be resolved immediately. Delaying merging or conflict resolution will leave teams with complex and often error-prone merges later that can hold up the delivery of code. If at the end of the sprint, Scrum B has not successfully completed all the stories that make up feature Y, feature X can still be deployed to UAT or production without delay. At this point, the trunk is tagged, which allows the teams to know the exact code that has been introduced into the trunk and gives the teams the ability to create a patch branch in the future should there be issues with feature X.
Patch Branches: A patch branch, or release branch, should be created if code deployed to the production environment requires bug fixes. The same rules apply for working in a patch branch as we applied to our feature branches above. Once the bug fix is coded and tested in the patch branch, the teams can merge the code change into the trunk. The release can take place from the patch branch, in this case, as it is possible that other newer stories live in the trunk, for which there may have reasons for not deploying.
Feature Toggles: A feature toggle gives the teams the power to switch on or off developed or partially developed features in the production environment. Over a year ago, my team was told about a change to an external interface that would be taking place and our system would have to completely change the format of the data we were sending. The date of the interface change was July 1st, 2014, and we realized that trying to perfectly time a release to go in production on the same evening as the other release would be too risky. So, for the interface feature, we introduced a feature toggle. Based on an on or off value stored in the database, we could tell the system to use the new feature or continue to operate using the legacy interface. Then, the interface date changed from July 1st, 2014 to October 1st, 2015. By developing the code with the feature toggle, we prevented potentially messy source-control issues that could have arisen with this delay. If we had created a release branch for this code when we were ready to deploy it, it would have been out of date with our trunk by the new date and we would have been performing merges into the branch for over a year.
Final Thoughts: No matter which source control strategy works best for your projects, there are a few simple rules that will make everyone’s life easier.
- Never check in broken code that does not compile or does not pass automated unit tests.
- Don’t allow long-living branches as they will become difficult for the team to support and cumbersome to eventually merge back to the trunk.
- Keep as much of your code, configuration, and documents in version control as possible. Version control is a powerful way to make sure you can track changes to your project artifacts and roll back to earlier versions should the need arise. Tailoring an agile version control process to the way your team works and delivers code will greatly increase the team’s ability to rapidly deliver high-quality code.