← All articles

Your Twelve Microservices Are One Service

Twelve repos, twelve pipelines, and a release train that still goes out together. There is a countable definition that explains why — and a whiteboard exercise that takes an afternoon and usually returns a much smaller number than the repo count.

Twelve repositories. Twelve pipelines. Twelve teams, notionally.

And a release that still has to go out together, because service four's migration breaks service nine, and nobody deploys on Friday.

The usual diagnosis is discipline — better contracts, better versioning, more tests. The actual diagnosis is that you do not have twelve services. There is a definition that settles it, and it is countable.

The definition

That definition is the architecture quantum:

an independently deployable unit that is functionally cohesive, carries everything it needs in order to run, and is bound to whatever it must call synchronously to serve a request

Three clauses, all load-bearing. The one that does the work here is the second — carrying everything it needs, which is static coupling — and it is worth being precise, because the whole diagnosis turns on it.

Static coupling is operational: what must exist for this thing to run at all. The OS, the frameworks, the transitively-pulled libraries, the schema, the credentials, and anything else without which the process does not come up healthy.

Dynamic coupling is communication: what it calls during a workflow, at runtime.

The distinction is the entire article. A service must have its database. It may call three other services while handling a request. Those are different relationships with different fixes, and conflating them is why so many decoupling projects deliver nothing.

Which gives the sharp consequence:

If a service can't run without a database that another service also can't run without, they are one quantum wearing two names, and "independently deployable" is a fiction.

A monolith, by this definition, is exactly one quantum — regardless of how tidy its internal packages are. And so are your twelve services, if they share a schema.

The counting exercise

This takes an afternoon and a whiteboard.

For each deployable, list everything it needs to start and be operational. Not what it talks to — what it cannot boot without:

  • the database schema it reads and writes
  • the shared library carrying your domain types
  • the config service it blocks on at startup
  • the auth provider it validates against
  • the message broker it must connect to before it is healthy

Then draw the overlaps. Every set that shares a required dependency is one quantum.

Teams doing this for the first time reliably discover the number is not twelve. It is three, or two, or one. The repo count was measuring how the code is organised, which is a real and useful thing, and not the same question.

The one-line version of the audit:

Can this deploy and run with all the others switched off?

If the honest answer is no, it is not a separate service, whatever the repository says.

The mistake this explains

Here is the failure mode the distinction predicts, and it is expensive.

A team feels the coupling. Deploys are entangled, changes ripple. So they act: introduce a message broker, convert synchronous calls to events, go asynchronous. Months of work. Real engineering.

They have attacked dynamic coupling — how services talk during a workflow.

The thing binding them was static — the shared schema underneath, which no amount of messaging touches. Two services sharing a database are statically coupled no matter how cleanly they message each other. The architecture diagram gets prettier. Deploys are still entangled, because the migration still breaks everyone.

The reverse mistake exists too and is rarer: splitting databases to fix what was really a chatty synchronous call path.

So before spending a quarter on decoupling, say out loud which kind you are fixing. If you cannot, you are not ready to spend the quarter.

The shared database, specifically

It is worth naming why this one dominates. A shared schema is the most efficient quantum-merger available:

  • It is invisible on the architecture diagram, where it appears as a box labelled "DB" that reads as infrastructure rather than as an interface with twelve consumers.
  • It has no version, no contract, and no consumer list, so its blast radius is unknowable without a query against production.
  • It is load-bearing at boot, which is precisely the static-coupling criterion.

There is a legitimate exception, and it matters: operational and analytical data are different animals. Operational data is what the business runs on — transactional, and if it stops the company stops. Analytical data is for prediction and trending; nobody notices its absence until the Monday report. A read-only analytical replica shared by many consumers does not merge their quanta, because nobody needs it to boot. Sharing the operational store does.

What to do with the number

You have counted. Suppose it is three, not twelve. Two honest options:

Separate the data, then the deployables. Data ownership comes first — each bounded context owning its operational store — because that is the coupling that actually binds. Splitting deployables before splitting data produces exactly the situation you are in.

Or accept three quanta and stop paying for twelve. This is the option nobody proposes in the meeting, and it is frequently right. If the boundaries are not real, the network hops between them are pure cost: latency, partial failure, distributed tracing, and an on-call rota, bought with no independence in return. Consolidating back to the real boundary count is a legitimate architectural move, not a retreat.

What you should not do is keep twelve pipelines and hope discipline will substitute for a boundary that does not exist.

The takeaway

A quantum measures — it does not prescribe. It tells you where your boundaries are, not where they should be. That is genuinely useful, because most teams in this situation are arguing about where boundaries should be while holding a wrong belief about where they currently are.

Count first. Then decide.

List what each deployable needs in order to start. Where those lists overlap, you have one service.