Pitfalls checklist (print this)
This is the “you’ll thank yourself later” list.
Event design
- Events are facts (past tense), not requests.
- You can explain each event to a non-technical domain expert.
- Events do not include infrastructure concerns (broker details, DB ids).
- You have a clear event versioning strategy (new types vs upcasters).
Aggregate correctness
- All invariants are enforced inside the aggregate.
-
Apply(...)methods are deterministic and side-effect free. - You never mutate aggregate state without raising an event.
Concurrency
- All appends use expected stream version.
- You have a clear retry policy for concurrency conflicts.
- Commands are idempotent (command id / dedupe) where needed.
Projections
- Projections are idempotent (checkpointing per stream or global position).
- You can rebuild projections from scratch.
- You measure projection lag.
- You have a poison-event strategy (bad schema, unexpected type).
Integration
- You don’t publish domain events “as-is” to other services.
- You use outbox (or equivalent) to avoid write/publish inconsistency.
- Consumers are idempotent (dedupe keys, exactly-once assumptions avoided).
Operations
- You can run mixed versions safely (new readers handle old events).
- You have a documented rebuild/cutover procedure for read models.
- You log correlation/causation ids.
- You’ve considered privacy/security implications (PII, encryption, retention).
If you want one guiding principle
Treat events like public APIs you can never revoke.