Microservices: the real problem is not service size, it is contracts
When companies move to microservice architecture, they discover that the main difficulty is not splitting the monolith - it is managing dependencies across APIs.
Conversations about microservices have changed considerably over the past two years. This used to be a topic for large technology companies. Now it comes up in mid-sized teams that are tired of their monolith and want to move faster.
I have nothing against microservices. But after two years of watching how this plays out in practice, I have a persistent feeling: most of the problems teams run into come not from service size, but from how dependencies between services are managed.
What typically happens during the transition
A team takes on a monolith and starts cutting. The first few services look clean: each does one thing, each owns its data. It feels good.
Then reality arrives. Services start calling each other. Request formats change quietly - someone added a field, someone renamed something. One service goes down and pulls three others with it, because dependencies are not described anywhere explicitly. The team discovers they do not have one monolith anymore - they have a distributed monolith, with the same problems, now also over the network.
A contract is not documentation
The typical response is to write documentation. Describe the API in a wiki, add request examples. Documentation goes stale faster than anyone reads it.
A contract is not a description of how an API works. A contract is an agreement that can be verified automatically. If service A expects a certain response format from service B, that expectation must be captured in tests that run with every change to service B. Without that, a "contract" is just text that nobody reads at the moment of change.
Contract testing tools have existed for several years. The question is not tooling - the question is whether contract governance has become part of the development process.
What breaks for the product owner
For a manager the problem looks different than it does for a developer. The symptoms are:
- releases slow down because changing one service requires manual verification of several others;
- incidents are increasingly explained by "service X changed its format and service Y did not know";
- nobody can answer confidently what will happen if you change a particular API field;
- onboarding a new developer takes weeks because the dependency map does not exist as a whole anywhere.
These are all symptoms of one problem: contracts between services are not managed - they simply exist.
Versioning as a discipline
A separate topic is API versioning. Many teams avoid it because it is extra work. Avoiding it costs more.
Without explicit versioning, any change can potentially break consumers. Teams start to fear changes, delay them, apply "backward-compatible" patches that gradually turn a clean interface into a tangled pile of optional fields.
The rule that works: any change that can break a consumer is a new version. The old version is supported until all consumers have migrated. This sounds heavy, but in practice it is cheaper than working through incidents.
Diagnostic questions
If you are thinking about microservice architecture or already living in it, a few questions help assess the maturity of contract governance:
- Can you get an up-to-date map of which services call which, in ten minutes?
- Are there automated tests that verify API compatibility between services?
- When did a change to one service's API last unexpectedly break another?
- Who decides whether an API change is "breaking" and requires a version bump?
- Does the developer changing an API have a tool to find out who uses that API?
If most of these questions have no confident answer, the conversation about the next service is worth postponing until the existing dependencies are in order.