Skip to main content

Domain-Driven Design for Microservices

Domain-Driven Design (DDD) is the foundation for properly decomposing systems into microservices. Without DDD, you’ll likely end up with a distributed monolith.
Learning Objectives:
  • Understand DDD strategic patterns
  • Identify bounded contexts in a domain
  • Map subdomains to microservices
  • Design aggregate boundaries
  • Apply context mapping patterns

Why DDD for Microservices?

DDD provides the conceptual framework to:
  1. Identify Service Boundaries - Bounded contexts become services
  2. Define Data Ownership - Aggregates define what a service owns
  3. Design Communication - Context maps define how services interact
  4. Align with Business - Ubiquitous language bridges tech and business
┌──────────────────────────────────────────────────────────────────┐
│                    DDD → MICROSERVICES MAPPING                    │
├──────────────────────────────────────────────────────────────────┤
│                                                                   │
│   DDD CONCEPT              →      MICROSERVICES                   │
│   ──────────────────────────────────────────────────────────     │
│   Bounded Context          →      Microservice                    │
│   Aggregate                →      Service's Data Ownership        │
│   Domain Event             →      Async Message/Event             │
│   Context Map              →      Service Integration Pattern     │
│   Ubiquitous Language      →      API Contract/Schema             │
│   Subdomain                →      Service Team/Ownership          │
│                                                                   │
└──────────────────────────────────────────────────────────────────┘

Strategic DDD Patterns

Subdomains

Every business has different types of domains:
What makes you competitive - The unique value proposition.
  • Invest most resources here
  • Custom-built, in-house
  • Highest quality code
  • Best engineers assigned
E-commerce Example:
  • Personalized recommendations
  • Dynamic pricing engine
  • Customer experience optimization
// Domain Classification Example
const domains = {
  core: {
    // Build in-house with best resources
    recommendationEngine: 'Custom ML pipeline',
    pricingEngine: 'Dynamic pricing algorithm',
    searchRelevance: 'Custom ranking algorithm'
  },
  supporting: {
    // Build in-house, standard quality
    orderManagement: 'Custom service',
    inventoryTracking: 'Custom service',
    customerReviews: 'Custom service'
  },
  generic: {
    // Buy or integrate
    emailService: 'SendGrid',
    paymentProcessing: 'Stripe',
    authentication: 'Auth0',
    analytics: 'Segment + Amplitude'
  }
};

Bounded Contexts

A bounded context is a boundary within which a particular domain model is defined and applicable.
E-COMMERCE BOUNDED CONTEXTS

┌─────────────────────────────────────────────────────────────────────────────┐
│                                                                              │
│  ┌─────────────────────┐    ┌─────────────────────┐                        │
│  │   CATALOG CONTEXT   │    │   SALES CONTEXT     │                        │
│  │                     │    │                     │                        │
│  │  Product:           │    │  Product:           │◀── Same word,          │
│  │  - SKU              │    │  - Price            │    different meaning!  │
│  │  - Description      │    │  - Quantity         │                        │
│  │  - Categories       │    │  - Discount         │                        │
│  │  - Images           │    │                     │                        │
│  │                     │    │  Order:             │                        │
│  │  Category:          │    │  - OrderId          │                        │
│  │  - Name             │    │  - Items            │                        │
│  │  - ParentCategory   │    │  - Total            │                        │
│  │                     │    │  - Status           │                        │
│  └─────────────────────┘    └─────────────────────┘                        │
│                                                                              │
│  ┌─────────────────────┐    ┌─────────────────────┐                        │
│  │  SHIPPING CONTEXT   │    │  BILLING CONTEXT    │                        │
│  │                     │    │                     │                        │
│  │  Product:           │    │  Product:           │                        │
│  │  - Weight           │    │  - TaxCategory      │                        │
│  │  - Dimensions       │    │  - Price            │                        │
│  │                     │    │                     │                        │
│  │  Shipment:          │    │  Invoice:           │                        │
│  │  - TrackingNumber   │    │  - InvoiceNumber    │                        │
│  │  - Carrier          │    │  - LineItems        │                        │
│  │  - DeliveryDate     │    │  - TaxAmount        │                        │
│  └─────────────────────┘    └─────────────────────┘                        │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

Notice: "Product" means different things in different contexts!

Ubiquitous Language

Each bounded context has its own vocabulary that everyone (developers and business) uses.
// Catalog Context - Language
class CatalogProduct {
  sku: string;
  title: string;
  description: string;
  categories: Category[];
  attributes: ProductAttribute[];
  images: Image[];
  
  // "Publishing" a product means making it visible
  publish(): void { /* ... */ }
  
  // "Archiving" removes from catalog
  archive(): void { /* ... */ }
}

// Sales Context - Different Language
class SalesProduct {
  productId: string;
  basePrice: Money;
  currentPrice: Money;
  discount?: Discount;
  
  // "Adding to cart" is meaningful here
  addToCart(cart: Cart, quantity: number): void { /* ... */ }
  
  // "Applying promotion" is sales concept
  applyPromotion(promo: Promotion): Money { /* ... */ }
}

// Shipping Context - Yet Another Language
class ShippingProduct {
  productId: string;
  weight: Weight;
  dimensions: Dimensions;
  isFragile: boolean;
  requiresSignature: boolean;
  
  // "Calculating shipping" makes sense here
  calculateShippingCost(destination: Address): Money { /* ... */ }
}

Context Mapping

Context maps show how bounded contexts relate to each other.

Relationship Patterns

Two teams share a subset of the domain model.
┌─────────────────┐     ┌─────────────────┐
│   Context A     │     │   Context B     │
│                 │     │                 │
│    ┌───────────────────────┐           │
│    │   SHARED KERNEL      │           │
│    │   (Shared Code)      │           │
│    └───────────────────────┘           │
│                 │     │                 │
└─────────────────┘     └─────────────────┘

Use when: Teams are closely aligned, small shared model
Caution: Changes require coordination

E-Commerce Context Map

                    CONTEXT MAP: E-COMMERCE PLATFORM
┌──────────────────────────────────────────────────────────────────────────┐
│                                                                           │
│         ┌──────────────┐         ┌──────────────┐                        │
│         │   CATALOG    │         │    SEARCH    │                        │
│         │   CONTEXT    │────────▶│   CONTEXT    │                        │
│         │              │Supplier │              │                        │
│         └──────┬───────┘/Customer└──────────────┘                        │
│                │                                                          │
│         Supplier/Customer                                                │
│                │                                                          │
│                ▼                                                          │
│         ┌──────────────┐                                                 │
│         │    SALES     │◀───────────────────────┐                        │
│         │   CONTEXT    │                        │                        │
│         │              │                        │                        │
│         └──────┬───────┘                        │                        │
│                │                                │                        │
│         Supplier/Customer              Supplier/Customer                 │
│                │                                │                        │
│      ┌─────────┴─────────┐                      │                        │
│      ▼                   ▼                      │                        │
│ ┌──────────────┐   ┌──────────────┐      ┌──────────────┐               │
│ │  INVENTORY   │   │   PRICING    │      │    USER      │               │
│ │   CONTEXT    │   │   CONTEXT    │      │   CONTEXT    │               │
│ │              │   │              │      │              │               │
│ └──────────────┘   └──────────────┘      └──────────────┘               │
│                                                  │                        │
│                                           Conformist                     │
│                                                  │                        │
│                                                  ▼                        │
│                           ┌────────────────────────────────┐             │
│                           │  EXTERNAL: AUTH0 (Identity)     │             │
│                           │  ┌─────────────────────────┐    │             │
│                           │  │ Anti-Corruption Layer   │    │             │
│                           │  └─────────────────────────┘    │             │
│                           └────────────────────────────────┘             │
│                                                                           │
│ ┌──────────────┐   ┌──────────────┐      ┌──────────────┐               │
│ │   SHIPPING   │   │   BILLING    │      │ NOTIFICATION │               │
│ │   CONTEXT    │   │   CONTEXT    │      │   CONTEXT    │               │
│ │              │   │              │      │              │               │
│ └──────────────┘   └──────────────┘      └──────────────┘               │
│        │                  │                     │                        │
│        │           Conformist                   │                        │
│        │                  ▼                     │                        │
│        │    ┌─────────────────────────┐        │                        │
│        │    │ EXTERNAL: STRIPE        │        │                        │
│        │    └─────────────────────────┘        │                        │
│        │                                        │                        │
│        │           Conformist                   │ Conformist             │
│        ▼                                        ▼                        │
│ ┌─────────────────────────┐     ┌─────────────────────────┐             │
│ │ EXTERNAL: FEDEX/UPS     │     │ EXTERNAL: SENDGRID/TWILIO│            │
│ └─────────────────────────┘     └─────────────────────────┘             │
│                                                                           │
└──────────────────────────────────────────────────────────────────────────┘

Tactical DDD Patterns

Aggregates

An aggregate is a cluster of domain objects treated as a single unit.
// Order Aggregate
// The Order is the Aggregate Root
class Order {
  private _id: OrderId;
  private _customerId: CustomerId;
  private _items: OrderItem[];  // Part of aggregate
  private _status: OrderStatus;
  private _shippingAddress: Address;  // Value Object
  
  // Only the Aggregate Root is referenced from outside
  // Other objects (OrderItem) are internal
  
  constructor(customerId: CustomerId, shippingAddress: Address) {
    this._id = new OrderId();
    this._customerId = customerId;
    this._items = [];
    this._status = OrderStatus.DRAFT;
    this._shippingAddress = shippingAddress;
  }
  
  // Business logic lives in the aggregate
  addItem(productId: ProductId, quantity: number, price: Money): void {
    if (this._status !== OrderStatus.DRAFT) {
      throw new Error('Cannot modify non-draft order');
    }
    
    const existingItem = this._items.find(i => i.productId.equals(productId));
    if (existingItem) {
      existingItem.increaseQuantity(quantity);
    } else {
      this._items.push(new OrderItem(productId, quantity, price));
    }
  }
  
  removeItem(productId: ProductId): void {
    if (this._status !== OrderStatus.DRAFT) {
      throw new Error('Cannot modify non-draft order');
    }
    
    this._items = this._items.filter(i => !i.productId.equals(productId));
  }
  
  submit(): DomainEvent[] {
    if (this._items.length === 0) {
      throw new Error('Cannot submit empty order');
    }
    
    this._status = OrderStatus.SUBMITTED;
    
    return [
      new OrderSubmittedEvent(this._id, this._customerId, this.total())
    ];
  }
  
  total(): Money {
    return this._items.reduce(
      (sum, item) => sum.add(item.subtotal()),
      Money.zero()
    );
  }
}

// OrderItem is part of the Order aggregate (not a separate aggregate)
class OrderItem {
  constructor(
    public readonly productId: ProductId,
    private _quantity: number,
    public readonly unitPrice: Money
  ) {}
  
  increaseQuantity(amount: number): void {
    this._quantity += amount;
  }
  
  subtotal(): Money {
    return this.unitPrice.multiply(this._quantity);
  }
}

Aggregate Design Rules

Rule 1: Reference by ID

Aggregates reference other aggregates only by their ID, never by direct object reference.
// ✅ Correct
class Order {
  customerId: CustomerId;
}

// ❌ Wrong
class Order {
  customer: Customer; // Don't embed
}

Rule 2: Small Aggregates

Keep aggregates small. Large aggregates cause concurrency issues.
// ❌ Too large
class Customer {
  orders: Order[];      // Grows unbounded
  reviews: Review[];    // Separate aggregate
}

// ✅ Better
class Customer {
  // Just customer data
}
class Order {
  customerId: CustomerId;
}

Rule 3: Consistency Boundary

The aggregate is the consistency boundary. Changes within are atomic.
// Order and its items are
// atomically consistent
await orderRepository.save(order);

Rule 4: Eventual Consistency

Use domain events for cross-aggregate consistency.
// Order submitted → Update inventory
// Done via events, eventually consistent
eventBus.publish(new OrderSubmittedEvent(...));

Value Objects

Immutable objects defined by their attributes, not identity.
// Value Object: Money
class Money {
  constructor(
    private readonly amount: number,
    private readonly currency: string
  ) {
    if (amount < 0) throw new Error('Amount cannot be negative');
    Object.freeze(this);
  }
  
  add(other: Money): Money {
    if (this.currency !== other.currency) {
      throw new Error('Cannot add different currencies');
    }
    return new Money(this.amount + other.amount, this.currency);
  }
  
  multiply(factor: number): Money {
    return new Money(this.amount * factor, this.currency);
  }
  
  equals(other: Money): boolean {
    return this.amount === other.amount && this.currency === other.currency;
  }
  
  static zero(currency: string = 'USD'): Money {
    return new Money(0, currency);
  }
}

// Value Object: Address
class Address {
  constructor(
    public readonly street: string,
    public readonly city: string,
    public readonly state: string,
    public readonly zipCode: string,
    public readonly country: string
  ) {
    Object.freeze(this);
  }
  
  equals(other: Address): boolean {
    return (
      this.street === other.street &&
      this.city === other.city &&
      this.state === other.state &&
      this.zipCode === other.zipCode &&
      this.country === other.country
    );
  }
  
  formatted(): string {
    return `${this.street}, ${this.city}, ${this.state} ${this.zipCode}, ${this.country}`;
  }
}

Domain Events

Events that indicate something important happened in the domain.
// Base Domain Event
abstract class DomainEvent {
  public readonly occurredAt: Date;
  public readonly eventId: string;
  
  constructor() {
    this.occurredAt = new Date();
    this.eventId = uuid();
  }
  
  abstract get eventType(): string;
}

// Specific Events
class OrderSubmittedEvent extends DomainEvent {
  constructor(
    public readonly orderId: OrderId,
    public readonly customerId: CustomerId,
    public readonly total: Money,
    public readonly items: Array<{productId: string, quantity: number}>
  ) {
    super();
  }
  
  get eventType(): string {
    return 'order.submitted';
  }
}

class OrderPaidEvent extends DomainEvent {
  constructor(
    public readonly orderId: OrderId,
    public readonly paymentId: string,
    public readonly amount: Money
  ) {
    super();
  }
  
  get eventType(): string {
    return 'order.paid';
  }
}

class InventoryReservedEvent extends DomainEvent {
  constructor(
    public readonly orderId: OrderId,
    public readonly reservations: Array<{productId: string, quantity: number}>
  ) {
    super();
  }
  
  get eventType(): string {
    return 'inventory.reserved';
  }
}

Mapping DDD to Microservices

From Bounded Context to Service

┌──────────────────────────────────────────────────────────────────────────────┐
│                     BOUNDED CONTEXT → MICROSERVICE                           │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│  SALES BOUNDED CONTEXT          →          ORDER SERVICE                      │
│  ────────────────────────────────────────────────────────────────────        │
│                                                                               │
│  Aggregates:                              Database Tables:                    │
│  ├── Order (Root)                         ├── orders                          │
│  │   └── OrderItem                        ├── order_items                     │
│  └── Cart (Root)                          └── carts                           │
│      └── CartItem                                                             │
│                                                                               │
│  Domain Events:                           Published Events:                   │
│  ├── OrderSubmitted                       ├── order.submitted                 │
│  ├── OrderPaid                            ├── order.paid                      │
│  └── OrderCancelled                       └── order.cancelled                 │
│                                                                               │
│  Commands:                                API Endpoints:                      │
│  ├── SubmitOrder                          ├── POST /orders                    │
│  ├── CancelOrder                          ├── DELETE /orders/:id              │
│  └── AddToCart                            └── POST /cart/items                │
│                                                                               │
│  Queries:                                 API Endpoints:                      │
│  ├── GetOrderById                         ├── GET /orders/:id                 │
│  └── GetOrderHistory                      └── GET /orders                     │
│                                                                               │
└──────────────────────────────────────────────────────────────────────────────┘

Service Structure Based on DDD

// Order Service - Folder Structure
order-service/
├── src/
│   ├── domain/                    # Core domain logic
│   │   ├── aggregates/
│   │   │   ├── order/
│   │   │   │   ├── Order.ts       # Aggregate Root
│   │   │   │   ├── OrderItem.ts
│   │   │   │   └── OrderId.ts     # Value Object
│   │   │   └── cart/
│   │   │       ├── Cart.ts
│   │   │       └── CartItem.ts
│   │   ├── value-objects/
│   │   │   ├── Money.ts
│   │   │   ├── Address.ts
│   │   │   └── Quantity.ts
│   │   ├── events/
│   │   │   ├── OrderSubmittedEvent.ts
│   │   │   └── OrderPaidEvent.ts
│   │   ├── services/              # Domain services
│   │   │   └── PricingService.ts
│   │   └── repositories/          # Interfaces
│   │       └── IOrderRepository.ts
│   │
│   ├── application/               # Use cases
│   │   ├── commands/
│   │   │   ├── SubmitOrderHandler.ts
│   │   │   └── CancelOrderHandler.ts
│   │   ├── queries/
│   │   │   └── GetOrderHandler.ts
│   │   └── services/
│   │       └── OrderApplicationService.ts
│   │
│   ├── infrastructure/            # External concerns
│   │   ├── persistence/
│   │   │   └── PostgresOrderRepository.ts
│   │   ├── messaging/
│   │   │   └── RabbitMQEventPublisher.ts
│   │   └── external/
│   │       └── InventoryServiceClient.ts
│   │
│   └── api/                       # HTTP layer
│       ├── controllers/
│       │   └── OrderController.ts
│       └── routes/
│           └── orderRoutes.ts

Anti-Corruption Layer Example

When integrating with external systems that have a different model:
// External Payment Provider (Stripe-like)
interface ExternalPaymentResponse {
  charge_id: string;
  amount_cents: number;
  currency: string;
  status: 'succeeded' | 'failed' | 'pending';
  failure_code?: string;
  failure_message?: string;
  created_at: number;  // Unix timestamp
}

// Our Domain Model
interface PaymentResult {
  paymentId: PaymentId;
  amount: Money;
  status: PaymentStatus;
  failureReason?: string;
  processedAt: Date;
}

// Anti-Corruption Layer
class PaymentProviderACL {
  constructor(private externalClient: ExternalPaymentClient) {}
  
  async processPayment(
    amount: Money,
    paymentMethod: PaymentMethod
  ): Promise<PaymentResult> {
    // Translate our model to external format
    const externalRequest = {
      amount: amount.cents,
      currency: amount.currency.toLowerCase(),
      source: this.translatePaymentMethod(paymentMethod)
    };
    
    // Call external service
    const externalResponse = await this.externalClient.createCharge(externalRequest);
    
    // Translate response back to our model
    return this.translateToPaymentResult(externalResponse);
  }
  
  private translatePaymentMethod(method: PaymentMethod): string {
    // Translation logic
    switch (method.type) {
      case 'CREDIT_CARD':
        return method.token;
      case 'BANK_TRANSFER':
        return method.accountToken;
      default:
        throw new Error(`Unsupported payment method: ${method.type}`);
    }
  }
  
  private translateToPaymentResult(response: ExternalPaymentResponse): PaymentResult {
    return {
      paymentId: new PaymentId(response.charge_id),
      amount: Money.fromCents(response.amount_cents, response.currency.toUpperCase()),
      status: this.translateStatus(response.status),
      failureReason: response.failure_message,
      processedAt: new Date(response.created_at * 1000)
    };
  }
  
  private translateStatus(externalStatus: string): PaymentStatus {
    const statusMap: Record<string, PaymentStatus> = {
      'succeeded': PaymentStatus.COMPLETED,
      'failed': PaymentStatus.FAILED,
      'pending': PaymentStatus.PENDING
    };
    return statusMap[externalStatus] || PaymentStatus.UNKNOWN;
  }
}

Event Storming Workshop

Event Storming is a workshop technique to discover bounded contexts.

Steps

1. DOMAIN EVENTS (Orange)
   What happened? Past tense verbs.
   ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
   │ Order Submitted │ │  Order Paid     │ │ Order Shipped   │
   └─────────────────┘ └─────────────────┘ └─────────────────┘

2. COMMANDS (Blue)
   What triggers events?
   ┌─────────────────┐    ┌─────────────────┐
   │  Submit Order   │───▶│ Order Submitted │
   └─────────────────┘    └─────────────────┘

3. AGGREGATES (Yellow)
   What data is needed?
        ┌─────────┐
        │  Order  │
        └────┬────┘

   ┌─────────┴────────┐
   ▼                  ▼
┌─────────────┐  ┌─────────────────┐
│Submit Order │  │ Order Submitted │
└─────────────┘  └─────────────────┘

4. BOUNDED CONTEXTS (Pink)
   Group related concepts
   ┌─────────────────────────────────────┐
   │         SALES CONTEXT               │
   │  ┌─────────┐ ┌─────────┐           │
   │  │  Order  │ │  Cart   │           │
   │  └─────────┘ └─────────┘           │
   └─────────────────────────────────────┘

Event Storming Result for E-Commerce

┌──────────────────────────────────────────────────────────────────────────────┐
│                         EVENT STORMING: E-COMMERCE                            │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                               │
│  CATALOG CONTEXT                    SALES CONTEXT                             │
│  ┌─────────────────────────────┐    ┌─────────────────────────────┐          │
│  │ • Product Created           │    │ • Item Added to Cart        │          │
│  │ • Product Updated           │    │ • Item Removed from Cart    │          │
│  │ • Product Published         │    │ • Cart Abandoned            │          │
│  │ • Product Archived          │    │ • Order Submitted           │          │
│  │ • Category Created          │    │ • Order Confirmed           │          │
│  │ • Product Categorized       │    │ • Order Cancelled           │          │
│  │                             │    │                             │          │
│  │ Aggregate: Product          │    │ Aggregates: Cart, Order     │          │
│  └─────────────────────────────┘    └─────────────────────────────┘          │
│                                                                               │
│  INVENTORY CONTEXT                  PAYMENT CONTEXT                           │
│  ┌─────────────────────────────┐    ┌─────────────────────────────┐          │
│  │ • Stock Received            │    │ • Payment Initiated         │          │
│  │ • Stock Reserved            │    │ • Payment Authorized        │          │
│  │ • Stock Released            │    │ • Payment Captured          │          │
│  │ • Stock Depleted            │    │ • Payment Failed            │          │
│  │ • Low Stock Alert           │    │ • Refund Issued             │          │
│  │                             │    │                             │          │
│  │ Aggregate: InventoryItem    │    │ Aggregate: Payment          │          │
│  └─────────────────────────────┘    └─────────────────────────────┘          │
│                                                                               │
│  SHIPPING CONTEXT                   NOTIFICATION CONTEXT                      │
│  ┌─────────────────────────────┐    ┌─────────────────────────────┐          │
│  │ • Shipment Created          │    │ • Email Sent                │          │
│  │ • Shipment Picked Up        │    │ • SMS Sent                  │          │
│  │ • Shipment In Transit       │    │ • Push Notification Sent    │          │
│  │ • Shipment Delivered        │    │ • Notification Failed       │          │
│  │ • Shipment Returned         │    │                             │          │
│  │                             │    │ Aggregate: Notification     │          │
│  │ Aggregate: Shipment         │    └─────────────────────────────┘          │
│  └─────────────────────────────┘                                             │
│                                                                               │
└──────────────────────────────────────────────────────────────────────────────┘

Interview Questions

Answer: A bounded context is a conceptual boundary within which a particular domain model is defined and applicable. It’s where a specific ubiquitous language is consistent.Key characteristics:
  • Same term can mean different things in different contexts (e.g., “Product” in Catalog vs Sales)
  • Each context has its own models, rules, and language
  • Maps naturally to microservices boundaries
  • Reduces complexity by limiting scope
Answer: An aggregate is a cluster of domain objects that can be treated as a single unit, with one entity acting as the root.Rules:
  1. Reference other aggregates by ID only
  2. Keep aggregates small
  3. Changes within aggregate are atomic (consistency boundary)
  4. Cross-aggregate consistency is eventual (via events)
Example: Order (root) contains OrderItems, but references Customer by ID.
Answer: An ACL is a translation layer between two systems with different models. It prevents external/legacy models from “corrupting” your domain model.Use cases:
  • Integrating with third-party APIs (Stripe, SendGrid)
  • Communicating with legacy systems
  • When upstream model doesn’t fit your domain
The ACL translates between external representations and your domain objects.
Answer:
  1. Event Storming: Workshop to discover domain events
  2. Identify Bounded Contexts: Group related events and concepts
  3. Define Aggregates: What data changes together?
  4. Map Context Relationships: Customer-Supplier, ACL, etc.
  5. Each Bounded Context → Microservice
Signs of good boundaries:
  • High cohesion within the service
  • Loose coupling between services
  • Clear ownership of data
  • Matches team structure

Summary

Key Takeaways

  • DDD provides the framework for microservice boundaries
  • Bounded contexts map to microservices
  • Aggregates define data ownership
  • Domain events enable loose coupling
  • ACL protects from external model pollution

Next Steps

In the next chapter, we’ll dive into Service Communication Patterns - how microservices talk to each other using REST, gRPC, and messaging.