A Retrospective Look at Adopting Trunk-based Development
People are interesting. We have our habits and behaviours ranging from the accepted to the downright quirky. Some of us are exceptionally flexible, while others revel in their habits. Developers are no exception. This is a story reflecting on developers as creatures of habit, striving for their "perfect" merge.
Upon commencing our agile journey just under three years ago, we adopted the practice of creating a branch for each individual sprint. This change was mainly attributed to the teams arriving one Monday morning to find all projects had been moved from Perforce to Git. At the time it was certainly painful, but definitely proved to be a blessing in disguise!
With the adoption of Git, we pretty much adopted the bog standard Git workflow, with the slight tweak of creating a new branch for each sprint. Developers would eagerly create and refactor code, raising pull requests into branch X and creating feature branches in their own private fork for their stories and dutifully worked on their items.
The Git Workflow is familiar to most…On reflection, creating a new branch every sprint did seem like overkill. Lead developers did end up with the challenge of having to delete branches every so often to keep the branch listing manageable. Surely, if we had continued with this model a single development branch would have been reasonable.
Feature branches themselves proved to be troublesome. Developers would not merge back to the sprint branch very often. In the majority of cases, they would raise the request only once their feature was complete, regardless of splitting the story down. I’m sure you’ll not be surprised to read that merge conflicts were common, and quite often affected multiple files. Integration between pieces often occurred towards the end of a sprint, resulting in a slap bang attempt to fix any issues. Breaking the psychological need to only commit perfection beholden to the developer seemed impossible.
A Bright Idea
When the alternative approach of Trunk-based Development was proposed to us in a knowledge share, it was the classic cartoon moment of a light bulb sparking to life within my head. The premise was essentially the reverse of our approach at the time, where developers raise pull requests directly to master.
As outlined at the Trunk-based Development home, developers merge directly to master. Initially, I thought back to all those branches we had to maintain. All those large pull requests. The pain of dealing with merge conflicts every sprint. I got that usual thrill of excitement coursing through my veins common with every hair-brained scheme I propose in work.
Adapting to Change
Trunk-based Development was initially adopted across a couple of teams. Adoption of a new branching strategy is significantly easier when a few of your colleagues are on the same knowledge share. The journey to date has certainly been interesting. The obvious benefit for leads was we no longer needed to create as many branches. In fact, thanks to the use of labels, we have been creating physical branches only in the event of hot fixes to a release, which are then merged back to master.
> The programmer, like the poet, works only slightly removed from pure > thought-stuff. He builds his castles in the air, from air, creating by exertion > of the imagination. > > Frederick P. Brooks Jr., The Mythical Man-Month: Essays on Software Engineering
One initial surprise was changing developer mindset in more ways than one. Adjusting to pulling the latest recently rather than getting caught up in the coding moment is something they were forced to adopt. It was no longer the case that they could work on building that castle without syncing up with the drawbridge being constructed by their colleague.
Diverging forks and merge conflicts also occurred more initially if developers didn’t raise pull requests regularly. They were forced to commit smaller pieces, while still adhering to the definition of done. This does result in more requests to review, but smaller reviews are definitely easier to understand.
These changes in behaviour, for the most part, seem to be holding. However, one thing that has not necessarily been eliminated is the use of feature branches by all. As their forks are their own, some do create branches sharing the story, or event sub-task name. Arguably that can increase the number of divergent branches a developer encounters in their fork. It also contravenes trunk-based best practice since they’re not pushing small frequent changes. But it seems in some ways that developers still like labeling a castle as a castle, or a tower as a tower. The question is if the same control is to be exerted over their private branches as it is over the trunk.
Thanks for reading!