Embracing trunk-based development: Advantages, disadvantages, and best practices
Trunk-based development (TBD) caters to developers working on the same codebase (trunk). As a developer, there’s a huge chance you are working with other developers on a project, merging changes to a single codebase. This means managing every change made to the source code during development. This is where version control management (VCM) practices are especially helpful.
VCM practices are vital in preserving code history, preventing errors, supporting parallel development, enabling continuous integration, enhancing code review, and more. Trunk-based development is a popular VCM practice that helps reduce the challenges associated with branch management and merge conflicts.
In this article, you will learn about the advantages, disadvantages, best practices, and the role of merge queues in trunk-based development.
What is a trunk-based development?
Trunk-based development is, quite frankly, an old practice. Its origin can be traced back to earlier version control systems like concurrent version systems (CVS) and subversion (SVN), where the prevalent philosophy advocated for everyone working on a single trunk, occasionally creating short-lived branches for purposes like bug-fixing or experimental development.
Authors like Jez Humble, co-author of DevOps Handbook and Continous Delivery, mentioned Version Control and the importance of avoiding long-lived branches in the 90s. So, what makes TBD so unique?
With TBD, developers can make frequent small changes, such as code integrations directly to the main branch or trunk, instead of creating long-lived feature branches. TBD is a type of continuous integration that prioritizes regular integration of code changes and their testing within a shared environment.
The goal is to promptly identify and address integration problems, thereby lowering the chances of such issues occurring again. This practice also shortens the time needed to introduce new features and enhances the overall quality of the codebase.
TBD is common among DevOps teams since it is mostly associated with merging and integration phases.
The significance of trunk-based development in your CI/CD Pipeline
Trunk-based workflows are great because they work seamlessly with continuous integration and continuous delivery (CI/CD) services. Here’s how it works:
- Each time you make a change to the main branch, automated tests (a branch of CI) check to make sure it doesn’t break anything
- After passing these tests, a pipeline can be set up to prepare the changes for the QA team to review on the staging branch
- The release manager, responsible for creating new releases, can then use the main branch’s code to publish a new release based on feedback from the QA team
- If any issues arise in production, a senior developer can make fixes specifically for that release
This approach keeps each release unique and doesn’t change the older release branches. As time passes, you can safely delete older release branches that are no longer needed.
The role of a merge queue in trunk-based development
Merge queue plays a crucial role in managing code changes and ensuring a streamlined and controlled process for integrating PRs into the main development branch, often called the “trunk” or “mainline.”
The role of a merge queue in TBD includes:
- Centralized Integration Point: The merge queue serves as the central point where code changes from different developers or teams are merged into the main branch. This ensures that all code changes are funneled through a single point of integration, reducing integration complexities and conflicts.
- Controlled Integration: The merge queue provides a controlled and orderly way to merge code changes into the trunk. This control helps prevent integration issues and conflicts that can arise when multiple developers attempt to merge their changes simultaneously.
- FIFO (First-In-First-Out) Order: In a merge queue, code changes are typically merged in a first-come, first-served order. This FIFO approach ensures that code changes are integrated in the submitted sequence, preventing any individual or team from monopolizing the merge process.
- Rollback Mechanism: In the event that a merged change causes unexpected issues or errors in the trunk, a merge queue may provide mechanisms to quickly roll back or revert the change, minimizing the impact on the development process.
- Automated Testing and Validation: Before code changes are merged into the trunk, they typically go through a series of automated tests and validations to ensure that they meet the required quality and compatibility standards. This can include unit tests, integration tests, code reviews, and other quality checks.
Implementing trunk-based development
Trunk-based development can be really useful in various application development cases. For instance, a startup MVP for investors or a client project on Fiverr. You do not need to wait for a project admin or a senior developer to review and merge the PR before pushing your changes.
An exception is the presence of experienced developers who help eliminate the chances of build-failing changes committed to the trunk.
Here is how I would implement TBD:
- Online services like Gitlab, Github, and more are needed for Git version control
- You need to create three pivotal branches: the main branch (also known as the trunk), a staging branch, and a production branch. Developers commit their code changes to the main branch. A release manager can then create new releases by merging the main branch with either the staging or production branch
- Code quality and integration should be prioritized if you plan to implement trunk-based development. A great way to ensure this is through the employment of a CI system. A CI system tests the modifications made by developers before changes become ready for release
- A CD system takes center stage in this process. It helps during the building and deployment stages of a project in either the staging or production environment
Trunk-based development vs. feature-based/Gitflow
Both development workflows have pros and cons, but depending on your instance, you can decide which works for you.
TBD is better if you are working on a project that changes frequently and requires swift, constant deployment. Developers can seamlessly integrate small changes to the trunk. Let’s say you are developing new product features or fixing a bug, TBD is absolutely great for this kind of change. You can also perform frequent code reviews and smooth automated test integrations with TBD.
Meanwhile, feature-based/Gitflow is much more useful in long-term projects. For example, if you are developing a large e-commerce application, you should utilize Gitflow, especially if a huge development team is on board. This is because Gitflow allows developers to work on separate branches, eliminating the need for collaborations and meetings.
Advantages of trunk-based development
Let’s take a look at some of the main advantages of implementing TBD:
- Simpler Codebase: With fewer long-lived branches, the codebase remains simpler and easier to understand. This reduces complexity, making it easier to maintain and troubleshoot code.
- Integration with CI/CD: An important benefit of TBD is its seamless integration with CI/CD services. This fosters an agile and smooth development environment.
- Faster time-to-market: Most businesses take faster time-to-market very seriously. They need to roll out new features or products as fast as possible to customers. As a developer, implementing TBD can make this happen. TBD helps reduce development and deployment time, ensuring new functionalities are delivered to end-users on time.
- Improved Feedback Loop: Regular integration allows for quick feedback on the impact of code changes. Developers can assess how their modifications affect the overall system, which is valuable for iterative improvement.
- Easier Debugging: When issues arise, it’s easier to identify the exact change that introduced the problem since there are fewer changes in the main branch. This simplifies debugging and troubleshooting.
Disadvantages of trunk-based development
As with any great software, implementation, or service, TBD has its advantages and disadvantages. Let’s take a look at some of its disadvantages.
- Isolation Problems: Since feature branches are absent, isolating changes for testing purposes can be challenging before integration into the Trunk.
- Learning Curve: Sadly, unless you are very technically inclined, wrapping your head around the ins and outs of TBD might take a while. The best way to avoid this is through training and training materials such as e-books, videos, and community support.
- Code conflicts: If codes aren’t merged properly, it leads to conflicts in your main codebase (the trunk).
- Dependency management: Trunk-based development can complicate the task of managing dependencies since developers cannot readily isolate various components or features.
Versioning and Rollbacks: Managing versions and rollbacks can be more complex in TBD, especially when multiple versions are under active development simultaneously.
Best practices for implementing trunk-based development
Companies like Netflix, Google, and Facebook use TBD during development. According to Google’s published Accelerate State of DevOps 2021 report, companies with higher performance are likely to have trunk-based development implemented.
Let’s take a look at some of the best practices for implementing TBD.
Automation First
To begin with, it’s important to introduce automation wherever feasible and effective. Automation should be applied in various aspects, such as software development, testing procedures, and deployment processes.
By embracing this approach, you can empower your team to carry out swift and effective iterations, thereby reducing the likelihood of any adverse impact on the primary codebase. A great automation software like Aviator is there to help you achieve this seamlessly.
Code freezes halt development. Avoid it!
Code freezes can impede the development process and cause integration issues as changes made in isolation may not smoothly align when merged into the main branch. A great way to avoid code freezes is to incentivize developers to integrate their work into the trunk when it reaches a stable state, even if it’s not entirely finished. This rapid integration helps prevent the accumulation of errors that tend to occur with prolonged waits.
In cases where it’s necessary, you can utilize feature toggles or branch-by-abstraction techniques to temporarily hide unfinished features, ensuring they don’t affect the rest of the codebase.
Pair or mob Programming?
In TBD, it’s essential to conduct code reviews promptly. While automated testing is valuable but doesn’t guarantee top-notch code quality. Therefore, employing methods like pair or mob programming to enhance team communication and facilitate immediate code review is beneficial.
A features flags management tool is the way to go
Feature management is a method for handling feature development and testing. It involves gradually releasing changes or new features to specific user groups before full deployment. This is achieved using “feature flags” that wrap new changes in inactive code paths, which can be activated when needed.
To simplify this process, consider using feature management tools like LaunchDarkly. These tools facilitate feature experimentation, A/B testing, and continuous deployment of microservices, allowing developers to combine testing with feature rollout. This approach ensures feature deployment without compromising software stability and provides the flexibility to roll back features without affecting the rest of the code in production.
Conclusion
Embracing Trunk-Based Development represents a bold stride forward in the world of software engineering. By fostering a culture of frequent integration, streamlined collaboration, and rapid innovation, this approach accelerates development cycles and enhances code quality. It underscores the significance of continuous integration, automated testing, and efficient development workflows.
This article covered the advantages, disadvantages, and best practices for implementing trunk-based development.
Aviator: Automate your cumbersome processes
Aviator automates tedious developer workflows by managing git Pull Requests (PRs) and continuous integration test (CI) runs to help your team avoid broken builds, streamline cumbersome merge processes, manage cross-PR dependencies, and handle flaky tests while maintaining their security compliance.
There are 4 key components to Aviator:
- MergeQueue – an automated queue that manages the merging workflow for your GitHub repository to help protect important branches from broken builds. The Aviator bot uses GitHub Labels to identify Pull Requests (PRs) that are ready to be merged, validates CI checks, processes semantic conflicts, and merges the PRs automatically.
- ChangeSets – workflows to synchronize validating and merging multiple PRs within the same repository or multiple repositories. Useful when your team often sees groups of related PRs that need to be merged together, or otherwise treated as a single broader unit of change.
- TestDeck – a tool to automatically detect, take action on, and process results from flaky tests in your CI infrastructure.
- Stacked PRs CLI – a command line tool that helps developers manage cross-PR dependencies. This tool also automates syncing and merging of stacked PRs. Useful when your team wants to promote a culture of smaller, incremental PRs instead of large changes, or when your workflows involve keeping multiple, dependent PRs in sync.