0002 — Not event sourcing, not CQRS
State is never derived from events; one model, not separate read and write models.
Decided. State is never derived from events. There is one model, not a write model and a read model.
The accurate name for what we are doing: state-stored services with a transactional outbox. Event-driven, not event-sourced.
Why not event sourcing
The log stops being the record (see 0001), so replay no longer reconstructs state. Keeping event-sourcing machinery on top of an authoritative database gives you the costs — unbounded replay on write, snapshot management, stream-sequence concurrency control — with none of the benefit.
Why not CQRS
CQRS means a separate model for writes and reads, connected asynchronously. That buys read scaling and shape freedom at the cost of a staleness window, a second store, and a divergence question during every incident.
We do not need it. Where a wide denormalized read shape is useful, it is a view, a materialized view refreshed in the writing transaction, or a trigger-maintained table — in the same database. One source of truth, synchronously consistent, no lag.
Command/query separation at the handler level is fine and normal. That is not CQRS; it is organised code.
What we keep from the event-driven world
- A durable, ordered, replayable event log per service (the outbox table).
- Curated domain events as the integration contract.
- Consumers building whatever projections they want from it.
Consequences
- Replay is for consumers, not for us.
- Emission completeness becomes a discipline: a state change that forgets its event row is a bug the database cannot catch. Hence the conformance check that every state change has a matching event row in the same transaction.