Domain-Driven Design (DDD) is a methodology and set of patterns for developing software that's focused on the business domain, its logic, and complexities. Eric Evans introduced it in his book, "Domain-Driven Design: Tackling Complexity in the Heart of Software". DDD can be quite dense, so here's a broad overview of its main ideas, patterns, and associated practices:
- Ubiquitous Language: A shared language between developers and domain experts. It's used within a bounded context to ensure that all parties have a consistent understanding of terms and concepts.
- Bounded Context: Represents limits where specific terms, concepts, and models are defined. It's essentially a boundary within which a specific domain model is applicable.
- Entity: An object with a distinct identity that runs through time and different states. Examples: User, Product, Order.
- Value Object: An immutable object that has no identity and is only defined by its attributes. Examples: Color, Address, Money.
- Aggregate: A cluster of domain objects (entities and value objects) that are treated as a single unit for data changes. Each aggregate has a root, which is an entity through which all external interactions with the aggregate occur.
- Domain Event: Represents something significant that happened in the domain. It's a state change that can trigger other domain actions or side effects.
- Service: When an operation doesn't conceptually belong to an entity or value object, it can be defined as a domain service.
- Repository: Provides methods to retrieve and store aggregates. It abstracts the storage mechanism, presenting a collection-like interface for accessing domain objects.
- Factory: Responsible for creating complex domain objects or aggregates. It encapsulates the logic of object creation.
- Context Mapping: Identifying and mapping different bounded contexts and their relationships with each other. Contexts can have relationships like:
- Upstream/Downstream: When one context produces data/concepts that another depends on.
- Shared Kernel: When two contexts share a subset of the domain model.
- Customer/Supplier: When one context (customer) depends on another (supplier) to fulfill its needs.
- Conformist: When one context conforms to another's model without critical integration.
- Anticorruption Layer: A layer that translates between two bounded contexts, ensuring that one context's model doesn't corrupt the other.
- Separate Ways: When two contexts have no integration and evolve separately.
- Open Host Service: Providing a well-defined and stable API to other bounded contexts.
- Distillation: The process of identifying the core domain (most crucial parts of the business logic) and separating it from generic subdomains.
- Large-Scale Structures: As systems grow, additional structural patterns (like Layers, Hexagonal Architecture, or Clean Architecture) can be applied to manage complexity.
- Event Storming: A workshop-based practice where developers and domain experts collaboratively explore domain events, aggregates, and bounded contexts using sticky notes on a board.
- Event Sourcing: Storing every state change in the system as a series of events. This allows for rebuilding the state at any point in time and can simplify certain complex domains.
- CQRS (Command Query Responsibility Segregation): A pattern where the data write model (Commands) is separated from the read model (Queries). This allows for flexibility in scaling and can align well with event-sourced systems.
- Microservices: Architectural style where systems are broken into small, independently deployable services. Bounded contexts in DDD often align well with microservices.
- TDD (Test-Driven Development) and BDD (Behavior-Driven Development): Techniques that emphasize writing tests first and can help validate and refine the domain model.