I’ve been pro-microservices for a while. I’ve built them. I’ve advocated for them. But we’re a few years into this movement now and I think it’s time to be honest about what’s actually happening in practice, because the gap between the pitch and the reality is getting hard to ignore.
The pitch is great. Break your monolith into small, independently deployable services. Each one owns its data. Teams pick their own stacks. Deployments are decoupled. Scaling is granular. Conway’s Law works in your favor. In the right hands, it’s beautiful. I’ve seen orgs genuinely transform their velocity by doing this thoughtfully.
Emphasis on thoughtfully.
Distributed monoliths. This is the most common failure mode and it drives me crazy. You decompose your monolith into twenty services, but they’re all calling each other synchronously, sharing databases under the table, relying on implicit contracts. You’ve paid the full price of distribution – network latency, partial failure, twenty deployment pipelines – without getting any of the independence you were supposed to get. Worst of both worlds.
Operational explosion. Your monolith had one deploy pipeline, one set of logs, one monitoring dashboard, one on-call rotation. Now you have twenty of each. Unless you built serious platform tooling first (and almost nobody does), the ops burden scales linearly with service count. Or worse.
Debugging nightmares. A request hits eight services and something goes wrong. Now you need distributed tracing, correlated logs, and a mental model of how all eight services interact. This is orders of magnitude harder than stepping through a monolith in a debugger. Teams dramatically underestimate this cost every single time.
Data consistency headaches. The minute you split data across services, you’re in the world of eventual consistency, sagas, and compensating transactions. For some domains that’s fine. For financial systems, inventory, anything with hard consistency requirements – it’s a constant source of bugs and cognitive load.
I think the mistake most teams make is treating microservices as a goal rather than a tool. The question shouldn’t be “how do we adopt microservices?” It should be “what problem are we actually trying to solve?”
If your monolith’s build takes an hour, maybe the answer is a better build system, not ten services. If teams keep stepping on each other’s code, maybe the answer is better module boundaries inside the monolith. If one component needs to scale independently, extract that one component. Don’t decompose everything because a conference talk made it sound like the right thing to do.
Start with a well-structured monolith. If you can’t maintain clean boundaries in a monolith, you absolutely will not maintain them across a network. And moving a boundary in a monolith is a refactor. Moving a boundary between services means rewriting protocols, migrating data, and coordinating deploys across teams. The cost is completely different.
If you do go the microservices route, invest in platform tooling first. Standardized service templates, centralized logging, distributed tracing, automated deploys. Without that platform, every new service is a snowflake, and the operational cost will eat you alive.
Keep services bigger than your instinct says. You can always split later once you understand the domain better. Premature decomposition is much harder to undo than premature coupling.
And just be honest about the costs. Microservices aren’t free. You’re trading local simplicity for global complexity. Sometimes that trade is worth it. Sometimes it really isn’t.
I suspect we’ll see a correction. Not everyone running back to monoliths, but a more nuanced conversation about when decomposition makes sense. The “modular monolith” pattern that’s starting to emerge feels right to me – you get team autonomy and clean boundaries without paying the full distributed systems tax.
The pendulum swung too far. It’ll come back. The people who do well through this will be the ones who kept their eye on the fundamentals: simplicity, clarity, and building the thing that actually fits the problem.