Every now and then, a way of working creeps in that is assumed not to correspond to established procedures. How nice it is when it is seen by many as a best practice and even has a name. In this case, it is a special version control practice, you guessed it, Trunk Base Development.
Software developers store their work in a version control system from which colleagues and the build process can read the current version of the source code. When a team is working on software, the team members have to organize themselves so that working on the shared code does not end in chaos.
If two developers develop separate features based on the same source code, there will always be a happy and an unhappy face. Both developers change the original source code in their own branch and then write it back to the main branch later. The developer who checks in his source code first has no additional work. The developer who checks in second has to merge the colleague’s changes with his own source code. In many cases this works automatically, but often the developer has to make changes manually due to merge conflicts.
More traditional approaches to using version control, such as GitFlow, provoke merge conflicts simply by the way they work.
In GitFlow, various branches are used: the main branch, which contains the delivered state of the respective versions. If you are older, then you know him as master; the develop branch, which contains the current state of development; and the hotfix, release and feature branches. The latter branches are recreated on demand, main and develop are two permanent branches.
The hotfix branches start from main and correct errors in the delivered code. These changes will be merged into main and develop. Release branches starts from develop when it is time for a new release. The final implementations are made here before delivery. The changes will be merged into main and develop when released.
The feature branches are used to develop new features and start from develop. As soon as the feature is complete, the changes from the feature branch will be merged to develop
The GitFlow process has been adopted by many teams and, with its branch concept, helps to develop software in a clear und structured way. Unfortunately, some disadvantages arise in everyday life. The disadvantages originate from the way the teams work, which do not align with GitFlow. This is not only a problem when working with GitFlow, but also with other branch-based practices.
The biggest problem is delays caused by large and old branches. The delays are due to extensive code reviews and merge conflicts. The risk of merge conflicts increases with the age of branches, or more precisely with the speed of drift between branches.
Let’s imagine a feature branch that is one day old. There are only a few changes between it and the develop branch, all of which probably exist in the feature branch. If the feature branch is a week old, there are various changes in the develop branch and additional changes in the develop branch due to feature branches that have been merged in the meantime.
The older a branch becomes, the more expensive it is to merge it back into the develop branch. Therefore, features should not be developed separately for a long time. These costs cannot be avoided by regularly merging the develop branch back into the feature branch, because this only distributes part of the costs over the lifetime of the branch.
However, the drift speed is not only determined by the pure age of branches, but also by the number of branches. If the team is not working together on features, which is bad, then there will be a high number of competing feature branches. Features developed in parallel are also merged in parallel. This increases the change frequency of develop. The higher the change frequency, the greater the drift speed to unmerged feature branches.
Release branches and hotfixes bring further merge conflicts. If releases are rare and elaborate, then changes between the release branch and the develop branch are inevitable. Since hotfixes in this scenario are carried out on very old source code, a merge conflict when adopting to develop is the rule rather than the exception.
If the changes in the feature branches become large, code reviews are often established. Other developers then check the source code more or less carefully before it is merged into develop. The larger a feature branch becomes, the more time-consuming code reviews naturally become. The quality of the code review is usually inversely proportional to the size of the code change. If the team does not work well together, code reviews that are not carried out cause further code drift between the branches.
In an Extreme Programming book, I once read something similiar too: “If something is good, do it more often, preferably much more often”. That is the idea of Trunk Based Development. The developers don’t merge their changes into the develop branch every few days and into the master every few weeks, but they merge into the trunk several times a day.
For this to work, a team needs an automated test suite that is as complete as possible, good collaboration between team members, preferably pair or mob programming and the use of feature flags to deactivate incomplete features.
Merging very small features or sub-features has various advantages. Firstly, they can be reviewed quickly without blocking the colleague for a long time. Secondly, the risk of an error in a small change is much lower than in a large change. Thirdly, there is no need for time-consuming manual merging and imposed code freezes. Fourthly, every active change provides rapid feedback.
A popular argument against Trunk Based Development is that it cannot be used to make major changes to the source code and that such adaptations require a long-lived feature branch. The answer to this is the Branch By Abstraction pattern. It introduces an abstraction behind which the customizations can be implemented without interacting with existing components.
Anyone who has not yet worked with trunk-based development should definitely try it out. The first step is not difficult, because with Trunk Based Development you only take very small steps.