How to implement Trunk Based Development
Moving your team to a full CI/CD workflow
Trunk Based Development is a way of working with a collection of techniques and processes aimed at organizations that want to speed up their software delivery cadence. This goes a bit beyond simple branching strategy, as we lean on some tools to help us reach its full potential.
If your team wants to reduce merge friction, have the full picture about each other work, and release faster, then keep reading!
Why consider Trunk Based Development?
This experience is based entirely on our own, a 3-person development team. We are an experienced team and that makes Trunk Based Development a bit easier to implement.
We currently carry our work using feature branches, that are long-lived in our case. This makes it a problem when we want to have a release from our master branch because the probability of having conflicts increases. In our case, having many feature branches combined all together and then splitting this work apart in order to generate a release branch was creating some friction that we wanted to fix.
We want to be able to deliver our work to the production environment in a more streamlined way, and that is why we decided to give Trunk Based Development a go.
We will focus this article following the needs of our team like we said earlier. We have some good CI/CD practices in place already, but Trunk Based Development will enable us to achieve a truly continuous deployment layout, making the release process more streamlined.
It is a new workflow for us, different from the traditional feature-branch system, and it requires careful planning to implement correctly. The good news is that this planning is really easy and adapts perfectly well to any kind of team, no matter how big.
Trunk Based Development vs. GitFlow
There are other branching strategies out there with their own pros and cons. One has to consider what is best for the team and what is possible to achieve with the current resources. In our case, as we mentioned already, we are a small team with an easy flow of communication.
I personally recommend this article to a full in-depth overview of both pros and cons.
Prerequisites
Being successful at implementing Trunk Based Development on a team is a task that requires attention to detail and a methodical approach in order to achieve its maximum potential. Let’s get an overview of some prerequisites that are necessary to be successful when implementing a TBD workflow.
Small batches
Developers usually push their code to the main repository once the task is finished, or maybe once a day. They do this by using short-lived local branches from the trunk. When implementing TBD the development team is encouraged to push small batches of their own work as often as possible, to avoid any kind of merge problem.
MVP mindset
The most important part about the success of Trunk Based Development is the team’s mindset. There has to be a change in mindset towards an MVP (minimum viable product) workflow, to fail earlier and safely. Features should be built in iterations, bugs should be fixed ASAP.
Feature flags
Feature flags are one of the key technical tools that usually go hand-in-hand with Trunk Based Development. This helper system allows for the integration of flaky or otherwise potentially risky code under a condition that can be easily toggled.
An easy and flexible package for feature flagging is: https://github.com/bestit/flagception-bundle
This PHP package already contains all the necessary workflow operations for flag toggling and setting.
Technical approach and advice
General conventions
- Despite Trunk Based Development encourages to work directly in a trunk (production branch) and push changes there, we need to facilitate the process of code review via pull requests, so we advise you to keep working with feature branches.
- Always create a feature branch from trunk — the branch that we are deploying on production environment. In legacy repositories usually named as master, or in new ones main, you could create yours — trunk.
- Before pushing of feature branch to origin, always rebase on top of the trunk.
- Merging of feature branch PR to the trunk should be done using squash strategy to keep the history linear and straightforward.
Workflow conventions
- Divide local work into small batches
- Push feature branches to origin asap and create a pull request, so it could be reviewed and merged into trunk earlier minimizing potential conflicts, as the changes are small.
- Flaky/untested code should be wrapped in a feature flag
- Ramp up the test suite
- Release from trunk using tags
Implementation
Shifting work from GitFlow and variants to Trunk Based Development can seem like a daunting task, but it is mostly a mindset change. Your team will soon benefit from an improved release cycle, doing much less manual work, and having powerful tests to back the releases.
Proposed general steps for the implementation:
- We need to create a trunk branch from master and make it protected. We will keep development branch in parallel to be able to switch to the legacy process easily. Developers are encouraged to use trunk and create any feature branches, push small batches, and code review as early as possible.
- Focus on having unit tests covering new functionality. Manual QA should be a process that should go much faster now.
- Implement a feature flag solution. This can be either a Symfony bundle or just some configuration files and if() conditions. Wrap flaky or untested code that is already present in the trunk, so it can be released without any major modification. See https://github.com/bestit/flagception-bundle
- Verify that the flag solution configuration is good for your setup and your team.
- When planning release, create tags from trunk for QA approval.
Step by step guide for developers:
- Always keep local trunk up to date.
- Suppose we have a task called feature-101, create a local branch task/feature-101 for it.
- Implement work.
- Send the branch for review in a PR as soon as a small piece of functionality is ready. Cover missing work with a feature flag. This flag is open for test and closed for production environments.
- Merge into the trunk. Allow the code on test to be tested with the flag open.
- Remember to update your local trunk often as code is sent there frequently.
Step-by-step orientation guide for QA
- Test work should be done with the flag open. Access the configuration in the profiler to verify.
- In case it is closed for the test environment check with the developer how to proceed.
Trade-offs
As with any methodology, Trunk Based Development is not a perfect solution, there are a few trade-offs to consider.
- Keeping all developers in sync is important, and failing to do so can lead to unexpected merge conflicts.
- There is a heavy reliance on unit tests and QA approval.
- This system relies on the effectiveness of the automated CI/CD tools, so keeping them up to date is very important.
Useful links
- Trunk based development methodology — https://trunkbaseddevelopment.com
- TBD vs GitFlow — https://www.toptal.com/software/trunk-based-development-git-flow
- Feature flag library for PHP — https://github.com/bestit/flagception-bundle