Don't get me started on Microservices

By Daniel Samson · 2026-05-04

TDLR: watch Don't Build a Distributed Monolith!

I am genuinely triggered!

I am sick of this mis-understanding about an architecture designed to allow many teams of 1000s of developers work in isolation from each other.

Microservices were invented to solve an organisational problem, not a technical one. At Amazon, Netflix, Google, you have thousands of engineers who physically cannot share a single codebase without trampling each other every day. Splitting the system along team lines lets each squad own their bit, ship on their own cadence, and not need a synchronised release train. That's the whole point of the pattern.

Most of us do not work at that scale. The team is five people. Ten on a good day. We don't have a team-coordination problem — we have a "Steve and Priya disagree about service boundaries" problem. Slapping microservices on top of that doesn't fix the disagreement; it codifies it in deployment topology.

You can scale a Monolith!

Horizontal scaling — multiple instances behind a load balancer — works exactly the same whether the binary is one service or fifty. Vertical scaling, in-memory caching, read replicas, sharding: all of these are available regardless of architecture. The decision between monolith and microservices has very little to do with how many requests per second you can serve.

When one specific module really does need its own scaling profile — say, a CPU-heavy image processor or a background job runner — you can extract just that piece as a sidecar service off the same image. You don't have to commit to splitting the entire app on day one. Scale the bit that hurts, leave the rest alone.

A Microservice is not a Tiny service

"Micro" is relative to the size of the organisation. Netflix's "tiny" services run on dozens of pods and have their own dedicated teams. To most businesses, a microservice is the same operational shape as a standalone app — same CI/CD, same secrets management, same observability stack, same on-call rotation, same auth setup.

Multiply that overhead by the dozen services you've decided to split your domain into and you're paying for a dozen apps. The fixed cost doesn't shrink just because you decided to call each one a microservice.

Stop Sharing the Database!

It happens almost every time. Two services need overlapping data, so they both connect to the same Postgres. Now the schema is a public contract: change a column and you're coordinating deploys across teams again. Congratulations — you've reinvented the monolith, except now it's distributed and a network partition can give you partial writes.

If two services genuinely need the same data, the answer is an event stream, an API call, or merging the services back into one. Not a shared schema held together with hopeful boundary etiquette.

Stick to one Tech Stack!

"Right tool for the job" sounds wonderful in a conference talk. In practice, a polyglot stack means you maintain separate build pipelines, separate dependency upgrades, separate security patching cycles, separate observability tooling, and separate libraries for the boring stuff — auth, retries, HTTP clients, logging. Every new language is roughly a doubling of the operational surface area.

Onboarding a new engineer? They now need to learn N languages and N idioms before they can ship a cross-cutting change. The team velocity loss is real and almost never accounted for in the original "the Go service will be faster" pitch.

One person is not NETFLIX!

A colleague I work with created an application using micro-service architecture with the best of intentions.

The services my colleague built can't be deployed independently because they all call on the same shared libraries and micro-services, which live in separate git repositories. A trivial change — updating some simple business logic — touches at least two repos. Meaning it takes at least one PR on two or more repos, four review cycles, and four releases that have to land in the right order.

This is the worst-case outcome of cargo-cult architecture: he took on every cost of microservices and got none of the benefits. The system is harder to reason about, harder to change, slower to ship. Sadly, my colleague had accidentally created a fractured distributed monolith, when a boring modular monolith would have sufficed.

Solution

One repository, one binary, one deploy. Inside the binary, enforce module boundaries the same way you'd enforce service boundaries — separate packages, clear interfaces, no cross-module reaching into private state. If a module needs its own database tables, give it a schema namespace. If it needs background workers, run them as sidecars off the same image.

When a specific module genuinely needs to scale independently — measured, not guessed — extract it. Pulling a well-defined module out of a monolith is far easier than gluing twelve fractured services back together after the fact.

Conclusion

Use a monorepo, draw clear module boundaries, deploy as one thing. Scale out the parts that demand it. Resist the temptation to fan everything out before you've earned the right to.

And really — go watch the video at the top. Twenty minutes of someone making this argument more patiently than I just did. Trust me! it will save you a lifetime of pain!