Continuous Integration and Trunk-Based Development: coding patterns and real-world examples

Daniele Scillia (Dan The Dev)
Learn Agile Practices
5 min readFeb 6, 2024

I often describe the advantages of CI and TBD: today, I will make it more concrete by sharing with you some real-world use cases and coding examples from my experience.

A happy developer made with Ideogram.AI

Introduction

Hello, developers! 🚀

Since I started this newsletter, I’ve talked of a lot of topics related to programming, Agile practices, and the work of a Software Engineer in general — but for sure, there are some of them that I talked about much more than others, with the top 3 probably composed by Test-Driven Development, Continuous Integration, and Trunk-Based Development.

Today, we talk again of the last two: after a quick recap of what they are about, I will share with you the coding patterns that enable CI and TBD by hiding work in progress, and some real-world examples where I applied those practices.

This issue aims to share a concrete guide for those who want to start applying these practices to help you achieve them in your practices first, and then in daily work — the coding patterns tips will be simple but clear, enough to clarify the approach and start practicing it.

I wanted to put some code examples, but this kind of pattern requires a lot of context to build a meaningful use case, and it would still be hard to understand only by reading, so I thought it wasn’t worth it and gave up the idea.

The principles

Continuous Integration is one of the most powerful concepts to master in the Software Development World, probably the one that most impacted how I see this job.

CI is the activity of very frequently integrating work to the trunk of version control and verifying that the work is, to the best of our knowledge, releasable.

Implementing Continuous Integration implies some practices that are embedded into it, and one of those practices is Trunk-Based Development.

Trunk-Based Development is a methodology where changes to code are integrated directly in the main branch, without any other branch in the middle, at least once per day.

If you want to really implement CI in your workflow, you must start using the set of practices that together make CI, including Trunk-Based Development: in other words, you can’t say you do CI if you don’t do TBD.

Sadly, that’s what most company does, at least in my experience — they use feature branches, typically with a very long life of multiple days, and then think they are doing CI just because they have an automated pipeline.

That’s just wrong.

Anyway, when it comes to the idea of very frequently integrating work to the trunk, where very frequently means daily or even multiple times per day, the typical concern is: how do we hide work in progress if I have to merge unfinished work to master (and even release to production, if I also want CD)?

There is a great quote I totally agree with, about this topic. The quote comes from Bryan Finster, who as a guest on an issue of the Crafting Tech Teams newsletter once said:

Software Developers have been trained to deliver complete features. That’s the problem. It’s one of the hardest habits to break.

That is so much true!

90% of software developers I know have this bias: we were taught to release fully completed features, and see the release of the software as the last piece of a long process instead of part of the daily work; this habit makes the question about how to hide work in progress seems to be a very hard and complicated question to find an answer to.

The reality is that this is a problem that has already been solved: there are multiple patterns that we can use to keep the work in progress hidden from the user, allowing us to release our code without any issue on their side.

We will dive into the most common patterns in a while, but I want to point out an important thing before; let me share a quick example with the most known pattern to hide work in progress: Feature Flags. A basic implementation could be as simple as a boolean value in the configuration, at a user level, that allows you to decide if a user has access to that feature or not; this has some consequences on code implementation, of course, because you’ll have to handle this configuration value to decide whether to execute the behavior or skip it.

From this example we can highlight a characteristic that is shared by all the “work in progress hiding patterns”: it will probably require some additional work to hide the work in progress; we have to think about how to hide it and make some coding to achieve this purpose.

So the question here is: is it worth it?

Of course, it is, and the reason is quite simple: the investment we take to hide our work in progress and enable the release of our code is completely repaid by the unplanned work we will avoid after the release; it is proved that implementing CI in our daily work will drastically reduce the unplanned work we will face later on during the process of completing the feature.

Maybe you remember it from our Lean Software Development issue, but let’s say it again: unplanned work is one of the biggest sources of waste in software development, therefore reducing it should be one of our targets.

Here, we are reducing unplanned work thanks to a little additional, but plannable, work: it means we are investing 1 today to be sure to not waste 10 tomorrow; we are accepting a bit of additional conscious work, that we are aware of and therefore is plannable, to ensure we avoid some unplanned, unexpected work later that will cause waste, issues, waiting time and context switch to be solved.

As always, if you want to deep dive into such topics, you will find a lot of useful resources in the Go Deeper section at the end of this issue.

Coding patterns

Keep the API Hidden

The pattern

The easier way to hide code to be executed or noticed in production is to hide its interface: just make sure that the path to the feature is either hidden to the user or the last piece you release. In a well-designed system, such interface elements should be minimal and thus simple to add.

Practical Tips

  1. Hide (or release last) the route of the API — I typically like to do this with a stubbed response that respects the real contract
  2. Hide (or release last) the UI that enables the user to interact with the feature (it can even mean hiding an entire component or page)

[ … continue … ]

Until next time, happy coding! 🤓👩‍💻👨‍💻

🙏 Thank you for reading this shortened version of this article. You can enjoy the full version on my blog here.

--

--

Daniele Scillia (Dan The Dev)
Learn Agile Practices

Software Engineer @TourRadar - Passionate Dev, XP Advocate, passionate and practitioner of Agile Practices to reach Technical Excellence