In a detailed article, Paul Hammant explains trunk-based development. In a nutshell, every time developers finish a piece of code, adding some functionality to an application and testing to see that the functionality works within the simulated environment that’s in use, they commit that code to trunk. This means that this functionality is now part of the trunk version of the application. Regularly, or on an event-driven basis (new commits), this application will go through rigorous tests. If trunk does not pass the tests, commits are stopped, and the problem is resolved with all hands on deck. The objective is to always have deployable code. This does not mean it is deployed. That’s an important nuance.
At regular intervals, releases take place. This means that a release engineer takes a copy of trunk, potentially cherry-picking among new functionalities and prepares the actual release of that functionality in production. The advantage of such approach is the speed at which functionality can be added to the production environment. It also ensures errors are found earlier in the process. Teams do not wait for months before integration tests take place.
However, there are some prerequisites to such an approach. Let’s discuss these in more detail.
- Functionality Is Developed in Small Modules
Each time a developer commits some functionality, it has to be operational within the wider application. This means it needs to be a nicely finished piece of code performing a function that adds value to the enterprise. As commits are expected daily, or every couple of days, the functionality is divided into small self-sustaining chunks. This leads to using service-oriented architecture principles, more loosely coupled functionality, clearly defined APIs, etc, all of which necessitates a different application architecture. In most existing enterprises, many developers work on existing applications and evolve them. But those applications often end up as vast monoliths and do not follow the architectural principles I highlighted. Let’s come back to this later in this article.
- Many Tests Are Automated
Testing is at the center of this approach. Unit tests are performed by developers, using studs for simulating functionality outside their control, databases, integration links, etc. As developers commit regularly, they will want to run most tests automatically so they remain focused on the software development process. By automating these tests, they are able to test the functionality very quickly and spot problems. Developers can correct issues immediately.
In a traditional approach, developers work on a given module for long periods of time and then hand the module over to be tested by a separate team. They continue with the next job. It’s only much later that they will be told what results the tests provided and may be asked to correct the code. They will have to re-invest in understanding what they did previously so they can address the issue. A lot of time and effort is lost in such an approach. If developers are able to have their code tested while, say, they head out for a coffee, they’ll stay focused on one task and bring it to fruition.
- Test in Production-Like Environments
How often have releases derailed because, although applications ran perfectly in test environments, something went wrong in production? Many times! And what’s the reason for this? The use of different software components, middleware, configurations, etc. So, why not do integration testing in a production-like environment? Well, it’s easier said than done.
Operations people keep evolving production environments regularly. It’s common to have changes in configurations, patches, and more. To keep test and production systems in synch requires strict version control. Every time a change is made in production, the same change has to be made in the test environment.
So, imagine having a test environment that is a scaled-down version of your production environment, and having all systems tests and system integration tests performed on this system? Automate as many tests as possible and run them regularly. That’s the idea behind the daily test of trunk. Sure, you will need to be able to run performance tests, and for this you’ll need a copy of your production environment. So why not provision this environment in a public cloud for the duration of the test? You won’t need the equipment all the time. Some functional tests and in particular user tests have to be done manually. Having trunk and an always-deployable application enables testers to run user tests at any time. They can do this in parallel with the automated tests.
What About Existing Applications?
In long-established enterprises, most developers are not working on new applications. They are, rather, expanding and improving existing ones. And in the majority of cases, these applications are monoliths. That means the above approach is not usable. So, what do we do?
It’s correct that you cannot apply a trunk-based development approach to a monolith, but there may be an opportunity to transform your application. As your company evolves to a digital enterprise, you will need the capability to invoke specific functionality when digitizing your business processes.
Fundamentally you have two ways of doing this:
- Isolate the existing functionality and make it callable through one or a series of APIs. All new functionality is developed in a modular SOA-compatible fashion and uses the APIs to call upon existing functionality. If existing functionality needs to be enhanced or corrected, it is actually rewritten as a module and removed from the original monolith. Doing this over time, you will empty the monolith of its contents!
- Re-factor the application by dividing the code in loosely coupled modules. Martin Fowler has many hints on re-factoring that are worth reading. Re-factoring breaks your monolith up, changes the architecture, and enables you to use the created modules in support of digitally enabled business processes.
The advantage of the second approach is that it gets you to trunk-based development faster as you address the existing functionality immediately. However, when doing that, you do not progress the actual functionality you present to your user. In their book “The DevOps Handbook”, Gene Kim et al describe how Amazon, PayPal, and others have rewritten their main applications several times so as to continually evolve their product and service offerings. Most of these organizations progress their application implementation by using microservices. Their applications become the pillar of their businesses.
This may not be the same for your organization, so ask yourself how far and how quickly you need to move. But keep in mind the requirement to evolve to a digital enterprise and the importance of your applications in that journey. You may be interested to read my posts about how to analyze your portfolio with the digital enterprise in mind:
Author: Christian Verstraete
Christian Verstraete, Advisory Services Cloud Application Lead, DXC Technology.
Christian specializes in the use of information technology to support business processes within the enterprise and across eco-systems in Europe and with global clients. His expertise includes consulting, project management, marketing, business and people management. Currently, Christian is a cloud evangelist for DXC, helping to develop a consistent offering crossing organizational boundaries.