Event Sourcing System Design
Event sourcing as append-only state, replay, projections, and audit history.
Event sourcing changes more than storage. It changes how the whole system thinks about truth, state, and time. In a CRUD system, the database row is the current fact. In an event-sourced system, the source of truth is an append-only stream of domain events, and current state is derived by replaying those events.
That shift starts at the write model. Instead of issuing an update such as set order status to paid, the application handles a command, checks business rules against the current aggregate state, and emits an event such as PaymentCaptured. The write path becomes a validator and historian rather than a row mutator. This is valuable when the journey matters as much as the destination, because the system keeps every meaningful state transition.
Read design changes too. Querying an event stream directly is usually inconvenient for user-facing features, so event-sourced systems build projections or read models. A projection subscribes to events and updates a view optimised for one purpose, such as order history, billing summary, or fraud analysis. That gives fast, purpose-built reads, but it introduces eventual consistency. A command may succeed before every projection has caught up.
The benefits are compelling in the right domain. Auditability is built in. Temporal debugging becomes possible because you can ask not only what the state is now, but how it became that way. New views can be created later by replaying historical events into a new projection without changing the original source of truth. Complex workflows also become easier to model when state transitions are explicit domain facts.
The costs are equally real. Event schemas are durable contracts and must evolve carefully. Corrections are not simple updates; they are new events that compensate, supersede, or annotate earlier ones. Deleting data can become tricky in regulated environments because immutable history may conflict with erasure requirements. Snapshots are often needed so aggregates do not replay unbounded history on every command.
Operational complexity rises as well. Projection lag must be monitored. Replays must be safe and idempotent. Ordering guarantees matter, especially when several consumers depend on the same event stream. If events are published externally, teams also need to separate internal domain events from stable integration events so they do not freeze their internal model accidentally.
Event sourcing is therefore not just "CRUD plus an audit log". It is a different architectural commitment. It works best when business history, traceability, and complex domain behaviour justify the extra machinery. Examples include finance, ledgers, booking systems, workflow engines, and domains where reversal and explanation matter.
If the domain is mostly simple records with straightforward updates and little need for replay, ordinary state storage is usually cheaper and easier to operate. The key difference in system design is not whether events exist. It is whether events themselves are the durable business truth around which writes, reads, recovery, and integration are all organised.