Decomposing by business capability, the strangler fig pattern, finding real seams in a monolith, database decomposition ordering, the nano-services anti-pattern, and Conway's Law.
Published September 23, 2026
The naive split — a "controllers service," a "business logic service," a "data access service" — creates services that must all change together for any single feature, achieving none of microservices' actual benefit (independent deployability). The correct axis is bounded context (a domain-driven-design term): each service owns a complete business capability end-to-end (its own API, business logic, and data) — an OrderService owning everything about orders, a PaymentService owning everything about payments, each independently deployable because a change to order logic never requires touching payment logic's code or deployment.
Named after a vine that gradually grows around and eventually replaces its host tree. Rather than a risky big-bang rewrite, traffic is incrementally routed away from the monolith to new services, one capability at a time:
Initially: [Client] → [API Gateway] → [Monolith: handles everything]
Mid-migration: [Client] → [API Gateway] → routes /orders/** → [New Order Service]
→ routes everything else → [Monolith]
Eventually: [Client] → [API Gateway] → routes to N services, monolith fully retired
The API Gateway's routing rules are what make this incremental — at every point, the system is fully functional, with some traffic hitting new services and the rest still hitting the (shrinking) monolith. This is dramatically lower-risk than "rewrite everything, then cut over," since any single migrated capability can be validated in production before the next one begins.
Before extracting anything, look for modules within the monolith that are already loosely coupled to the rest — minimal cross-module method calls, few shared database tables, a naturally cohesive responsibility. These pre-existing low-coupling boundaries are far cheaper to extract than tightly-coupled ones (which would require significant untangling work just to make extraction possible at all) — a monolith with genuinely well-factored internal modules (even if never deployed separately) is already most of the way toward a sensible service decomposition.
Extract the data first: split the capability's tables into a separate database/schema while the code temporarily accesses it across a boundary (or via a data-access layer) — this forces resolving cross-capability data dependencies (foreign keys spanning what will become two databases) up front, before any service-level extraction, at the cost of a period where extracted data is accessed somewhat awkwardly. Extract the code first: pull out the service's logic into its own deployable unit while it still shares the original database — faster to get a deployable service running, but defers the harder data-separation problem, and the new service still isn't independently scalable at the database layer until that's resolved. Neither order is universally correct — teams commonly choose based on which risk (data untangling vs premature service extraction complexity) is more manageable for their specific monolith.
Splitting too finely — a service so small its entire purpose could be one method — multiplies network overhead (every cross-service call is now a network round-trip instead of a method call) and operational cost (every service needs its own deployment pipeline, monitoring, on-call rotation) without a corresponding benefit. A service boundary should align with a genuine bounded context with real independent-deployability value, not be drawn just because "smaller services" sounds like the goal in itself.
"Organizations design systems that mirror their own communication structure." The practical implication for decomposition: service boundaries that don't match team boundaries tend to fight an uphill battle — a service owned by two separate teams with different priorities and release cadences creates exactly the coordination overhead microservices are meant to eliminate. Effective decomposition considers who will own each resulting service, not just the technical/domain boundary in isolation — aligning service boundaries with team boundaries (rather than fighting the org structure) tends to produce services that stay genuinely independently deployable in practice, not just on a diagram.
Q: How do you handle a business transaction that used to be a single database transaction across what are now two separate services? A: This is the classic distributed-transaction problem microservices decomposition creates — the standard answers are the Saga pattern (a sequence of local transactions, each publishing an event that triggers the next, with compensating actions to undo prior steps on failure) or accepting eventual consistency with a reconciliation process, rather than trying to preserve ACID guarantees across a network boundary.
Q: If strangler fig means the monolith and new services coexist for a while, how do you keep their data consistent during the transition? A: Commonly via a synchronization mechanism (the monolith publishes change events the new service consumes, or vice versa, depending on which system is the temporary source of truth for a given capability) — this transitional complexity is a real, often underestimated cost of the strangler fig approach, not a detail to skip over when planning a migration timeline.
Q: Is 'one service per team' always the right granularity implied by Conway's Law? A: Not strictly — the point isn't a rigid 1:1 mapping, it's that service boundaries crossing team boundaries create coordination friction. A single team can reasonably own multiple small, related services; the anti-pattern is one service requiring coordinated changes across multiple teams with independent priorities.
Q: How would you decide whether a specific module is a good extraction candidate? A: Look for low fan-in/fan-out with the rest of the codebase (few other modules call into it, it calls few others), a cohesive single responsibility already (an SRP violation within the module is a warning sign — see Single Responsibility & Open/Closed), and minimal shared-database-table overlap with modules staying in the monolith — a module scoring well on all three is a strong strangler-fig extraction candidate.