The Eternal Ledger

Accountants have known for centuries: don't erase, append. A ledger records every transaction---deposits, withdrawals, transfers. You never delete an entry. If a mistake is made, you add a correction. The history is sacred.

This ancient wisdom has profound implications for how we design systems. What if, instead of storing what is, we stored what happened?

Two Ways to Remember

Consider our chess game. We could remember it in two ways:

The Snapshot: Store the current position.

yaml
    current_state:
        board: [positions of all pieces]
        turn: black
        move_count: 23

The Story: Store what happened.

yaml
    events:
        1. pawn e2 → e4
        2. pawn e7 → e5
        3. knight g1 → f3
        ...
        23. bishop c1 → g5

Both contain the same information---from the events, we can reconstruct any snapshot. But they represent fundamentally different philosophies of memory.

Events as Source of Truth

In event sourcing, we make a radical choice: the events are the source of truth. The current state is merely a derivative---something we compute when we need it.

sql
    source_of_truth:
        events: [event_1, event_2, ..., event_n]
    
    derived (computed when needed):
        current_state = apply_all(events, starting from initial_state)

Why would we do this? Because events have properties that snapshots lack:

Immutable
An event that happened cannot un-happen. pawn e2 → e4 at move 1 is eternal.
Ordered
Events form a sequence. We know what came before and after.
Meaningful
Events carry intent. "Player moved pawn" is richer than "pawn is now at e4."

The Append-Only Log

An event log is append-only. We only add to the end. We never modify or delete.

erlang
    log:
        [event_1]                           // after move 1
        [event_1, event_2]                  // after move 2
        [event_1, event_2, event_3]         // after move 3
        ...

This simplicity has profound consequences:

  1. No lost history --- Every state the system ever had can be reconstructed
  2. Audit trail --- We can always answer "what happened and when?"
  3. Debugging --- When something goes wrong, we can replay to find where

What Makes a Good Event?

Not every change should be an event. Good events are:

Domain-meaningful: They describe something that matters in the problem domain.

python
    // Good: captures intent
    PlayerMovedPiece(player: white, piece: knight, from: g1, to: f3)
    
    // Less good: too low-level
    SquareCleared(square: g1)
    SquareFilled(square: f3, piece: knight)

Complete: They contain everything needed to understand what happened.

haskell
    // Good: self-contained
    PlayerMovedPiece(player: white, piece: knight, from: g1, to: f3, 
                     timestamp: 2024-01-15T10:30:00Z)
    
    // Incomplete: what piece? from where?
    PieceMoved(to: f3)

Past tense: Events describe what did happen, not what should happen.

python
    // Good: fact about the past
    PieceWasMoved(...)
    
    // Not an event: a command (request for future action)
    MovePiece(...)

Commands vs Events

This distinction is crucial:

    Command: MovePiece(knight, g1, f3)
        // A request. Might be rejected if invalid.
        
    Event: PieceWasMoved(knight, g1, f3)
        // A fact. Already happened. Cannot be undone.

The flow is:

python
    1. User issues Command
    2. System validates Command against current state
    3. If valid: system records Event
    4. Event is appended to log (forever)
    5. State is updated (derived from events)

The Eternal Return

In an event-sourced system, nothing is ever truly deleted. The past persists eternally in the log.

python
    // A game from years ago
    game_2847_events:
        1. pawn e2 → e4        // still here
        2. pawn e7 → e5        // still here
        ...                    // all of it, forever

This has philosophical weight. Every decision, every move, every moment---preserved. The system remembers everything.

For some applications, this is exactly right: financial transactions, legal records, medical histories. For others, the right to be forgotten matters. Event sourcing makes forgetting hard by design.

We've stored the story. But how do we read it? In the next chapter, we learn to travel through time---replaying events to reach any moment in history.