Domain Driven Design
Introduction
Love theory and try to stick to something where a pattern exists so I thought a page on this might not go a miss
Domain-Driven Design (DDD) Building Blocks
A consolidated reference for the core conceptual building blocks used in Domain-Driven Design. These patterns form the vocabulary of a rich domain model and guide how business logic is structured.
1. Value Object
Definition
A Value Object represents a concept in the domain that is defined entirely by its data.
Characteristics
Identity by value
Immutable
No lifecycle
Owned by an Entity
No identity key
Examples
Money
Address
DateRange
Coordinates
Notes
Use Value Objects to express meaning and enforce invariants.
2. Entity
Definition
An Entity represents something in the domain with a unique identity that persists over time.
Characteristics
Identity by ID
Mutable
Has a lifecycle
Can contain Value Objects
Examples
User
Order
Pizza
Notes
Entities model things that exist and change.
3. Aggregate
Definition
A cluster of Entities and Value Objects that form a consistency boundary.
Characteristics
Has a single Aggregate Root
Enforces invariants
Only the root is accessed from outside
Treated as a single unit
Examples
Order (root) with OrderLines
Cart (root) with CartItems
Notes
Aggregates define transactional boundaries.
4. Domain Service
Definition
A stateless operation that belongs to the domain but not to any specific Entity or Value Object.
Characteristics
Pure behaviour
No state
Encapsulates domain logic that does not fit elsewhere
Examples
PaymentProcessor
PricingCalculator
Notes
Use Domain Services sparingly and only when behaviour cannot live in an Entity or Value Object.
Explanation of Layer Placement
Domain Services live in the Domain Layer (Business Logic) because they encapsulate domain-specific behavior that does not naturally belong to any single Entity or Value Object. They focus purely on domain rules and operations without managing state or infrastructure concerns.
Why Not Application or Infrastructure Services?
Application Services coordinate workflows and manage transactions but contain little or no domain logic themselves. They live in the Application Layer.
Infrastructure Services provide technical capabilities like persistence, messaging, or external system integration and live in the Infrastructure Layer.
Example Clarifications
PaymentProcessor is a Domain Service because it encapsulates domain rules for processing payments, which involves domain logic beyond simple data storage or retrieval.
PricingCalculator is a Domain Service because it calculates prices based on business rules and discounts, which is domain behavior, not just application orchestration or infrastructure tasks.
5. Domain Event
Definition
A record of something meaningful that happened in the domain.
Characteristics
Immutable
Named in the past tense
Handled by domain or application logic
Examples
OrderPlaced
UserRegistered
Notes
Domain Events capture facts the system cares about.
6. Repository
Definition
An abstraction for retrieving and persisting Aggregates.
Characteristics
Works with Aggregate Roots
Hides persistence details
Returns domain objects
Examples
IOrderRepository
ICustomerRepository
Notes
Repositories provide a collection-like interface for Aggregates.
7. Factory
Definition
A pattern for creating complex domain objects or Aggregates.
Characteristics
Encapsulates creation logic
Ensures invariants are satisfied at creation time
Examples
OrderFactory
UserFactory
Notes
Use when creation requires more than simple construction.
8. Specification
Definition
A reusable, composable way to express business rules or filtering logic.
Characteristics
Encapsulates a predicate
Can be combined (AND, OR, NOT)
Often used for querying
Examples
OrdersPlacedInLast30Days
CustomersWithOverdueInvoices
Notes
Specifications help keep logic reusable and expressive.
Summary Table
| Concept | Identity | Mutable | Purpose | Example |
|---|---|---|---|---|
| Value Object | By value | No | Represent meaning | Money Additional details can be added here. |
| Entity | By ID | Yes | Represent things that exist | Order Includes unique identity. |
| Aggregate | Root ID | Yes | Consistency boundary | Order + OrderLines Defines transactional boundaries. |
| Domain Service | None | No | Behaviour without identity | PricingCalculator Stateless operations. |
| Domain Event | N/A | No | Record of something that happened | OrderPlaced Immutable facts. |
| Repository | N/A | N/A | Persistence abstraction | IOrderRepository Collection-like interface. |
| Factory | N/A | N/A | Controlled creation | OrderFactory Encapsulates creation logic. |
| Specification | N/A | N/A | Business rule expression | OrdersPlacedInLast30Days Reusable predicates. |
9. Invariants
Definition
Invariants are rules or conditions that always stay true and never change, no matter what happens in the system. They are like promises or guarantees that certain things will remain constant throughout the life of an object or process.
Explanation
Think of invariants as safety rules that keep your system reliable and consistent. They ensure that the system's state is always valid.
Examples
A bank account balance can never be negative.
An order must always have at least one order line.
A user’s email address must be unique in the system.
The total quantity of items in a shopping cart cannot be less than zero.
A product’s price must always be greater than zero.
Notes
Invariants help maintain correctness and prevent errors by enforcing essential business rules consistently.
10. Example Project Structure
Overview
This example project structure demonstrates a practical organization of a Domain-Driven Design system implemented using Clean Architecture principles. It separates concerns into layers and organizes code for clarity, maintainability, and scalability.
Project Structure Example
An example of project structure can be found own repos https://git.bibble.co.nz/bibble235/dvdrental_api_cs
Notes
The Api project contains presentation and interface concerns such as HTTP endpoints, middleware, filters, and API documentation (Swagger).
The Application project contains application logic including services, DTOs, validation, and request/response models. It orchestrates domain objects but contains minimal business logic.
The Domain project contains the core business model including entities, value objects, domain interfaces, and domain rules.
The Infrastructure project contains technical implementations such as persistence, caching, security, and external integrations.
The Shared project contains reusable utilities, extensions, enums, and configuration attributes shared across layers.
This structure aligns well with Clean Architecture principles by clearly separating concerns and dependencies between layers.=== Overview ===
Clean Architecture is a software design approach that organizes code into layers with clear responsibilities, promoting maintainability, scalability, and testability.
Layers in Clean Architecture
Domain Layer: Contains the business logic and domain model, including Entities, Value Objects, Aggregates, Domain Services, Domain Events, Specifications, and Factories.
Application Layer: Coordinates application workflows and use cases, orchestrating domain objects and managing transactions.
Infrastructure Layer: Handles technical concerns like data persistence, messaging, external APIs, and other system integrations.
Presentation Layer: Manages user interfaces and user interactions.
Converting Design to Implementation
When converting a Domain-Driven Design into a working system using Clean Architecture:
Start by modeling the domain layer with Entities, Value Objects, Aggregates, and Domain Services that encapsulate business rules.
Define Application Services to coordinate use cases and workflows without embedding business logic.
Implement Infrastructure Services to provide technical capabilities, keeping them separate from domain logic.
Use Dependency Inversion to ensure that the domain layer is independent of infrastructure and frameworks.
Why This Matters
This separation ensures that business rules remain pure and unaffected by external changes, making the system easier to maintain and evolve.
Example
A PricingCalculator Domain Service lives in the Domain Layer because it encapsulates business rules for price calculation.
An OrderApplicationService in the Application Layer coordinates placing an order by calling domain objects and managing transactions.
A PaymentGateway in the Infrastructure Layer handles communication with external payment providers.