Home/Learn/Microservices/Service Decomposition Strategies

Service Decomposition Strategies

Intermediate
Fundamentals

Decompose by business capability, by subdomain (DDD), or by verb (action); wrong boundaries are the primary cause of microservices complexity and distributed monoliths.

Overview

Service decomposition is the most consequential decision in microservices architecture. Poor boundaries result in chatty networks, distributed monoliths, or nano-services that are harder to manage than what they replaced. The three main strategies are: decompose by business capability (stable organisational functions), by DDD subdomain (bounded contexts), and by use case or verb (each service owns one business action). The "strangler fig" pattern is the recommended migration path from a monolith — new features are built as services while the monolith is gradually hollowed out.

Decompose by Business Capability

A business capability is a stable function the organisation performs, e.g. Order Management, Customer Management, Billing. Each capability becomes a service with its own data store. This aligns with Conway's Law — teams map to services.

Conceptual — business capability decomposition
// Business capabilities → services

// Capability: Order Management
// Service: order-service
// Owns: orders DB table, order lifecycle state machine

// Capability: Customer Management
// Service: customer-service
// Owns: customers DB, profile management

// Capability: Billing
// Service: billing-service
// Owns: invoices, payment records

// Anti-pattern — shared database across services:
// order-service → JOIN customers → violates service independence
// ✗ SELECT o.*, c.email FROM orders o JOIN customers c ON o.customer_id = c.id

// Correct — order-service calls customer-service API:
// ✓ GET /customers/{id} → returns CustomerDTO to order-service

Decompose by Subdomain (DDD)

DDD bounded contexts define explicit linguistic boundaries. Each bounded context becomes one service (or a small cluster of related services). Ubiquitous language inside a context keeps the model consistent; context maps define inter-service integration.

Java — Anti-Corruption Layer for bounded contexts
// Bounded contexts in an e-commerce platform

// "Order" context — order-service
// Ubiquitous language: Order, LineItem, Fulfilment, ShipmentStatus

// "Catalogue" context — catalogue-service
// Ubiquitous language: Product, Variant, Inventory, PriceList
// Note: "Product" means something different in each context!

// Context Map — how they integrate
// ① Conformist: order-service conforms to catalogue-service's Product model
// ② Anti-Corruption Layer (ACL): order-service translates catalogue concepts
//    into its own domain model (LineItem, SKU) via an adapter

// ACL example
public class CatalogueAdapter {
    private final CatalogueClient catalogueClient;

    public LineItemDetails getLineItemDetails(String sku) {
        ProductDTO product = catalogueClient.getProduct(sku);  // external model
        return new LineItemDetails(                             // internal model
            product.getSku(),
            product.getDisplayName(),
            Money.of(product.getPriceCents(), "GBP")
        );
    }
}

Strangler Fig Migration

The strangler fig pattern incrementally replaces a monolith. New functionality is built as services; existing features are migrated one capability at a time. An API gateway or reverse proxy routes requests to the service or to the monolith based on the path.

Nginx — strangler fig routing strategy
# Step 1 — route new capability to microservice via API gateway (nginx example)
# Old path goes to monolith; new /api/v2/orders goes to order-service

location /api/v2/orders {
    proxy_pass http://order-service:8080;
}

location / {
    proxy_pass http://monolith:8080;   # all other traffic still hits the monolith
}

# Step 2 — strangler: migrate /api/v1/orders from monolith to order-service
# Deploy order-service, run dual-write, switch routing, then deprecate monolith endpoint

# Step 3 — extract customer capability
# Build customer-service, migrate data, update routing

# Eventually the monolith handles nothing and is decommissioned

Key Points to Remember

  • 1Decompose by business capability, DDD bounded context, or use case — choose the strategy that fits your team structure.
  • 2Wrong service boundaries cause distributed monoliths (tight coupling) or nano-services (excessive overhead).
  • 3Each service must own its own data store — no shared databases.
  • 4Anti-Corruption Layers translate between bounded contexts to protect the internal model.
  • 5Conway's Law: team structure influences service boundaries; align them intentionally.
  • 6Use the strangler fig pattern to migrate a monolith incrementally without a big-bang rewrite.

Interview Questions

Sign in to ask Aria
1

What are the main strategies for decomposing a monolith into microservices?

MediumAmazon
2

What is a bounded context and how does it guide service decomposition?

MediumThoughtWorks
3

What is the strangler fig pattern and when would you use it?

MediumNetflix
4

What makes a service boundary "wrong" and what are the symptoms?

HardUber
5

What is an Anti-Corruption Layer and why is it needed between services?

HardPivotal

Ask Aria about Service Decomposition Strategies

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…