Overview
jMolecules provides a set of Domain-Driven Design (DDD) annotations to model and structure the domain layer of your application. These annotations help enforce the key building blocks of DDD while making the roles of your entities, aggregates, and other components explicit.
This guide explains each annotation, its constraints, and provides examples to demonstrate their usage.
jMolecules DDD Annotations and Their Constraints
Here’s a table summarizing the allowed and restricted dependencies for each annotation:
Annotation | Must Depend On | Must Not Depend On | Represents |
---|---|---|---|
@AggregateRoot | Domain objects (@Entity , @ValueObject ) | Infrastructure or service layers | The root of an aggregate, responsible for enforcing consistency. |
@Entity | Domain objects (@Entity , @ValueObject , @AggregateRoot ) | Infrastructure or service layers | A mutable object with an identity, part of an aggregate. |
@ValueObject | None (pure logic only) | Mutable state or infrastructure | An immutable object that defines a concept or value in the domain. |
@Repository | @AggregateRoot | Other repositories, services | The abstraction for retrieving and storing aggregates. |
@Service | Domain objects, Repositories | Application or infrastructure logic | A stateless service encapsulating domain-specific operations. |
@Factory | @AggregateRoot , @Entity , @ValueObject | Infrastructure logic | A mechanism for creating complex domain objects. |
@DomainEvent | None (pure event data) | Infrastructure logic | An event representing something of significance in the domain. |
Explanation of Annotations
1. @AggregateRoot
- Definition: Represents the root of an aggregate. It’s the only entry point for manipulating the aggregate’s state.
- Constraints:
- Must Depend On:
@Entity
,@ValueObject
(other domain objects within the aggregate). - Must Not Depend On: Infrastructure code or services.
- Must Depend On:
- Purpose:
- Ensures that all changes within the aggregate are consistent.
- Acts as the single source of truth for its contained entities.
2. @Entity
- Definition: Represents a mutable object with an identity that is part of an aggregate.
- Constraints:
- Must Depend On:
@AggregateRoot
, other@Entity
, or@ValueObject
. - Must Not Depend On: Infrastructure or service layers.
- Must Depend On:
- Purpose:
- Represents a piece of the aggregate that can change over time but is controlled by the aggregate root.
3. @ValueObject
- Definition: Represents an immutable object that models a concept in the domain.
- Constraints:
- Must Depend On: None (should encapsulate pure domain logic).
- Must Not Depend On: Mutable state, infrastructure, or services.
- Purpose:
- Models values like monetary amounts, coordinates, or dates without tracking identity.
4. @Repository
- Definition: Provides an abstraction for persisting and retrieving aggregates.
- Constraints:
- Must Depend On:
@AggregateRoot
. - Must Not Depend On: Other repositories or application services.
- Must Depend On:
- Purpose:
- Hides persistence details and serves as the interface for accessing aggregates.
5. @Service
- Definition: Represents a stateless service encapsulating domain-specific operations.
- Constraints:
- Must Depend On: Domain objects (e.g.,
@Entity
,@ValueObject
,@AggregateRoot
) and@Repository
. - Must Not Depend On: Application services or infrastructure.
- Must Depend On: Domain objects (e.g.,
- Purpose:
- Encapsulates domain logic that doesn’t naturally fit within an entity or value object.
6. @Factory
- Definition: Used for constructing complex domain objects.
- Constraints:
- Must Depend On:
@AggregateRoot
,@Entity
, or@ValueObject
. - Must Not Depend On: Infrastructure code.
- Must Depend On:
- Purpose:
- Handles creation logic that involves multiple steps or collaborators.
7. @DomainEvent
- Definition: Represents a significant occurrence in the domain.
- Constraints:
- Must Depend On: None (self-contained).
- Must Not Depend On: Infrastructure code or mutable state.
- Purpose:
- Communicates changes in the domain to other parts of the system.
Example: E-Commerce Order System
Components in the Domain
-
AggregateRoot:
Order
- The root of the aggregate, ensuring consistency for all order-related data.
-
Entity:
OrderItem
- Represents individual items within an order.
-
ValueObject:
Money
- Encapsulates currency and amount as an immutable concept.
-
Repository:
OrderRepository
- Abstracts persistence for
Order
aggregates.
- Abstracts persistence for
-
Service:
OrderService
- Handles domain-specific operations like calculating the total price of an order.
-
DomainEvent:
OrderPlacedEvent
- Published when an order is placed.
Code Example
AggregateRoot (Order)
Entity (OrderItem)
ValueObject (Money)
Repository (OrderRepository)
Service (OrderService)
DomainEvent (OrderPlacedEvent)
Why These Rules Matter
-
Encapsulation:
- Aggregates enforce consistency by restricting direct access to their internal entities and values.
-
Testability:
- Domain logic remains decoupled from infrastructure, enabling unit tests without external dependencies.
-
Domain-Focused Design:
- The application aligns with the problem domain, improving clarity and maintainability.
Conclusion
jMolecules DDD annotations provide a structured way to implement Domain-Driven Design principles. By adhering to the constraints, you can maintain a clean separation between your domain logic and infrastructure, ensuring a more robust and scalable system.