TBD or Trunk Based Development
A Game Changer for Efficient Software Development
Introduction
Today, we’re gonna dive into Trunk Based Development (TBD), and let me tell you, from my experience, it was a total game-changer that shook up the way I think about development methodologies in general.
In the high-speed realm of software development, being efficient and adaptable is essential (I mean, how often have you been asked to deliver a feature, like, yesterday?). As companies work hard to develop top-notch software at lightning speed, they’re always on the hunt for ways to make their processes even smoother and reliable. That’s where TBD comes in - it’s been gaining popularity, and for good reason. So, what’s the deal with TBD, and how can it change the game for your software development? In this blog post, we’ll dive deep into Trunk Based Development, looking at what makes it tick, its perks, and its challenges.
So, a little backstory: in 2020 we launched a startup named “Trigon,” which focuses on accounting software (though that’s not the main topic of this blog post). In this article, we’ll be sharing some real-life examples of how we put TBD to work at Trigon, revealing the ways it has benefited us and the challenges we’ve faced along the way. This hands-on perspective will give you an even better understanding of how TBD might fit into your own software development journey.
If you are interested on implementing TBD in your team I highly suggest start reading from Here.
Philosophy
Everyone pushes to master/trunk (no branches, no merge conflicts) it always should be ready to go to prod. ๐ฅณ Sounds scary ๐ฑ ? That’s how I felt in the beginning at least.
Alright, let’s explore the history of Trunk Based Development (TBD). While it’s tough to pinpoint the exact origin of TBD, it has its roots in the early days of version control systems, particularly with the advent of centralised version control tools like CVS and Subversion.
TBD really started to gain traction with the rise of Agile methodologies and Continuous Integration (CI) practices in the early 2000s. Agile development prioritizes rapid iteration and collaboration, making it a natural fit for TBD’s streamlined approach to software development.
The concept of TBD was further popularized by tech giants like Google, Facebook, and Netflix, who championed the approach as they scaled their operations. These companies found that traditional branch-based development (Git flow) methods couldn’t keep up with their rapid growth and the need to deploy new features quickly. And in my opinion what is even more problematic is fixing issues after release was very challenging by being not able to identify source of the issue and the department team which should address it.
In 2019, when I was first exposed to TBD at TransferWise (now known as Wise), my initial reaction was, “this can’t be correct, safe, or dependable. What about testing?” The absence of testing, particularly across teams and components, seemed baffling at first. However, it didn’t take long for me to realize that this approach was actually more reliable and impressive than for example feature based appeared. At the end of the day my thinking that the tests/testing were not there was misconception.
In 2020, when my friend and Trigon Co-Founder Priit Pihus and I started Trigon, we were absolutely certain that we wanted to use TBD as our development workflow. Having both witnessed TBD in action and recognized its advantages, Priit and I were enthusiastic about adopting it. However, as we began assembling a team, we quickly realized that many developers still shared the mindset I had in 2019. Consequently, we started promoting the TBD culture, but soon encountered another problem. Developers who didn’t fully grasp the concept and philosophy of Trunk-based development began to unintentionally undermine the ideology, leading to counterproductive outcomes.
The philosophy is super important. It’s essential to stick to it and make sure everyone on the team is on the same page. To be honest, the specific workflow (whether it’s TBD, branch-based development, or something else) doesn’t matter as much as being consistent and following the chosen approach to be successful within that framework.
What I really admire about TBD is its philosophy of embracing a short feedback loop. To promptly identify and address mistakes, and to deliver features gradually rather than all at once. It’s like building a Lego set while it’s already in production!
Key requirements for TBD.
- Single trunk: ๐ฅ Developers work on a single, shared branch called the ’trunk’ or ‘master’ or ‘main’. This central branch is always in a releasable state, ensuring that new features and bug fixes can be rapidly deployed.
- Short-lived branches: ๐ฆ If branches are created for feature development, they are kept short-lived and frequently merged back into the trunk. This minimizes the risk of merge conflicts and keeps the codebase up-to-date.
- Continuous integration: ๐ข Code changes are committed, tested, and merged into the trunk multiple times per day (ideally maybe 100 times per day ๐ ๐ ). This ensures that the codebase is always in a stable, working state and that any bugs or issues are identified and resolved quickly.
- Fast feedback loop: โป๏ธ Developers receive immediate feedback on their changes (in a way requires monitoring systems in place), enabling them to quickly address issues and iterate on their work. This fosters a culture of continuous improvement and learning.
- Collaboration: ๐ค TBD promotes close collaboration between team members, as everyone works on the same codebase. This encourages open communication, knowledge sharing, and collective ownership of the code.
- Automated testing: ๐งช Comprehensive test suites are used to ensure that code changes do not introduce new bugs or regressions. Tests are run automatically whenever changes are made to the trunk, providing a safety net for developers. Test suites should not only focus on code coverage but also be reliable and relevant to real-world business scenarios.
- Incremental releases: ๐ Features are released incrementally, as soon as they are completed and tested. This allows for faster delivery of value to users and reduces the risk of large, monolithic releases. For instance, when developing a REST API, it’s actually ideal to simply write DTOs and push an empty controller that returns null to the trunk, and with other increments, implement a part of it and continue in that manner.
Styles
Although there are very different implementations of TDB and in my opinion it really narrows down to the use case and what fits your team and how to tune it. However, I really like how Paul Hammant describes it in his website 3 main strategies to implement TBD.
Committing straight to the trunk
While extremely agile and fast this style can work out only for small teams (around 2-5 developers), also you should consider couple of key points.
- how long it takes to build the project in the pipelines
- how fast you can recover from failure
- how to ensure that nobody has “bad” code pulled in their local while you were reverting and/or your commit was building and tests were running.
It is crucial to prevent others from pulling the problematic commit into their local workstations. One solution is to publish a specific commit number or hash that is known to pass all tests, ensuring it is safe to pull. To enforce this, an alias can be created for commands like git-pull, allowing developers to fetch the good commit instead of the latest one. Another thing to consider is to balance the CI build execution time with frequent trunk updates. Build failures can affect subsequent commits, especially with high commit rates. Some lock the trunk after the first issue (e.g. failing test), while others revert specific failed commits. The build duration is critical; short builds handle frequent commits, but longer builds become problematic. If you have committed every minute but your build takes a minute or more that would indicate that you should try other methodology styles for your team.
Short-Lived Feature Branches (SLFB)
This style is suitable for larger teams that adhere to strict code standards and are accustomed to branch-based development but still want to benefit from Trunk-Based Development (TBD). The main difference is that developers need to create and push their code using short-lived branches (SLFB), as well as one task can have many SLFBs. After creating the branch, developers will request reviews and wait for feedback and confirmation before merging into the main/trunk. Ensuring passing builds on the specific branch is crucial. However, potential delays in reviews and larger commit histories can hinder continuous delivery goals.
There is also a third approach, closely resembling the second one, but with some technical implementation differences. For more details on this approach, you can find them here.
Personal experience
At Trigon, we employ a mix of both styles, primarily favouring the first approach. However, there are instances when we require feedback on coding approaches or styles. Since our team is mostly remote, we occasionally resort to using pull requests for collaboration and code review. Currently, we do not have an automatic mechanism in place to revert commits if they fail to build in the trunk. Given our relatively small team size, we effectively communicate and address any dirty commits in the trunk.
Throughout my career, I have experienced various development practices, and undoubtedly, there are teams that successfully implement GitFlow and find it comfortable. The choice of approach largely depends on the specific needs and the size of the team.
Conclusion
Trunk-Based Development (TBD) offers a streamlined and efficient approach to software development, promoting continuous integration and a stable main/trunk branch. By encouraging short-lived branches, frequent code merges, and continuous code review, TBD fosters collaboration, faster feedback, and improved code quality. While it may require careful management of trade-offs, TBD proves to be a valuable strategy for teams seeking rapid delivery and reliable software products.
The decision to adopt a Trunk-Based Development (TBD) approach or rely on pull-requests has trade-offs that depend on various factors:
- Build technology: TBD may require building ’everything’ for every commit, which can impact build times. Some build technologies like Google’s Blaze (Bazel) can mitigate this issue.
- Source-control bottleneck: A monorepo with a large number of committers may lead to push/pull bottlenecks in the source-control system.
- Build duration: The median build duration versus the commit rate is crucial. Frequent commits may require faster build automation.
- Build-automation infrastructure: Ensuring the build-automation infrastructure keeps up with the incoming commits or pull-requests is essential to avoid delays.
- Developer reliance on automated builds: Developers must not overly depend on automated builds as a crutch, but instead, strive for local testing and verification.
- Handling follow-up commits: TBD relies on subsequent commits to address improvements, so the team must be adept at handling follow-up commits effectively.
- Commit granularity: Teams need to be skilled in separating refactoring commits from functional commits and should avoid overly small “baby commits.”
- Code-review process: The ability to handle code-review feedback after committing or pushing to the trunk/main branch is critical for maintaining code quality.
The trade-offs will vary based on the team’s size, experience level, development practices, and tooling. Striking the right balance is essential to optimize development efficiency and code quality.