Documents/domain/DDD Fundamentals

DDD Fundamentals

Domain-Driven Design — Reference Guide

DDD fundamentals applied to microservices decomposition. This is the "theory" — Business Domain.md is the "practice" applied to the assessment.


1. What is DDD & Why Does It Matter Here?

Domain-Driven Design (Eric Evans, 2003) = 
  Software design centered on the DOMAIN (business domain)
  not on technology.

Why is it critical for microservices?
  Monolith → Microservices = WHERE do you cut?
  DDD provides the answer: cut along BOUNDED CONTEXTS
  
  Wrong: cut by layer (1 service for DB, 1 for API, 1 for UI)
  Wrong: cut by code module (arbitrary boundaries)
  Right: cut by DOMAIN BOUNDARY (each service = 1 business capability)

2. Strategic Design — High-Level Concepts

2.1 Domain & Subdomain

Domain = the entire business area the software serves
  Example: Enterprise Travel & Event Management Platform

Subdomain = a smaller part of the domain, divided by business function

3 types of Subdomains:
┌─────────────────────────────────────────────────────────────┐
│                                                              │
│  CORE DOMAIN           SUPPORTING DOMAIN    GENERIC DOMAIN   │
│  ─────────────         ─────────────────    ──────────────   │
│  Competitive           Needed but does not  Commodity,       │
│  advantage.            create competitive   buy off-the-shelf│
│  Must build in-house,  advantage.           or use existing  │
│  invest the most       Build or buy         platform         │
│                                                              │
│  Examples:             Examples:             Examples:        │
│  • Travel Booking     • Workforce Mgmt     • Email/SMS       │
│  • Event Management   • Reporting          • Authentication  │
│  • Payment            • Allocation         • File Storage    │
│                                                              │
│  → Pour resources &   → Adequate quality   → Buy SaaS or    │
│    AI effort here       is sufficient         use platform   │
└─────────────────────────────────────────────────────────────┘

2.2 Bounded Context

Bounded Context = a clear semantic boundary for a domain model

Key insight:
  The same word "Booking" has DIFFERENT MEANINGS in different contexts:
  
  Travel Context:    Booking = flight + hotel + itinerary + pricing
  Event Context:     Booking = venue + date + capacity + registration
  Payment Context:   Booking = transaction reference + amount + status
  Workforce Context: Booking = staff assignment + shift + location

  → Each context has its OWN MODEL for "Booking"
  → NO shared model → NO shared database
  → This is the reason for per-service databases

Bounded Context ↔ Microservice mapping:

Ideal: 1 Bounded Context = 1 Microservice

In practice: 
  • 1 BC can = multiple services (if BC is too large)
  • Multiple BCs can = 1 service (if BCs are too small, use modules within 1 service)
  
For this assessment (5 engineers):
  1 BC = 1 Service is the right granularity (not too small, not too large)

2.3 Ubiquitous Language

Ubiquitous Language = SHARED LANGUAGE between developers and business
  Each Bounded Context has its own language
  Code must REFLECT business language

Example (Travel Context):
  ✅ class Itinerary { ... }           not ❌ class TravelPlan { ... }
  ✅ class BookingConfirmation { ... }  not ❌ class OrderStatus { ... }
  ✅ method ConfirmBooking()            not ❌ method ProcessOrder()

Why does this matter?  
  When business says "confirm booking" → dev finds ConfirmBooking()
  No need to "translate" between business language and code

2.4 Context Map — Relationships Between BCs

Bounded Contexts are NOT fully isolated — they interact.
The Context Map describes HOW they interact.

Relationship patterns:
┌──────────────────────────────────────────────────────────────┐
│                                                               │
│  PARTNERSHIP                                                  │
│  Two teams coordinate, co-develop the interface               │
│  Travel ←→ Event: shared concepts "date", "location"          │
│                                                               │
│  CUSTOMER-SUPPLIER (upstream/downstream)                      │
│  Upstream provides data, downstream consumes                  │
│  Travel (upstream) → Reporting (downstream): booking data      │
│                                                               │
│  CONFORMIST                                                    │
│  Downstream accepts upstream model as-is                       │
│  External GDS API → Travel: must conform to external schema    │
│                                                               │
│  ANTI-CORRUPTION LAYER (ACL)                                  │
│  Downstream translates upstream model to internal model        │
│  New Services → ACL → Legacy Monolith (Payment)               │
│                                                               │
│  SHARED KERNEL                                                 │
│  Two BCs share a small part of the model (use with caution!)  │
│  Shared: UserId, Currency, DateRange value objects             │
│                                                               │
│  OPEN HOST SERVICE + PUBLISHED LANGUAGE                       │
│  Service exposes public API with well-defined schema           │
│  API Gateway: exposes REST API for all consumers               │
│                                                               │
└──────────────────────────────────────────────────────────────┘

3. Tactical Design — Concepts Within a Bounded Context

3.1 Building Blocks

┌──────────────────────────────────────────────────────────┐
│            Tactical Design Building Blocks                │
│                                                           │
│  ENTITY                                                   │
│  • Has identity (ID)                                      │
│  • Lifecycle: created → modified → deleted                │
│  • Examples: Booking, User, Event                         │
│                                                           │
│  VALUE OBJECT                                             │
│  • No identity, compared by value                         │
│  • Immutable                                              │
│  • Examples: Money(100, "USD"), DateRange(start, end),    │
│              Address(street, city, country)                │
│                                                           │
│  AGGREGATE                                                │
│  • Cluster of entities + value objects                    │
│  • 1 AGGREGATE ROOT = entry point                         │
│  • Transaction boundary: save/load entire aggregate       │
│  • Examples: Booking (root) → BookingItems → Travelers    │
│                                                           │
│  DOMAIN EVENT                                             │
│  • Records "something happened"                           │
│  • Past tense: BookingCreated, PaymentProcessed            │
│  • Triggers side effects within or across services        │
│                                                           │
│  REPOSITORY                                               │
│  • Interface for accessing aggregates from persistence    │
│  • IBookingRepository.GetById(id)                          │
│  • Implementation: EF Core, Dapper, etc.                   │
│                                                           │
│  DOMAIN SERVICE                                            │
│  • Logic that doesn't belong to a single entity           │
│  • Example: PricingService.CalculateTotal(booking, rules)  │
│  • Stateless                                               │
│                                                           │
│  APPLICATION SERVICE                                       │
│  • Orchestrates use cases, contains no business logic     │
│  • MediatR handler = application service                   │
│  • Example: CreateBookingHandler calls domain → repo → event│
│                                                           │
└──────────────────────────────────────────────────────────┘

3.2 Aggregate Design Rules

Rules for aggregate design (critical for microservices):

1. PROTECT INVARIANTS WITHIN AGGREGATE
   Booking total must = sum(BookingItem.price)
   → Booking aggregate enforces this rule
   
2. SMALL AGGREGATES
   Small aggregate = small transaction = better performance = less concurrency conflict
   ❌ 1 aggregate with 10,000 child entities
   ✅ Booking with max 20-50 BookingItems
   
3. REFERENCE OTHER AGGREGATES BY ID
   ❌ Booking.Traveler (embedded)  
   ✅ Booking.TravelerId (ID reference)
   → Cross-aggregate = eventual consistency
   
4. ONE AGGREGATE = ONE TRANSACTION  
   Never save 2 aggregates in 1 DB transaction
   → Use domain events to sync between aggregates

3.3 CQRS & Event Sourcing

CQRS (Command Query Responsibility Segregation):
┌─────────────────────────────────────────────────┐
│                                                  │
│  Commands (Write)         Queries (Read)         │
│  ─────────────            ────────────           │
│  CreateBooking            GetBookingById         │
│  CancelBooking            SearchBookings         │
│  UpdateItinerary          GetDashboard           │
│                                                  │
│  Write Model              Read Model             │
│  (normalized,             (denormalized,         │
│   domain-rich)            query-optimized)       │
│                                                  │
│  Azure SQL                Azure SQL (views)      │
│  (transactional)          or Redis (cache)       │
│                                                  │
│  → Scale independently                           │
│  → Optimize each for its purpose                 │
└─────────────────────────────────────────────────┘

Event Sourcing (optional, per aggregate):
  Instead of storing current state → store sequence of events
  
  BookingCreated → ItemAdded → ItemAdded → PaymentReceived → Confirmed
  
  Rebuild state: replay events from beginning
  
  ✅ Benefits: Full audit trail, temporal queries, debugging
  ❌ Cost: Complex, eventual consistency, snapshots needed for performance
  
  Recommendation for this project: 
    CQRS = YES (for all services)
    Event Sourcing = SELECTIVE (only Booking aggregate if audit is required)

4. DDD in the Microservices Context

4.1 Bounded Context → Service Boundary

DDD concept              → Microservice equivalent
──────────────────         ──────────────────────────
Bounded Context          → Service boundary
Ubiquitous Language      → API contract + event schema
Aggregate                → Internal consistency boundary
Domain Event             → Integration event (cross-service)
Repository               → Service's database
Context Map              → Service communication topology
ACL                      → Adapter service / gateway layer

4.2 Communication Patterns

WITHIN a service (synchronous):
  API → Application Service → Domain Service → Repository
  MediatR pipeline: Request → Handler → Response
  
BETWEEN services (asynchronous preferred):
  Service A → publish DomainEvent → Azure Service Bus
  Service B → subscribe → handle event → update own state
  
  Example:
  Travel publishes BookingConfirmed
  → Workforce subscribes → auto-allocate staff
  → Communications subscribes → send confirmation email
  → Reporting subscribes → update dashboard
  
BETWEEN services (synchronous when needed):
  Service A → HTTP call → Service B API
  Use when: immediate response needed (price check, availability)
  Risk: coupling, cascading failure
  Mitigation: Circuit breaker (Polly), timeout, cache

4.3 Data Ownership

RULE: Each service OWNS its data. No shared database.

┌──────────┐     ┌──────────┐     ┌──────────┐
│ Travel   │     │ Event    │     │ Workforce│
│ Service  │     │ Service  │     │ Service  │
│          │     │          │     │          │
│ ┌──────┐ │     │ ┌──────┐ │     │ ┌──────┐ │
│ │Travel│ │     │ │Event │ │     │ │WFM   │ │
│ │ DB   │ │     │ │ DB   │ │     │ │ DB   │ │
│ └──────┘ │     │ └──────┘ │     │ └──────┘ │
└──────────┘     └──────────┘     └──────────┘
      ↑                ↑               ↑
      └────── NO cross-DB JOINs ──────┘
      
Instead:
  • API calls to get data from other services
  • Event subscriptions to maintain local copies (read model)
  • CQRS read model denormalizes data needed from multiple sources

5. Anti-Patterns to Avoid

Anti-Pattern Description Why It's Wrong Correct Approach
Distributed Monolith Microservices that must be deployed together Worst of both worlds: latency + coupling Loose coupling, async events
Shared Database 2 services sharing the same DB Coupled via schema, cannot deploy independently Per-service DB
Anemic Domain Model Entities with only properties, logic in services Violates OOP, business logic scattered Rich domain model, logic in entities
God Service 1 service doing everything This is just a monolith in disguise Split by bounded context
Chatty Services Service A calls B calls C calls D synchronously Latency cascade, failure cascade Async events, CQRS read model
Wrong Boundary Split by tech layer (DB service, API service) Every feature change → modify every service Split by business capability
Big Bang Migration Migrate everything at once Zero downtime violated, massive risk Strangler Fig, module by module

6. DDD Process — How to Apply It

Step 1: EVENT STORMING (workshop)
  Team + domain expert sticky notes events → discover domain
  Output: list of domain events, aggregates, commands
  
Step 2: IDENTIFY BOUNDED CONTEXTS
  Group related events/aggregates → context boundaries
  Look for: different language, different lifecycle, different team
  
Step 3: CONTEXT MAP
  How do contexts interact? Who depends on whom?
  Identify: upstream/downstream, ACL needs, shared kernel
  
Step 4: DESIGN AGGREGATES
  Per bounded context: what are the aggregates?
  Apply small aggregate rules
  Define domain events per aggregate
  
Step 5: DEFINE APIs & EVENTS
  External contract: REST API schema + event schema
  Internal: domain model, handlers, repositories
  
For this assessment (5 engineers, with AI):
  Step 1: AI analyzes legacy code → extracts events (replaces workshop)
  Step 2: AI suggests boundaries → team validates
  Step 3: Team designs context map
  Step 4-5: AI generates boilerplate → team reviews domain logic

7. Key DDD Concepts Summary Table

Concept Definition Level Application
Domain Business domain Strategic Entire platform
Subdomain Sub-area of domain Strategic Travel, Event, Payment, ...
Bounded Context Semantic boundary for a model Strategic = Service boundary
Context Map Map of context relationships Strategic Service topology
Ubiquitous Language Shared language (dev + business) Strategic API + event naming
Entity Object with identity Tactical Booking, User, Event
Value Object Immutable, identity-less object Tactical Money, DateRange, Address
Aggregate Consistency boundary cluster Tactical Booking + items + travelers
Domain Event Record of something that happened Tactical BookingCreated
Repository Persistence access interface Tactical IBookingRepository
Domain Service Cross-entity business logic Tactical PricingService
Application Service Use case orchestrator Tactical CreateBookingHandler
ACL Anti-Corruption Layer Strategic Legacy Payment adapter
CQRS Separate read/write models Tactical Per-service pattern