skip to content

Service Decomposition

Carving services along business capabilities and bounded contexts rather than technical layers, and extracting them gradually with the strangler-fig approach. The failure you must be able to name is the distributed monolith, where services must be deployed together anyway.

part ofMicroservices architectureoverview, primer and where to startread it →
on this pageshow

questions

6

When breaking a monolithic application into microservices, what does it mean to decompose 'by business capability' (e.g., Order Management, Inventory, Billing) rather than by technical layer (e.g., a separate UI service, a business-logic service, and a database-access service)? Why is the capability-based split generally preferred?

level: juniorimportance: must knowfreq 55%

answer

  1. capability = full vertical slice
  2. Conway's Law mirror
  3. layered split seeds distributed monolith
  4. event storming finds capabilities
  5. data ownership follows the capability

basics

~20 s

Group services around business functions like 'Orders', each owning its own logic and data end to end. Splitting by technical layer (UI service, logic service, DB service) instead forces every feature to touch several services at once.

solid answer

~40 s

Decomposing by business capability means each service encapsulates everything needed to deliver one coherent piece of business functionality — its API, business logic, and data — such as Order Management or Billing. This mirrors Conway's Law: teams organized around capabilities produce services that map to it and can ship changes independently. The alternative — layering by technical tier (a presentation service, a business-rule service, a shared database service) — forces almost every feature change to touch multiple services and coordinate multiple deployments, recreating monolith-style coupling with network calls added on top. Capability boundaries also tend to align with natural data ownership, keeping a service's data close to the logic that changes it.

go deeper

for a junior

Should recognize the difference between capability-based and layer-based splitting and give one concrete example of each.

for a middle

Should be able to run through an example decomposition (e.g., an e-commerce checkout) and assign capabilities to services with justification.

for a senior

Should discuss Conway's Law implications, how team topology drives capability boundaries, and when limited duplication across capabilities is the right trade-off.

for a principal

Should be able to critique an existing service map, identify where technical-layer thinking has crept in as a smell, and propose a re-decomposition strategy with migration cost in mind.

## What a capability boundary is Decomposing **'by business capability'** means drawing service boundaries around a coherent slice of what the business does — Order Management, Inventory, Billing, Customer Identity — rather than around a technical concern that cuts across every business function, such as 'presentation,' 'business rules,' or 'data access.' The mechanism starts before any code is written: teams run a discovery exercise — **event storming**, **capability mapping**, or simply interviewing domain experts — to trace the business's core processes end to end and find the natural seams. A **seam** is a point: - where vocabulary shifts (an 'order' becomes a 'shipment'); - where a different team or department owns the outcome; - or where the sub-process changes at a different rate and for different reasons than its neighbors. Each capability identified this way becomes a candidate service, and it owns: - its own **API**; - its own **business logic**; - and — critically — its own **data**, so that no other service reaches into its database or its internal model to get work done. ## Why the capability axis exists This exists to solve a coupling problem that predates microservices: distributed systems built on technical layering. In a layered split, you might get: | Layered service | What it takes on | |---|---| | `Presentation/API` | all clients call it | | `Business Rules` | all domain logic funnels through it | | `Data Access` | owns the database | On paper this looks like separation of concerns — it is the classic three-tier architecture pattern, just deployed as separate network services instead of in-process layers. In practice, almost every new business feature (adding a discount code, changing how refunds work) has to touch all three layers and be deployed together, because business changes are vertical (cut across a capability) while the split is horizontal (cuts across capabilities). You end up with the operational overhead of microservices — network calls, serialization, separate deploy pipelines — combined with the change coupling of a monolith. **Capability-based decomposition avoids this** because it makes the unit of change (a business feature) match the unit of deployment (a service): a change to how orders are validated lives entirely inside the Order Management service. ## The trade-off The trade-off is real and shows up on both sides. - Capability decomposition demands **upfront domain knowledge** that a technical split doesn't — you need to understand the business well enough to know where the seams actually are, and getting that wrong (drawing a boundary through the middle of a process that should stay together) is expensive to fix later, since it usually means moving data ownership between services. - It also tends to push **cross-cutting concerns** — input validation rules, currency formatting, authentication checks — toward **controlled duplication**: each capability either re-implements a small piece of shared logic or pulls in a shared library, because routing every capability's requests through one central 'Validation Service' would recreate the very technical-layer coupling you were trying to escape. - **A layered split, by contrast,** gives you a single place to put genuinely shared logic and requires less upfront domain modeling — its failure mode just arrives later, as change coupling, rather than upfront as design risk. ## Failure modes The failure mode of getting this wrong is visible in operations long before anyone calls it out in a design review: - deployment calendars where three or four 'independent' services always ship together for a single feature; - pull requests that touch multiple repos for what the business considers one change; - on-call engineers who can't explain what a service does in business terms, only in technical terms ('it's the one that talks to the database'). Another common failure is stopping the capability search too early and naming a service after a system concept rather than a business one — e.g., a 'Cache Service' or a 'Notification Service' that every capability calls for a synchronous business decision, which quietly becomes a new bottleneck layer. ## Where it shows up A well-known real-world illustration is **Amazon's shift** away from a monolithic retail platform toward services owned end-to-end by small ('two-pizza') teams, each responsible for a business capability — Cart, Checkout, Recommendations, Fulfillment — including that capability's data store, with communication only through published APIs, not shared databases. This is frequently cited, including by Amazon's own engineering leadership, as the organizational precondition that made later independent deployability possible. **The counter-example** is common in early 2000s SOA rollouts, where organizations stood up an Enterprise Service Bus and a layer of 'reusable' services (a shared customer-lookup service, a shared pricing-rules service) that every business process had to call through — reintroducing a central coordination point and, functionally, a distributed monolith with extra network hops.

  • What technique do teams commonly use to discover the right capability boundaries before writing any service code?
    Event storming or capability mapping workshops with domain experts, where you trace business processes end-to-end and identify natural seams — points where vocabulary changes, ownership changes, or where a sub-process could evolve independently. These seams often align with the bounded contexts DDD identifies, which then become candidate service boundaries.
  • If two services both need to validate a shipping address, does capability decomposition mean duplicating that logic?
    Often yes, in a controlled way — either duplicating a small validation library across services or extracting a shared utility library (not a service) that's compiled into each. The alternative, a shared 'Address Validation' service every capability calls synchronously, reintroduces coupling and a single point of failure for something that's cheap to duplicate.
  • How does Conway's Law relate to choosing capability-based boundaries?
    Conway's Law says system structure mirrors the communication structure of the organization that built it. If you organize teams around business capabilities, the services they build will naturally align to those capabilities; if teams stay organized by technical specialty, the resulting services will end up layered and coupled regardless of the intended design.

Like organizing a hospital by department (Cardiology, Radiology, Billing) where each department has its own staff, equipment, and records — versus organizing it by job title across the whole hospital (all nurses in one pool, all clerks in another), where treating one patient requires coordinating five separate pools for every step.

saying these in an interview costs you the question

  • Proposes a shared 'business logic service' called by every other service for core rules
  • Cannot name a business capability, only technical layers, when asked to sketch service boundaries
  • Assumes decomposition is purely a technical exercise with no reference to team structure or domain
  • Treats 'one service per database table' as the same thing as capability decomposition

context

open as a page

How do bounded contexts (from Domain-Driven Design) inform where you draw microservice boundaries, and what concrete symptoms show up when a service's boundary crosses into a neighboring bounded context?

level: middleimportance: must knowfreq 70%

basics

~20 s

A bounded context is where one business term has one consistent meaning (e.g., 'Customer' differs between Billing and Support). Match each service to one context; crossing that boundary causes inconsistent meanings and constant translation code between services.

open as a page

Walk through how you'd use the strangler fig pattern to extract one capability — say, Inventory Management — out of a monolith into its own service, without a big-bang rewrite. What are the concrete steps, and how is traffic routed during the transition?

level: middleimportance: must knowfreq 65%

basics

~20 s

Build the new Inventory service beside the old monolith, redirect traffic bit by bit through a router. Once the old code sees no traffic, delete it — like a strangler fig vine replacing host tree.

open as a page

A company has split its monolith into 15 separately-deployed services, but every release still requires deploying most of them together in a fixed order, and a single slow service brings down request chains everywhere. What is this failure mode called, and what specific decomposition mistakes typically cause it?

level: seniorimportance: must knowfreq 75%

basics

~10 s

This is a distributed monolith: separate services still tightly coupled (shared code, chatty synchronous calls, or a shared database), so you can't deploy them independently — all of microservices' overhead, none of the benefit.

open as a page

When you decompose a monolith's single database into per-service data stores, how do you decide which service owns a given piece of data, and when is it appropriate to replicate that data into another service versus having that service call the owner synchronously on every read?

level: seniorimportance: should knowfreq 60%

basics

~20 s

Give each piece of data one owning service that's the source of truth for writes. Others call the owner for occasional fresh reads, or keep a replicated copy, updated via events, for frequent reads or to stay available if the owner is down.

open as a page

A platform team has split a product catalog capability into 12 tiny services (ProductName, ProductPrice, ProductImages, ProductReviews-summary, and so on), each with its own repo, pipeline, and on-call rotation. What's this anti-pattern usually called, what does it cost in practice, and how would you decide the right granularity instead?

level: principalimportance: should knowfreq 45%

basics

~20 s

This is over-decomposition, or 'nanoservices' — splitting so finely that running each piece (deploys, monitoring, network calls) costs more than the benefit. Right size is roughly 'one team, one business capability,' not 'one service per field.'

open as a page