Skip to content

Domain-Driven Design

Domain-Driven Design (DDD) keeps business logic at the center of the application. The domain layer expresses the ubiquitous language of the business, independent of technical concerns.

Core Concepts

Entities

Entities are objects with identity that persists over time. Two entities with the same attributes but different identities are distinct.

Value Objects

Value objects are immutable objects defined by their attributes. They are self-validating and use beberlei/assert for validation.

final readonly class ISBN
{
    private function __construct(private string $value)
    {
        $this->validate($this->value);
    }

    public static function fromString(string $value): self
    {
        return new self($value);
    }
}

Domain Events

Events represent significant business occurrences (e.g., BookCreatedEvent, LoanReturnedEvent). See Event-Driven Architecture.

Aggregates

Aggregates are clusters of entities and value objects with a root entity that serves as the entry point.

Repository Pattern

Repositories provide collection-like interfaces for aggregates. Interfaces live in Domain; implementations in Infrastructure.

Domain Exceptions

Domain exceptions represent business rule violations (e.g., InvalidTitleException, InvalidIsbnException).

Key Principles

Immutability and Mutability

Value objects are immutable (readonly classes), ensuring they cannot be modified after creation.

Entities are mutable but encapsulate state changes through behavior methods (markAsBorrowed(), markAsReturned()) rather than exposing setters.

Self-Validating Value Objects

Validation occurs in constructors, ensuring invalid objects cannot exist.

Enums for Domain States

Type-safe enums represent finite domain states:

enum BookStatus: string
{
    case Available = 'available';
    case Borrowed = 'borrowed';
}

Ubiquitous Language

Code reflects business terminology: BorrowBookCommand, ReturnBookCommand, LoanPeriod.

See Also