advanced 2 min answer

A team proposes CQRS with event sourcing for a new service. How do you evaluate the proposal?

cqrsevent-sourcingcomplexitydecision
Show the full answer Hide the answer

Separate the two, because they are independent decisions

CQRS is separating the write model from the read model. Event sourcing is storing state as a sequence of events rather than as current values. Each is useful without the other, and they are proposed together so often that teams adopt both when they need one or neither.

When CQRS alone is justified

Read and write workloads that differ substantially — very high read volume against modest writes, or queries whose shape has nothing to do with the write model. Multiple read shapes served from one source: a search index, a dashboard aggregate, a denormalised list.

The cost is eventual consistency, and specifically the read-your-own-writes case that surprises users. Mitigations: read from the write side for the acting user, return the new state in the write response, or design the interface to reflect the pending action.

The requirement people skip: projections must be rebuildable, and the rebuild must be tested at production data volume. Eleven hours is a different operational fact from ten minutes. And projection lag must be alerted on, because a stalled projection presents as plausible stale data rather than as an error.

When event sourcing is justified

A genuine need for history as a first-class thing: a regulatory audit trail, temporal queries ("what was the state on this date"), the ability to replay events into new projections, or a domain where the events are the business — accounting, trading, insurance claims.

The costs are large and permanent:

Schema evolution never ends. Events are immutable and must remain readable years later, so upcasters are maintained forever and the chain grows. Semantic changes cannot be upcast at all.

Snapshots become necessary to avoid replaying thousands of events, with their own correctness requirement — always reconstructible from the log.

Querying current state is indirect, which is why event sourcing pulls CQRS along with it.

Deleting data is hard, which collides directly with erasure obligations. Crypto-shredding — encrypting per subject and destroying the key — is the usual answer and must be designed in from the start.

The team must learn a genuinely different model, and the failure mode is a half-understood implementation that is worse than a table.

The evaluation

Ask what specific problem each half solves in this service. If the answer to event sourcing is "audit" and an append-only audit table would do, that is the cheaper answer. If the answer to CQRS is "the reads are slow", a read replica or a materialised view is cheaper.

Then apply the complexity budget: this is one of the largest complexity commitments available, and it is one-way for the data. Adopting it for one aggregate where the case is strong is a far better first step than adopting it service-wide.