Note: this blog post is mostly intended for software developers having some experience using version control systems (Git, SVN).

About feature branches

Version control has always been around in software development, even before the likes of Subversion and Git were made broadly available. The reason is simple: as soon as several developers are working on the same project, making changes to the code on a daily basis, it is mandatory to keep track of all the modifications, and ensure that they are not overwriting each other.

There are usually two best practices that most developers agree on when using version control:

  • There should be a “main” branch for the project, also sometimes called “production” or “master”. This is the stable branch, the one used to build and ship new releases of the software. Everything that is pushed in there should be finished and well tested.
  • Developers should regularly push their changes to the repository, and synchronize it with the latest state of the “main” branch.

Looking at these two rules, they kind of contradict each other. Some features take weeks to be ready, and therefore, if developers have to regularly push their changes, they will inevitably push unfinished code to the repository, which is forbidden on the “main” branch.

A very common solution is to use a so-called “feature branch”. Feature branches are temporary branches, used to work on a feature in isolation, where the code is allowed to be unfinished and untested. The “main” branch is regularly synchronized with the feature branch, and once the feature is done, the whole feature branch is reviewed and merged to the “main” branch.

Example feature branch

Feature branches are extremely popular in the programming world, and despite the title of this article, we do not intend to imply that it is inherently wrong to use them. In some cases, for example in open source communities, they are a great solution to enable many programmers to collaborate. However, in our own (very) small team, we came to the conclusion that we should explore better alternatives to avoid some of their drawbacks.

Drawbacks of using feature branches

Working with feature branches has the following drawbacks:

  • Conflict resolution: it is pretty likely that multiple feature branches will end up modifying the same part of the code, especially if they stay open for a long time. Resolving these conflicts is time-consuming and error-prone.
  • Prevents refactoring: the direct consequence of the previous point is that developers will try modifying existing code as little as possible to avoid conflicts, and instead focus on introducing new code. This means that existing code will barely ever get refactored and improved, and the code base will grow bigger than necessary.
  • Code reviews are late and massive: when a feature branch has been opened for weeks, a code review is necessary before merging. This means reviewing a huge chunk of code, making it very likely for the branch to be rejected, or for the reviewer to be too forgiving. It also means that feedback comes very late in the game.

The more developers there are on the team, the more features branches, and the worse it gets. These drawbacks can be somewhat mitigated by enforcing short-lived feature branches that have to be merged rapidly, but even then, it is far from ideal.

A better alternative: trunk-based development

A good alternative to feature branches is trunk-based development, a very different approach, which allows avoiding the drawbacks listed above.

  • No feature branches are used: developers are pushing their changes directly into the “main” branch.
  • New features are disabled until they are completely implemented, using feature toggles.
  • Refactoring and improving existing code is encouraged.
  • Commits shall be as small and focused as possible, making the few conflicts to resolve very small and of little complexity.
  • Code reviews are done every day, so developers are getting feedback very quickly.
  • Changes can be deployed at any time, even before being reviewed.
  • The “main” branch can be deployed to production at any time.

Trunk based development

This approach requires discipline and clean commits, since every change could, in theory, be deployed straight away. We do believe that this is actually a good thing, as it forces developers to only push clean and stable code, which should always be the case anyway. This approach also encourages writing automated tests to minimize any risk, and scales well if there are more developers on the team.

The codefortynine way

At codefortynine, we tend to prefer trunk-based development to feature branches. We still use feature branches occasionally, though, when it can’t be avoided (for example when upgrading our central application framework to a new major version, which has to be done in one go), but only once or twice a year. 

For code reviews, we use the open-source software Cordon Bleu, which is maintained by our own developers.

Since we are a SOC 2 compliant organization, we can’t, however, allow commits modifying or adding critical components to be deployed without a code review. To ensure this, we slightly modified the trunk-based approach described above:

  • We use two branches: staging and live.
  • Developers are working on the staging branch. They don’t have permissions for pushing commits to the live branch directly.
  • Every commit of the staging branch which does not modify or add critical components is automatically merged into the live branch by our build system. Otherwise, the build system will wait for a manual code review to be completed before merging it.
  • The staging branch is merged to the live branch using fast-forward merges. This means that if a commit is not automatically merged, subsequent commits won’t be merged as well until the code review is complete.
  • The staging branch is automatically deployed to our staging environment. The live branch is deployed to our production environment. Deploying the live branch to our production environment is manually triggered. We do it at least once a day, often more. 

trunk-based development SOC 2 compliant

Overall, we are very happy with our approach, and it’s really great not having to worry about conflict resolution while encouraging refactoring ! If you want to learn more about how we build software, get in touch with us and join our team!

Cookie Consent with Real Cookie Banner