4.8 KiB
Domain Objects Design Guide (Clean Architecture)
This document defines all domain object types used in the Core and assigns strict responsibilities and boundaries.
Its goal is to remove ambiguity between: • Entities • Value Objects • Aggregate Roots • Domain Services • Domain Events
The rules in this document are non-negotiable.
⸻
Core Principle
Domain objects represent business truth.
They: • outlive APIs and UIs • must remain stable over time • must not depend on technical details
If a class answers a business question, it belongs here.
⸻
- Entities
Definition
An Entity is a domain object that: • has a stable identity • changes over time • represents a business concept
Identity matters more than attributes.
⸻
Responsibilities
Entities MUST: • own their identity • enforce invariants on state changes • expose behavior, not setters
Entities MUST NOT: • depend on DTOs or transport models • access repositories or services • perform IO • know about frameworks
⸻
Creation Rules • New entities are created via create() • Existing entities are reconstructed via rehydrate()
core//domain/entities/
⸻
Example • League • Season • Race • Driver
⸻
- Value Objects
Definition
A Value Object is a domain object that: • has no identity • is immutable • is defined by its value
⸻
Responsibilities
Value Objects MUST: • validate their own invariants • be immutable • be comparable by value
Value Objects MUST NOT:
• contain business workflows
• reference entities
• perform IO
• contain presentation or formatting logic (e.g., formatForDisplay())
⸻
Domain vs. Presentation Value Objects
It is critical to distinguish between Domain Value Objects and Presentation Value Objects (Displays):
- Domain Value Objects (Core): Protect business meaning and invariants. They are pure and know nothing about how data is shown to users.
- Display Objects (Website): Protect presentation logic and formatting. They are used by the Website (both server and client) to ensure consistent display.
If the API needs to return formatted strings, this logic belongs in API Presenters, not in Domain Value Objects.
Creation Rules • create() for new domain meaning • fromX() for interpreting external formats
core//domain/value-objects/
⸻
Example • Money • LeagueName • RaceTimeOfDay • SeasonSchedule
⸻
- Aggregate Roots
Definition
An Aggregate Root is an entity that: • acts as the consistency boundary • protects invariants across related entities
All access to the aggregate happens through the root.
⸻
Responsibilities
Aggregate Roots MUST: • enforce consistency rules • control modifications of child entities
Aggregate Roots MUST NOT: • expose internal collections directly • allow partial updates bypassing rules
⸻
Example • League (root) • Season (root)
⸻
- Domain Services
Definition
A Domain Service encapsulates domain logic that: • does not naturally belong to a single entity • involves multiple domain objects
⸻
Responsibilities
Domain Services MAY: • coordinate entities • calculate derived domain values
Domain Services MUST: • operate only on domain types • remain stateless
Domain Services MUST NOT: • access repositories • orchestrate use cases • perform IO
core//domain/services/
⸻
Example • SeasonConfigurationFactory • ChampionshipAggregator • StrengthOfFieldCalculator
⸻
- Domain Events
Definition
A Domain Event represents something that: • has already happened • is important to the business
⸻
Responsibilities
Domain Events MUST: • be immutable • carry minimal information
Domain Events MUST NOT: • contain behavior • perform side effects
core//domain/events/
⸻
Example • RaceCompleted • SeasonActivated
⸻
- What Does NOT Belong in Domain Objects
❌ DTOs ❌ API Models ❌ View Models ❌ Repositories ❌ Framework Types ❌ Logging ❌ Configuration
If it depends on infrastructure, it does not belong here.
⸻
- Dependency Rules
Entities → Value Objects Entities → Domain Services Domain Services → Entities
Reverse dependencies are forbidden.
⸻
- Testing Requirements
Domain Objects MUST: • have unit tests for invariants • be tested without mocks
Domain Services MUST: • have deterministic tests
⸻
Mental Model (Final)
Entities protect state. Value Objects protect meaning. Aggregate Roots protect consistency. Domain Services protect cross-entity rules. Domain Events describe facts.
⸻
Final Summary • Domain objects represent business truth • They are pure and framework-free • They form the most stable part of the system
If domain objects are clean, everything else becomes easier.