Domain-Driven Design: The Core Trio

shield Aggregate Root

The "Manager" of a consistency boundary. It is an Entity that binds together other entities (like an Order holding OrderItems). It guards the data integrity; outside objects can only modify the internal state through the Root's specific methods, never directly.

hub Domain Service

The "Operator" of complex logic. When a business rule doesn't fit naturally into a single Entity (e.g., "Transfer funds from Account A to Account B"), this stateless service coordinates the logic. It speaks the business language strictly.

settings_ethernet Infrastructure Service

The "Plumber" or delivery mechanism. It implements an interface defined in the domain to talk to the outside world (sending emails, saving files, calling 3rd party APIs). It handles the *technical* "how", not the *business* "what".

Consistency Boundary

The Gatekeeper

Think of an Aggregate Root as a Store Manager holding the keys to the inventory room.

Customers (external objects) cannot walk into the back room and take an item (internal entity) directly. They must go through the Manager. This ensures the inventory count is always correct and no rules are broken (e.g., "You can't buy an item that is reserved").

  • check_circle
    Global Identity: It's the only object you can look up directly by ID from a repository.
  • check_circle
    Transactional: Changes to the aggregate are saved as one atomic transaction.
  • check_circle
    Encapsulation: It forbids external access to its internal children.
Aggregate Root Analogy
Interactive Code
class Order { // Aggregate Root
private items: OrderItem[];
Private! No one can touch this list directly.
private status: 'DRAFT' | 'PAID';
State is protected.
public addItem(product, quantity) {
Public API: The only way to change state.
if (this.status === 'PAID') throw Error(...);
Invariant Check: The Manager enforcing rules.
this.items.push(new OrderItem(product, quantity));
}
}
Pure Business Logic

The Facilitator

Think of a Domain Service as a Marriage Officiant.

A marriage involves two people (Entities), but the act of marrying them isn't a method on the Groom or the Bride. It's a process that involves both but belongs to neither. The Officiant (Service) performs the ceremony according to the laws (Business Rules).

  • check_circle
    Stateless: It doesn't hold data; it performs an action.
  • check_circle
    Cross-Cutting: Perfect for logic involving multiple Aggregate Roots.
  • check_circle
    Ubiquitous Language: The service name comes from the business (e.g., "FundsTransfer"), not tech.
Domain Service Analogy
Interactive Code
class FundsTransferService {
public transfer(fromAccount, toAccount, amount) {
Orchestrates interaction between TWO aggregates.
// Business Logic not belonging to one account
if (!fromAccount.canWithdraw(amount)) throw ...;
Validation using Entity methods.
fromAccount.withdraw(amount);
toAccount.deposit(amount);
}
}
Technical Implementation

The Delivery System

Think of an Infrastructure Service as the Postal System.

You write the letter (Domain content), but you rely on the Postal Service (Infrastructure) to physically move it. The Postal Service doesn't care about the emotional content of your letter; it only cares about the address and the transport.

  • check_circle
    Dependency Inversion: The Interface lives in the Domain (e.g., `IEmailSender`), but the Implementation lives in Infrastructure.
  • check_circle
    External World: Talks to DBs, APIs, File Systems, Hardware.
  • check_circle
    Replaceable: You can swap `SmtpEmailSender` for `MockEmailSender` without changing business rules.
Infrastructure Service Analogy
Interactive Code
class SmtpEmailSender implements IEmailSender {
private smtpClient: SmtpClient;
Specific 3rd party library usage.
public async send(to, subject, body) {
Implements the contract defined in the Domain.
// Technical implementation details
await this.smtpClient.connect(...);
await this.smtpClient.sendMessage(...);
}
}

Architect's Challenge

Where does this responsibility belong? Test your knowledge.

We need to verify that an Order does not exceed the Customer's credit limit. The credit limit is on the Customer entity, the total is on the Order entity.

Quick Comparison

Feature Aggregate Root Domain Service Infrastructure Service
Main Goal Protect integrity of state Execute logic spanning entities Communicate with external systems
State Stateful Stateless Stateless
Dependencies Other entities, Value Objects Entities, Repositories (Interfaces) External Drivers, SDKs, DBs
Layer Domain Layer Domain Layer Infrastructure Layer