C++20 Modules: A Gentle Hands-On Workshop
Join Lieven De Cock to take a small C++ library from headers to a working modular build with CMake, covering interfaces, partitions, existing headers and the std module.
🗓️ Wed 30 Sept, 11 AM ET · Recording included
✍️ From the editor’s desk
Welcome to the 65th issue of Deep Engineering!
Herb Sutter could not give his keynote at CppCon 2026, so Andrei Alexandrescu stepped in to talk about systems engineering, examining what happens when AI systems can generate large amounts of code with little effort while inspecting and validating that code remains the hard part.
Alexandrescu put much of his emphasis on the shift from authoring programs to understanding how a system is structured and how it evolves over time, with managing complexity at scale as the challenge ahead.
Nikolai Kutiavin reaches the same conclusion from a very different starting point, which is what makes his view worth reading right now. “If you asked me today to build the same C++ application I built as a student, the result would look completely different,” he writes, and a decade on he finds that the classes, containers and algorithms he relies on have barely changed, while the questions he asks before writing any code have changed completely. Today he starts by asking which components exist, which dependencies between them are allowed, how each one gets tested on its own, and how the build system enforces those decisions.
Those decisions stay critical and expensive even when writing code becomes cheap. As Sándor Dargó, senior engineer at Spotify, warned in our recent deep dive, a bad pattern that makes it into the codebase eventually becomes the one your agents copy next. Structural mistakes used to stay where you made them. Now they spread.
In today’s issue, we’re featuring Nikolai’s deep dive on seeing a C++ project as components rather than files. He previously built automotive software at BMW, and he now writes about C++, CMake, architecture and testing at sqglobe.com and also in his interesting newsletter, From Complexity to Essence in C++.
Let’s get started.
🔥 The C++ Programming Masterclass Bundle
📚 21 expert-led ebooks worth US$761 · Pay what you want
From bare-metal programming, memory management and templates to coroutines, CMake, CUDA, low-latency systems and Rust for C++ developers, all in one Humble Bundle from Packt.
Purchases also support The Global FoodBanking Network.
🧠 Practical Deep Dive
How 10 years of C++ changed the way I see a C++ project
If you asked me today to build the same C++ application I built as a student, the result would look completely different.
Not because I know more C++ syntax.
I would still use many of the same classes, containers, algorithms, and language features. What changed much more is how I see the application itself.
As a student, I saw a C++ project mostly as a collection of files and classes. My questions were simple: Which .cpp files do I need? Where should this new class go? How do I make everything compile?
After more than ten years of professional C++ development, I start with different questions: What are the components of this application? What responsibilities belong to each of them? Which dependencies should be allowed? How can they be tested independently? And how should the build system enforce these decisions?
This difference matters because a professional application has to do much more than work once.
It has to remain understandable, testable, and changeable after months or years of development.
That change in perspective did not come from learning one particular C++ feature. It came from maintaining production code, dealing with changing requirements, fixing architectural mistakes, writing tests, working with build systems, and discovering which decisions make a codebase easier to evolve and which ones make every future change more painful.
To make this shift concrete, consider a deliberately small example: a grep-like desktop application with a Qt user interface.
I will show how I would have approached this application as a student, and how I would design the same application today.
From files to components
As a student, I rarely thought about splitting an application into components.
I usually started with whatever project structure my IDE generated. When I needed a new class, I created another .h and .cpp file in the same project directory.
Suppose I had been asked to build a grep-like application with a Qt user interface.
I would probably have started with the generated MainWindow class. User interaction, error handling, and search logic would gradually accumulate in mainwindow.cpp.
I probably would not have put everything into that class. Some file-related operations might have escaped into the traditional refuge of homeless functionality:
utils.h and utils.cpp.
And I would have ended up with something like this:
For a small project, this can work surprisingly well.
The problem appears when the program starts growing.
MainWindow gradually becomes responsible for more than the user interface. Dependencies become implicit. Changing one part of the program unexpectedly affects another. Testing the search logic requires dealing with GUI code.
Today, I would start from a different question:
What are the components of this application?
For this small program, I might identify three:
files-search: file operations and match lookup;
gui: user interaction and presentation;
main: application composition and startup.
This looks like a small distinction, but it changes many later decisions.
Each component now has an explicit responsibility. Its implementation details can remain internal while only a small interface is exposed to other components.
As a result, I can change the implementation of file searching without rewriting the GUI. I can also test the search component without starting a Qt application.
The important shift is this:
I no longer see the application primarily as a collection of source files. I see it as a collection of cooperating components.
Files are merely the physical representation of that architecture.
Continue reading → In the rest of the piece, Nikolai rebuilds the application’s CMake around targets that enforce each component boundary, and shows how that design lets the search logic be tested on its own.
💪 We’re Big on C++
We’ve covered C++ in depth across our books, workshops, newsletter issues and long-form deep dives. Here are the pieces that stand out.
Design and decomposition: Sam Morley on decomposition and abstraction in C++, the real cost of every abstraction, and why clean code can be a trap when cache locality matters.
The state of the language: Jelle Bakker asks whether C++ is dead in the face of memory-safety guidance, and Sándor Dargó covers C++26 adoption traps and the compiler gap and the hidden cost of clever code.
Features in practice: Lieven De Cock builds three coroutines by hand to show why the boilerplate belongs in a library.
Review in the agent era: Sándor Dargó on why “fix this” is not enough, even when an agent wrote the code.
🛠️ Tool of the Week
Google’s C++ testing and mocking framework shipped version 1.18.0 in August, its first release since April 2025.
Links as a CMake target, so a test executable depends on a component exactly the way the application does
gMock ships in the same repository for faking the interfaces between components
CMake’s
gtest_discover_testsregisters every test case with CTest individuallyBSD-3-Clause licensed
📎 Tech Briefs
LLVM 23.1.2 released - LLVM publishes its second 23.1 point release, giving teams refreshed signed binaries across major development platforms.
Qt Creator 20.0.2 released - Android tooling fixes land alongside compatibility updates for Xcode 27, iOS Simulator, and Qt 6.12.
Qt 6.12 reaches release candidate - Qt’s next commercial LTS reached release candidate, with the final release scheduled for 30 September.
Qt patches QXmlStreamReader stack exhaustion - Qt patches CVE-2026-78253, preventing deeply nested XML from exhausting stacks and crashing applications parsing untrusted input.
The Address is Not The Place - Laurie Kirk presents an open-source C++26 residency library using reflection and annotations for developer-directed memory tiering.
That’s all for this week.
That’s all for this week. If you take one habit from Nikolai's piece, make it drawing the component boundary in CMake before the code needs it.
Keep building,
Saqib Jan, Editor-in-Chief, Deep Engineering
Partner with Deep Engineering
If your company wants to reach senior developers, software engineers, and technical decision-makers, speak to us about partnering with Deep Engineering.






