Most teams never decide to create an unmanageable monolith. They add features, tables, shared libraries and dependencies until every meaningful release crosses the whole product. The opposite mistake is decomposing too early and discovering a distributed monolith instead.
“Services should have loose coupling and high functional cohesion.”Microsoft Azure Architecture Center · Microservices ↗
The market signal
Microsoft’s microservices guidance stresses loose coupling, cohesion, independent deployment, data ownership and failure isolation. AWS recommends understanding business capabilities and dependencies before decomposing a monolith, and documents patterns such as decomposition by business capability and the Strangler Fig. Martin Fowler’s “Monolith First” argument remains useful because service boundaries are expensive to get wrong.
The balanced conclusion: architect for independence before optimizing for service count.
How the accidental monolith forms
The early product chooses one runtime, one database and one deployment because that is the fastest path to MVP. Those choices are reasonable. The problem begins when every new domain keeps sharing the same schema, internal libraries, release train and scaling model long after the product has multiple teams and distinct workloads.
A system can also have 40 containers and still be a monolith if they must deploy together, share the same database and call one another synchronously for every request.
How stronger product companies handle it
| Anti-pattern | What it really signals | Better response |
|---|---|---|
| Many services deploy together | Distributed monolith | Revisit boundaries and independent deployment |
| Shared database schema | Data coupling | Explicit domain ownership before physical separation |
| Every team chooses a stack | Operational sprawl | Opinionated default + justified exception |
| One stack mandated forever | Workload constraint | Permit exceptions when economics or workload justify them |
| Kubernetes required for everything | Platform complexity leaked to teams | Golden paths and simpler managed services where appropriate |
The CodePravaha perspective
Use an Architecture Independence Ladder: Code boundaries → domain modules → explicit data ownership → independent deployment → independent scaling → justified technology choice.
The operating rule is Opinionated Default + Justified Exception. Give teams a preferred runtime, CI/CD, observability, secrets, API and infrastructure path. Allow deviation when a workload has a real technical or business need, not because every team wants a different tool.
When a module deserves to become a service
Extract when several of these are true: a distinct team owns it; it changes at a different cadence; it needs independent scale or availability; failures should be isolated; it has a clear business boundary; a different data technology is materially better; it can own its data; and it can deploy without coordinating with the core application.
If almost all answers are “no,” a modular component inside the existing deployable may be the simpler architecture.
What to change now
Metrics worth watching
Measure cross-team release dependencies, repositories/services touched per customer feature, percentage of independently deployable components, change failure blast radius, scaling cost by workload, shared-schema changes, synchronous dependency depth and developer time spent operating infrastructure rather than product capabilities.
Use an opinionated default stack, modular domain boundaries and a service-extraction test. Separate only when business ownership, scaling, reliability or change cadence justify it.