Product architecture and engineering

An architecture serves a product. Never the other way round.

A project does not start by picking a database, a framework or a cloud architecture. It starts by understanding what the product has to make possible, the constraints it will meet, and the trajectory it has to be able to follow.

The architecture comes after.

Our aim is neither to build the simplest system possible nor the most sophisticated one. It is to find the minimal architecture that brings the guarantees the product needs to work today and to keep evolving tomorrow without losing its speed.

Product use
Real constraints
Intended trajectory
Guarantees needed
Architecture
Technologies
Technology is a consequence of what the product needs, not its starting point.

Building exactly what is needed

An application used by fifty people and a platform serving several million users do not need the same architecture. Nor do a product handling public data and software processing sensitive information.

Anticipating every possible need quickly leads to building complexity nobody yet knows will be of any use. Anticipating nothing creates the opposite problem: every change costs more than the one before it.

The work of architecture is therefore to find the right level of preparation.

Some decisions can wait, because they will be easy to revisit. Others have to be made properly from the start, because they concern the data, security, the boundaries of the system, or dependencies that will become hard to replace.

We invest where the cost of future change justifies it.

Standards, without a default architecture

Starting from the product does not mean starting from a blank page on every project.

Build enough applications and certain problems keep coming back: authentication, secret management, isolating components, deployment, storage, backups, logs, monitoring, environment management, scaling.

We have gradually turned that experience into reusable technical foundations. They let us start from practices that have already been proven, without imposing the same architecture on every product. The foundation is shared; what gets built on top of it depends on the context.

We work regularly on AWS, but also on infrastructure such as OVHcloud or Scaleway when hosting or sovereignty constraints — or simply the client’s context — call for it.

The provider is an implementation choice. The properties we are after stay the same.

The product

  • Specific features
  • Business data and usage
  • Particular constraints

Technical foundation

  • Security
  • Authentication
  • Deployment
  • Observability
  • Data and backups
  • Environment management
Reuse what has become standard, design what is specific to the product. The foundation is the same from one project to the next; the architecture resting on it never is.

An architecture has to be handed over

A system turns fragile when an important part of how it works exists only in the head of the person who built it.

That is particularly visible in infrastructure. Infrastructure configured by hand can work perfectly well for years. The trouble starts when it has to be reproduced, when someone needs to understand why a rule exists, rebuild an environment, or take responsibility for it.

Which is why we favour Infrastructure as Code: the infrastructure is described in versioned code that can be read and reproduced, rather than in a sequence of manual actions nobody can reconstruct.

The same principle applies elsewhere. The code should let a reader understand the structure of the system. Important decisions should be findable. Non-obvious business rules should be written down. Deployments should be reproducible.

The point is not to document everything. We document what would be expensive to rediscover.

Good documentation does not try to replace reading the code. It carries the context the code cannot explain on its own.

Quality as an accelerator

Tests, documentation, CI/CD, logs, typing and code review are often presented as rules of good conduct. We prefer to start from the reason they exist.

A test is useful when it prevents a regression that would be costly. A log is useful when it explains a problem that would otherwise be hard to reproduce. A CI pipeline is useful when it removes a fragile manual step from the release process. Documentation is useful when it spares the next developer from mentally rebuilding several weeks of context.

So these practices have no universal metric. 95% test coverage is not necessarily better than 60%. It depends on what is actually covered: testing trivial code heavily while leaving a critical business rule unprotected gives an excellent number and a poor guarantee.

The question is always the same: which risk are we trying to reduce?

The practiceWhat it has to bring
TestsConfidence in changes
CI/CDRepeatable releases
Infrastructure as CodeReproducible infrastructure
Logs and monitoringUnderstanding incidents
DocumentationPassing on the context
Typing and conventionsSafer changes
The practice is never the goal. The guarantee it brings is. That is what tells us when a practice deserves to be pushed further, and when it is already enough.

What AI changes in the way we build

LLM-based tools now speed up certain development tasks considerably: exploring a codebase, producing a first implementation, refactoring, writing documentation, generating tests. We use them daily.

But that acceleration makes the principles above more important, not less. Producing code has become cheaper. Deciding whether that code deserves to exist, whether it fits the system properly and whether it actually answers the need remains an engineering decision.

Automated test generation is a good example: producing hundreds of tests and reaching excellent coverage has become easy. It does not guarantee that the behaviours that matter are protected.

AI increases how much can be produced. It does not take over responsibility for the architecture.

Designing for change rather than predicting the future

An architecture has to prepare for change without trying to guess exactly which change will come.

Nobody knows for certain what a product will be in three years: which feature will grow in importance, which provider will have to be replaced, which piece of data will change role, or which regulatory constraint will appear.

So we spend less effort forecasting all of that than avoiding the decisions that would make some of it needlessly difficult. That means clear responsibilities between components, explicit interfaces, dependencies kept under control, and particular attention to the decisions that are hard to reverse.

Modularity is not a goal in itself. It becomes interesting when it lets one part of the system be changed without having to understand or rebuild all the others.

The same logic applies to microservices, event-driven architectures or any other pattern: their complexity has to be paid for by a real benefit.

Easy to changeHard to change

UI

Library

Provider

Data model

System boundaries

Invest progressively more in the decision

Not every decision costs the same to reverse. The ones a week of work can undo do not deserve a long debate; the ones that commit the data model and the system boundaries are paid for over years. It is that scale, rather than a general principle of modularity, that says where to invest.

Working with what already exists

Engineering is not only about designing new systems. A large part of the work is arriving on a product already in use, built under different constraints and sometimes by another team.

In that situation we do not set out to rebuild the product the way we would have built it ourselves. We start by understanding where the friction actually is.

Is it the architecture slowing the team down? A dependency that has become a blocker? A data model that no longer matches the business? Infrastructure that is hard to operate? A lack of observability? Or simply a part of the system that needs clarifying?

A difference in technical preference is not reason enough to rewrite. As with a prototype, what works stays until there is a concrete reason to change it.

When the state of an existing system has to be understood first, we start with a technology audit.

When a first version works but now has to carry the constraints of a real product, the subject becomes moving from prototype to production.

An architecture the team can keep alive

Ultimately we judge an architecture less by its diagram than by what it lets the team do.

Can they ship a new version without anxiety? Can they understand an incident quickly? Can they change a feature without unpredictable side effects? Can a new developer understand the system without depending for weeks on the people who built it?

And above all: can the product keep evolving at the pace of the company?

That is what engineering is for.

Our principle of quality as an accelerator, and how it fits into the way we build products, is set out in detail in the Vezero Method.