An architecture that leaves doors open
“The job of an architect is to build a structure that allows decisions to be delayed as long as possible”: 5 examples illustrating Uncle Bob’s point.

The job of an architect is to build a structure that allows decisions to be delayed as long as possible
This aphorism from Uncle Bob probably isn’t a definition of software architecture, but it highlights an essential component: the need to leave doors open and not to constrain the future. Or at least, as little as possible.
Here are five architectural considerations that illustrate this point.
Bounded contexts
Contexts, as defined by Domain-Driven Design, are areas of high cohesion that are loosely coupled to one another. Put another way, the proper boundaries of contexts are those that minimize the need for communication between them. Contexts are therefore areas of isolation: invoicing can reasonably be considered a distinct entity, almost independent of sales. It’s all in the “almost,” because there is, of course, an exchange of information (a sale triggers the issuance of an invoice). But making a business distinction between these two contexts still allows us to say that we can evolve one while minimizing the impact on the other and on the system as a whole. The doors remain wide open.
The Modular Monolith
Does it still need an introduction in 2025? The modular monolith is the voice of reason: it offers you nearly all the benefits of modularity, starting with the isolation I discussed earlier, without the drawbacks specific to deploying microservices. In practical terms, the various contexts, although functionally isolated, remain interconnected in terms of deployment. They are deployed as a single unit, forming a monolith. A well-organized monolith, and therefore one that can always be evolved into microservices later on, if needed. Once again, we’re leaving the door open; we’re not limiting our future options.
Hexagonal Architecture
We are now inside a context. As soon as there is even a little business logic, it must be isolated. Not only because this makes testing easier, but also because it is the most stable element over time. A company’s core business doesn’t change every other day, whereas technologies do. We’d therefore like to be able to write domain code while abstracting away from the technical details of the outside world (databases, third-party APIs, etc.). Fortunately, Hexagonal Architecture makes this possible, through dependency inversion and a few mappers. This lets us postpone the choice of technologies until later. And when the time comes to store data, we’ll make a much better choice, because we’ll know exactly what queries we need, both read and write.
The CQRS pattern
The CQRS (Command Query Responsibility Segregation) pattern involves separating the write and read models, allowing them to be specialized. In other words, it means having a very good write model and a very good read model rather than an “average” model that does both poorly. One could even have 1 read model and N write models. Put another way, this allows you to leave options open and postpone decisions until later. Event Sourcing, in particular, is often used as a write model. Its responsibility is to faithfully store all events in a tamper-proof (append-only) manner, regardless of how the information will be retrieved later. Accountants are very familiar with this concept.
SQL
I’ll grant you that SQL isn’t an architecture, it’s a language. But the reasoning holds: among all databases, SQL databases are unique in that they aren’t specialized for a single type of query. In principle, they allow for all queries, even if it means optimizing the execution path of a few of them later on. The physical model is designed with the eight normal forms in mind, and this physical model is modified only marginally to optimize queries. This contrasts with the NoSQL family, where the choice of database depends on a very specific query: to find all third-degree relationships of a person (a typical use case for a social network), it is better to use a graph database, such as Neo4j.
Conclusion
This insight from Uncle Bob shouldn’t be taken literally: the goal isn’t to create overly generic, convoluted systems “just in case,” but rather to build simple solutions that will evolve easily. In other words, don’t introduce complexity today, but allow for it to emerge tomorrow.