Files
gridpilot.gg/docs/architecture/core/CQRS.md
2026-01-11 14:42:54 +01:00

246 lines
4.8 KiB
Markdown

CQRS Light with Clean Architecture
This document defines CQRS Light as a pragmatic, production-ready approach that integrates cleanly with Clean Architecture.
It is intentionally non-dogmatic, avoids event-sourcing overhead, and focuses on clarity, performance, and maintainability.
1. What CQRS Light Is
CQRS Light separates how the system writes data from how it reads data — without changing the core architecture.
Key properties:
• Commands and Queries are separated logically, not infrastructurally
• Same database is allowed
• No event bus required
• No eventual consistency by default
CQRS Light is an optimization, not a foundation.
2. What CQRS Light Is NOT
CQRS Light explicitly does not include:
• Event Sourcing
• Message brokers
• Projections as a hard requirement
• Separate databases
• Microservices
Those can be added later if needed.
3. Why CQRS Light Exists
Without CQRS:
• Reads are forced through domain aggregates
• Aggregates grow unnaturally large
• Reporting logic pollutes the domain
• Performance degrades due to object loading
CQRS Light solves this by allowing:
• Strict domain logic on writes
• Flexible, optimized reads
4. Core Architectural Principle
Writes protect invariants. Reads optimize information access.
Therefore:
• Commands enforce business rules
• Queries are allowed to be pragmatic and denormalized
5. Placement in Clean Architecture
CQRS Light does not introduce new layers.
It reorganizes existing ones.
core/
└── <context>/
└── application/
├── commands/ # Write side (Use Cases)
└── queries/ # Read side (Query Use Cases)
Domain remains unchanged.
6. Command Side (Write Model)
Purpose
• Modify state
• Enforce invariants
• Emit outcomes
Characteristics
• Uses Domain Entities and Value Objects
• Uses Repositories
• Uses Output Ports
• Transactional
Example Structure
core/racing/application/commands/
├── CreateLeagueUseCase.ts
├── ApplyPenaltyUseCase.ts
└── RegisterForRaceUseCase.ts
7. Query Side (Read Model)
Purpose
• Read state
• Aggregate data
• Serve UI efficiently
Characteristics
• No domain entities
• No invariants
• No side effects
• May use SQL/ORM directly
Example Structure
core/racing/application/queries/
├── GetLeagueStandingsQuery.ts
├── GetDashboardOverviewQuery.ts
└── GetDriverStatsQuery.ts
Queries are still Use Cases, just read-only ones.
8. Repositories in CQRS Light
Write Repositories
• Used by command use cases
• Work with domain entities
• Enforce consistency
core/racing/domain/repositories/
└── LeagueRepositoryPort.ts
Read Repositories
• Used by query use cases
• Return flat, optimized data
• Not domain repositories
core/racing/application/ports/
└── LeagueStandingsReadPort.ts
Implementation lives in adapters.
9. Performance Benefits (Why It Matters)
Without CQRS Light
• Aggregate loading
• N+1 queries
• Heavy object graphs
• CPU and memory overhead
With CQRS Light
• Single optimized queries
• Minimal data transfer
• Database does aggregation
• Lower memory footprint
This results in:
• Faster endpoints
• Simpler code
• Easier scaling
10. Testing Strategy
Commands
• Unit tests
• Mock repositories and ports
• Verify output port calls
Queries
• Simple unit tests
• Input → Output verification
• No mocks beyond data source
CQRS Light reduces the need for complex integration tests.
11. When CQRS Light Is a Good Fit
Use CQRS Light when:
• Read complexity is high
• Write logic must stay strict
• Dashboards or analytics exist
• Multiple clients consume the system
Avoid CQRS Light when:
• Application is CRUD-only
• Data volume is small
• Read/write patterns are identical
12. Adoption Rule (Strict)
CQRS Light is a structural rule inside Core.
If CQRS Light is used:
- commands and queries MUST be separated by responsibility
- queries MUST remain read-only and must not enforce invariants
This document does not define a migration plan.
13. Key Rules (Non-Negotiable)
• Commands MUST use the domain
• Queries MUST NOT modify state
• Queries MUST NOT enforce invariants
• Domain MUST NOT depend on queries
• Core remains framework-agnostic
14. Mental Model
Think of CQRS Light as:
One core truth, two access patterns.
The domain defines truth.
Queries define convenience.
15. Final Summary
CQRS Light provides:
• Cleaner domain models
• Faster reads
• Reduced complexity
• Future scalability
Without:
• Infrastructure overhead
• Event sourcing complexity
• Premature optimization
It is the safest way to gain CQRS benefits while staying true to Clean Architecture.