Let's start with the advice that loses us consulting revenue: most teams asking about microservices should keep their monolith. A well-factored monolith with a clean module structure is faster to develop, easier to test, cheaper to run, and simpler to debug than a distributed system — and a distributed system built from a badly factored monolith is that same mess with network calls between the pieces. The question isn't whether microservices are good. It's whether your constraints have genuinely outgrown a single deployable — and if so, how to split without betting the company.
When not to split (which is most of the time)
- Because the code is messy. Messy code needs refactoring, not distribution. Service boundaries drawn through a big ball of mud produce a distributed ball of mud.
- Because the team is small. Under roughly twenty engineers, in our experience, the operational tax of microservices — deployment pipelines, service discovery, distributed tracing, on-call complexity — outweighs the autonomy gains.
- Because it's the modern thing. Résumé-driven architecture is real and expensive.
- Because one endpoint is slow. Profile it. Cache it. Scale the monolith horizontally. Extraction is the most expensive performance fix available.
Signals you've actually outgrown it
- Teams block each other constantly. Multiple teams queueing on one release train, merge conflicts as a daily ritual, a broken build freezing everyone.
- Parts need genuinely different scaling or availability. A compute-heavy pricing engine and a CRUD admin panel sharing one deployment means paying for peak of both, everywhere.
- Regulatory isolation. When audit scope (PCI, banking regulation) covers the whole monolith because payment logic lives inside it, extraction can shrink compliance cost dramatically.
- Technology dead ends. One domain needs a runtime, language, or data model the monolith can't accommodate.
Notice these are organizational and operational signals, not aesthetic ones. That's Conway's Law working as intended: your architecture ends up mirroring your communication structure, so the right service boundaries are the ones that let teams ship independently — not the ones that look tidy on a whiteboard.
How: strangler fig, domain seams, one service at a time
Never do a big-bang decomposition. The pattern that works is the strangler fig: new services grow around the monolith, traffic shifts gradually, and the monolith shrinks until what remains is either gone or small enough to stop mattering. The playbook:
- 1. Find the domain seams. Service boundaries should follow business capabilities — orders, payments, identity — not technical layers. Domain-driven design's bounded contexts are the map. If two "services" would need to deploy together, they're one service.
- 2. Modularize in place first. Enforce the future boundary inside the monolith — separate modules, no cross-imports, calls through an interface. If the boundary doesn't work in-process, it definitely won't work over a network.
- 3. Extract the first service. Pick one that changes often (so the payoff is real) but isn't the scariest (so the learning is survivable). Route traffic to it behind a facade; keep the monolith's code path as fallback until confidence is earned.
- 4. Decompose the data — the actually hard part. Splitting code is easy; splitting the database is the project. Shared tables must become owned-by-one-service, cross-entity transactions become sagas or well-designed eventual consistency, and joins become API calls or replicated read models. Budget more time for this than for everything else combined; in our experience, teams that underestimated data decomposition are the ones that abandoned the migration halfway.
- 5. Integrate through events where you can. An event backbone (Kafka or equivalent) keeps services loosely coupled: publish "OrderPlaced" rather than synchronously calling four downstream services. Reserve synchronous calls for genuine request/response needs — chains of them just rebuild the monolith with latency.
Stop-when-done rule: the goal is not "microservices," it's independent deployability where it pays. Many successful decompositions end with four services and a smaller monolith — and that's a win, not an unfinished project.
Where AI-assisted analysis changes the work
The riskiest step — finding real seams in a codebase nobody fully understands — used to depend on tribal knowledge. AI coding agents change that: pointed at a decade-old monolith, an agent maps which modules touch which tables, traces call graphs across the boundary you're proposing, and flags the hidden couplings (shared mutable state, sneaky cross-module queries) that would have surfaced as production incidents in month six. It also accelerates the safety net — characterization tests around the seam before extraction — the same way it does in any modernization effort. The judgment calls — where the bounded contexts are, what consistency the business can tolerate — stay with your architects.
A real-world shape
If you want to see this pattern under maximum pressure — regulatory isolation, zero-downtime requirements, and a database at the center of everything — read our core-banking decomposition case study, where a strangler-fig extraction ran against a live core-banking monolith. Engagements like that typically run as a dedicated augmented pod working alongside the client's architects, though a fully bounded extraction can also be a managed outsourced deliverable.
Key takeaways
- Default to the monolith: split only on organizational, scaling, regulatory, or technology signals — never on aesthetics.
- Boundaries follow business domains and team structure (Conway's Law), not technical layers.
- Strangler fig, one service at a time, with the monolith as fallback — never big-bang.
- Data decomposition is the hard part; budget more for it than for everything else combined.
- Prefer event-driven integration; chains of synchronous calls rebuild the monolith with latency added.
- AI-assisted code analysis de-risks seam-finding and test backfill, but architects still own the boundary decisions.
Wrestling with a monolith that's outgrown its skin — or unsure whether it actually has? Talk to us. We'll tell you honestly if the answer is "keep the monolith, fix the modules."