The tech industry loves a pendulum swing. For the past decade, "monolith" has been a dirty word, and microservices have been the promised land. But for many organizations, the harsh reality is that they've traded a single, manageable codebase for a distributed nightmare—the dreaded "distributed monolith."
The Correctness Fallacy
Microservices promise decoupling, but often deliver distributed coupling. If Service A cannot function without Service B, they are not decoupled; they are just communicating over a flakey network instead of a reliable function call. This introduces latency, serialization overhead, and the complex challenge of distributed transactions.
When Complexity is Justified
Microservices *do* have their place. They excel when you have distinct domains with clear boundaries, independent scaling requirements, and—crucially—teams large enough to support the operational overhead. If you're a team of five engineers managing twenty microservices, you aren't building a scalable system; you're building a resume.
The Modular Monolith
We advocate for starting with a "Modular Monolith." Define clear boundaries within a single codebase. Enforce them with linting rules or module systems. This gives you logic separation without the operational tax of orchestration, service discovery, and network failure modes. You can always split a well-structured module into a service later, but merging a spaghetti microservice architecture back into a monolith is a herculean task.