Guide contents

Lesson 58 of 129

Decomposition by Business Capability and Subdomain

Decomposition is the activity of dividing a system into services. The goal is that each service is cohesive, owns its data, and changes independently of the others. Two complementary methods derive boundaries from the business rather than from the code's technical structure: decomposition by business capability and decomposition by subdomain.

Decomposition by business capability

A business capability is something a business does to create value, described by what it achieves, not how. Capabilities are relatively stable: the way a company handles orders changes more often than the fact that it handles orders.

Procedure:

  1. List the organization's capabilities, using existing business documents, org charts, and interviews with domain experts.
  2. Arrange them in a hierarchy. Top-level capabilities are broad (Order Management); lower levels are specific (Order Fulfillment, Returns).
  3. Assign each capability, or group of closely related capabilities, to a service.
  4. Identify the data each capability owns.
  5. Identify the interactions between capabilities: which need synchronous answers, and which can be events.

Example capability tree for an online retailer:

graph TD
    R["Retail business"] --> Cat["Catalog management"]
    R --> Ord["Order management"]
    R --> Fin["Payments and billing"]
    R --> Log["Fulfillment and logistics"]
    R --> Cus["Customer engagement"]
    Ord --> Cart["Shopping cart"]
    Ord --> Place["Order placement"]
    Log --> Inv["Inventory"]
    Log --> Ship["Shipping"]
    Cus --> Notif["Notifications"]
    Cus --> Rev["Reviews"]

Decomposition by subdomain

The DDD approach (see domain-driven design and bounded contexts) divides the problem space into subdomains and aims for one bounded context per subdomain, with each context a service candidate.

Procedure:

  1. Explore the domain with domain experts (for example, through event storming: a workshop that lists domain events on a timeline, then groups them by the concept that produces them).
  2. Identify where the language changes: where a term changes meaning, a context boundary is likely.
  3. Classify subdomains as core, supporting, or generic.
  4. Define a bounded context for each, and a context map for their relationships.

Capability analysis starts from the organization's structure and what it does; subdomain analysis starts from the model and its language. They usually give similar boundaries, and comparing the two results is a check on both.

Worked example: order to shipment

Consider a retailer, with the following sample flow: a customer adds items to a cart, places an order, pays, the warehouse picks and ships, and the customer is notified.

Candidate services and their owned data:

Service Capability Owns Notes
Catalog Catalog management Products, descriptions, categories Read-heavy, changes independently of orders
Cart Shopping cart Carts, items Short-lived data
Order Order management Orders, order status Coordinates the order lifecycle
Inventory Inventory Stock levels, reservations Strict consistency on stock counts
Payment Payments Payment attempts, refunds Regulated; isolate, often generic
Shipping Shipping Shipments, carrier labels Integrates with carriers
Notification Notifications Templates, delivery log Generic; consumes events

What each context calls "product" differs: Catalog holds descriptions, Inventory holds SKUs and quantities, Order holds a snapshot of name and price at purchase time. The identifier (SKU) is the link between them; each service keeps only the attributes it needs.

The flow uses events at boundaries where the caller does not need to wait:

sequenceDiagram
    participant C as Customer
    participant O as Order
    participant I as Inventory
    participant P as Payment
    participant S as Shipping
    participant N as Notification
    C->>O: Place order
    O->>I: Reserve stock (command)
    I-->>O: StockReserved (event)
    O->>P: Charge payment (command)
    P-->>O: PaymentCompleted (event)
    O-->>S: OrderConfirmed (event)
    S-->>N: ShipmentDispatched (event)
    N->>C: Notification

The multi-step process across Order, Inventory, and Payment is coordinated with a saga. If the payment fails after stock is reserved, no single transaction can roll back both services, so the Order service sends a compensating command that releases the reservation.

Verbs versus nouns

A service can be defined around a noun (an entity, such as "Customer service" or "Product service") or a verb (an activity, such as "Checkout" or "Shipping").

  • Noun services tend to become CRUD wrappers around one table. Every feature that involves a customer then touches the Customer service, so it becomes a shared dependency, and behavior that belongs elsewhere accumulates in it.
  • Capability (verb-oriented) services keep the behavior together with the data that behavior needs. The same real-world entity appears in several services in different forms.

An entity name can still serve as a service name when the service owns a capability with real behavior. The test is whether the service holds business rules and owns its data, or is only a data-access layer.

Common wrong splits

Wrong split Problem
By technical layer (UI service, business logic service, data service) Every feature change crosses all layers, so all services change together
One service per database table or per entity Chatty calls, no cohesive behavior, distributed transactions for simple operations
By development phase or by team convenience Boundaries have no relation to change patterns
A "common" or "utility" service holding shared logic Becomes a dependency for everything; a single point of coupling and failure
Splitting a single aggregate across services The invariant can no longer be enforced in one transaction
Splitting before the domain is understood Boundaries move later, at high cost
Shared database with services split only in code Schema coupling remains, so services still cannot deploy independently

Validating boundaries

  • Do most feature changes touch only one service?
  • Can the service be deployed without coordinating with others?
  • Does it own its data, with no other service reading its tables?
  • Does one team own it end to end?
  • Can it answer its main requests without synchronous calls to many others?

If the answer to several is no, the boundary is a candidate for revision (see service granularity).

Interview questions

  • How does decomposition by business capability work? Identify what the business does, arrange capabilities in a hierarchy, and assign each capability with its data to a service. Capabilities are stable, so the boundaries are stable.
  • Why are services organized by technical layer a bad split? A feature typically needs changes in every layer, so each change requires coordinated changes and releases across services.
  • Why can a service per entity be a problem? Such services become thin data wrappers, behavior spanning entities requires many cross-service calls, and central entities (customer, product) become dependencies of all other services.
  • What is event storming used for here? It exposes domain events and where the language changes, which points to bounded context boundaries.