Glossary Architecture Patterns

Event Sourcing

An architectural pattern where application state is derived by replaying an append-only log of events rather than storing and mutating current state directly.

The Problem with Mutable State

When you store only current state, you lose history. A bank account table has a balance column. When a transfer occurs, you update the balance. The previous balance is gone. If you need to answer "what was this account's balance on March 3rd?" you cannot. If you need to know why the balance changed, you cannot. If a bug corrupted balances and you want to recompute them from scratch, you have no source of truth to replay. Audit trails require separate logging tables bolted on as an afterthought, and they frequently diverge from actual state.

Event sourcing addresses this by inverting the storage model: instead of storing current state and losing the history that produced it, store the history and derive the current state from it.

How It Works

Every state change is recorded as an immutable event appended to a log. For a bank account: AccountOpened, MoneyDeposited{amount: 500}, MoneyWithdrawn{amount: 200}, MoneyTransferred{to: "acc-456", amount: 100}. The current balance (200) is not stored anywhere. It is computed by replaying the event sequence. The event log is the source of truth.

Events are immutable. You never update or delete events. If a transaction was recorded in error, you append a compensating event (TransactionReversed) rather than modifying history.

Snapshots

Replaying the full event log on every read is impractical for long-lived aggregates. An account with 10 years of daily transactions might have 5,000 events. The solution is periodic snapshots: at regular intervals (every 500 events, for example), persist the computed current state as a snapshot. On read, load the most recent snapshot and replay only the events that occurred after it. Snapshot strategy is an operational decision balancing read latency against snapshot storage cost.

Projections

The event log is the write model. For reads, you build projections: separate read models optimized for specific query patterns. A AccountSummaryProjection might maintain a table of current balances per account. A MonthlyStatementProjection maintains transaction history grouped by month. Projections consume the event stream and maintain their own state asynchronously. This makes event sourcing naturally pair with CQRS.

Consistency Trade-off

Projections are eventually consistent with the event log. There is a window (typically milliseconds to seconds) between when an event is written and when all projections reflect it. Systems using event sourcing must be designed to tolerate this. Read-your-own-writes guarantees require reading directly from the event log for the requesting user's own operations, or using techniques like causality tokens.

Event Schema Evolution

Events are immutable but systems evolve. An event recorded in 2020 with a UserRegistered schema that lacked a referral_source field must still replay correctly in 2025 after the field was added. Schema versioning strategies: upcasting (transform old events to the current schema at read time), version tagging in the event payload, or maintaining separate event handlers per version. This is an ongoing operational concern that naive adopters of event sourcing underestimate. A system with 5 years of event history may need to handle 10 schema versions for a single event type.

When to Use It

Event sourcing is appropriate when: you need a complete audit trail (financial systems, healthcare, compliance-heavy domains), your domain has complex state transitions where history matters, you need to support temporal queries (state at a point in time), or you need to rebuild read models after discovering a projection bug.

It is inappropriate for: simple CRUD applications where history has no business value, high-frequency state updates (IoT sensor data at 10,000 writes per second) where storage cost grows prohibitively, or teams without experience managing the operational complexity of event logs, projection rebuilds, and schema evolution across years of history.

Interview Tip

The question that probes depth: "How do you handle a projection that has a bug in its event handler?" The expected answer: you fix the handler and rebuild the projection by replaying the event log from the beginning. This is the key property that makes event sourcing worth its complexity. The follow-up question: "How long does a rebuild take for 50M events?" Forces the candidate to think about snapshot strategy, parallel replay, and whether the projection rebuild can be done without downtime (it can, using blue-green projection deployment where the new projection is built in the background and swapped atomically once caught up). Candidates who mention only the happy path (events flow, projections update) have not operated an event-sourced system in production.