2024-07-29
#architecture
#ddd
#backend
#patterns
#system-design

DDD: Theoretical Squeeze

Core concepts of Domain-Driven Design: Bounded Contexts, Entities vs Value Objects, Aggregates, and Layered Architecture.

Domain-Driven Design (DDD)

DDD is an architectural approach focused on modeling software to match the complex business domain. It is especially effective for large-scale enterprise applications and microservices.

Core Goals

  1. Align Code with Business: Developers and Domain Experts speak the same language (Ubiquitous Language).
  2. High Cohesion: Related logic stays together.
  3. Low Coupling: Independent modules interact minimally.
  4. Isolation: Encapsulate domain logic from technical details (UI, Database).

Strategic Design

Bounded Context

A semantic boundary within which a particular domain model is defined and applicable. Ideally, one Microservice = one Bounded Context.

Examples:

  • Sales Context: Product (Price, Stock, Discount).
  • Shipping Context: Product (Weight, Dimensions, Fragility). The same term "Product" has different meanings and attributes depending on the context.

Layered Architecture

  1. User Interface (Presentation)

    • Responsible for showing information to the user and interpreting user commands.
    • Example: REST Controllers, Frontend Apps.
  2. Application Layer

    • Coordinates the application activity. Thin layer. It doesn't contain business logic.
    • Example: Service that loads data from DB, calls Domain method, and saves back.
  3. Domain Layer (Business)

    • The Heart of Software. Contains information about the domain.
    • Rules, logic, and business state live here.
    • Strictly isolated: Depends on nothing (pure code).
  4. Infrastructure Layer

    • Supports all other layers.
    • Example: Database persistence (ORM), File System, 3rd party API clients.

Tactical Patterns (Building Blocks)

1. Entity

An object defined by its Identity, not just its attributes.

  • Has ID: Two entities with different IDs are different, even if all other fields are identical.
  • Lifecycle: Can change over time (Mutable).
  • Example: User (id: 1, name: "John"). If John changes his name, he is still User 1.

2. Value Object (VO)

An object defined by its Attributes, not identity.

  • No ID: Identified only by its data.
  • Immutable: Cannot be changed. To "change" it, you create a new instance.
  • Example: Money (amount: 100, currency: USD), Address, Color. Analogy: A $10 bill is a Value Object. You don't care which specific bill it is, only its value.

3. Aggregate & Aggregate Root

A cluster of associated objects (Entities and VOs) that we treat as a unit for data changes.

  • Aggregate Root: The only entity that outside objects are allowed to hold references to.
  • Consistency Boundary: The root ensures all internal rules are satisfied before any change is committed.
  • Example: Order is the Root. OrderItem is an internal entity. You cannot change an Item directly; you must ask the Order to order.addItem(), so the Order can recalculate the total price.

4. Domain Service

Logic that doesn't naturally fit into an Entity or Value Object.

  • Stateless: Performs an operation and returns a result.
  • Example: PaymentProcessor (involves external systems logic or complex calculation across multiple entities).

5. Repository

Abstracts the storage mechanism.

  • acts like a collection of objects in memory.
  • Interface lives in Domain Layer.
  • Implementation lives in Infrastructure Layer.

6. Factory

Encapsulates complex creation logic.

  • Used when creating an object involves complex setup or validation rules.

Architectural Components

Data Transfer Object (DTO)

A simple object used to transfer data between processes (e.g., from Controller to Service).

  • No Behavior: Just fields (getters/setters).
  • Purpose: Decouples the internal Domain Model from the external API contract.

Event Bus / Domain Events

A mechanism to decouple side effects.

  • Event: Something that happened in the past (OrderPlaced).
  • Publisher: Emits the event.
  • Subscriber: Listens and reacts (e.g., Send Email, Update Inventory).
  • Benefit: The "Order" logic doesn't need to know about "Email" logic.

Summary

  1. Model strictly mirrors the Business.
  2. Isolate the Domain from the Infrastructure.
  3. Use Aggregates to guarantee consistency.
  4. Communicate via DTOs and Events.

Connected Thoughts

Egor Zdioruc | Lead Full Stack Developer | Laravel & AI Solutions