Day 021: Event Sourcing - Events as the Source of Truth (Event sourcing fundamentals)

Day 021: Event Sourcing - Events as the Source of Truth

Topic: Event sourcing fundamentals

πŸ’‘ Today's "Aha!" Moment

The insight: Traditional databases store current state ("balance: $100"). Event Sourcing stores history of changes ("created account, deposited $50, deposited $50"). Current state becomes derived dataβ€”replay events to reconstruct it.

Why this matters:

Most systems throw away history. When you UPDATE a database row, the old value vanishes forever. Questions become impossible to answer:

Event Sourcing keeps everything. Every change is an immutable event:

Events (append-only):
1. AccountCreated { id: 123, owner: "Alice", timestamp: "2024-01-01T10:00:00Z" }
2. MoneyDeposited { id: 123, amount: 50, timestamp: "2024-01-02T14:30:00Z" }
3. MoneyWithdrawn { id: 123, amount: 20, timestamp: "2024-01-03T09:15:00Z" }

Current State (derived by replaying events 1β†’2β†’3):
balance = 0 + 50 - 20 = $30

Want state at any moment? Replay events up to that timestamp. Need audit trail? Events ARE the audit trail. Bug in business logic? Fix code, replay events, correct state.

The pattern: Store facts (events), derive state (projections)

This pattern appears wherever history matters more than current state:

🌟 Why This Matters

Event Sourcing revolutionizes system design by providing perfect audit trails, time travel debugging, and unmatched data integrity. Major companies like Amazon, Netflix, and financial institutions rely on this pattern for critical systems.

🎯 Daily Objective

Master the Event Sourcing pattern: understand how storing events instead of state revolutionizes system design, enables time travel debugging, and provides perfect audit trails. Build a practical event-sourced system from scratch.

πŸ“š Topics Covered

How to recognize Event Sourcing fits:

Use Event Sourcing when: Avoid Event Sourcing when:
Audit trail is legally required Simple CRUD, history irrelevant
Time travel debugging needed Performance-critical reads (millions/sec)
Complex business logic prone to bugs Small app, no regulatory requirements
Multiple projections from same events Team unfamiliar with pattern
Temporal queries ("state at time T") Data never changes (append-only anyway)

Common misconceptions:

❌ Myth: "Event Sourcing means no database"
βœ… Truth: Events are stored in a database (event store). It's append-only database, not stateless.

❌ Myth: "Event Sourcing is always paired with CQRS"
βœ… Truth: They complement each other but are independent. Can use Event Sourcing without CQRS (single model).

❌ Myth: "Replay is too slow for production"
βœ… Truth: Use snapshotsβ€”save state every N events, replay from latest snapshot. Example: Snapshot every 100 events, replay 10-20 events = milliseconds.

Real-world examples:

  1. Banking systems: Every transaction is event (deposit, withdrawal, transfer). Balance derived from transaction history. Regulation requires keeping transactions forever.

  2. GitHub commit history: Each commit is immutable event. Current repo state = replay all commits. Time travel via git checkout <commit>.

  3. Apache Kafka: Log-based architecture. Topics store events forever (or until retention), consumers replay to rebuild state.

  4. Event Store DB: Purpose-built database for Event Sourcing (created by Greg Young). Optimized for append-only writes, fast event replay.

  5. AWS EventBridge: Event-driven architecture. Services publish events, other services subscribe. Events stored for replay.

  6. Airline booking: Reservation events (SeatReserved, PaymentReceived, TicketIssued). Can reconstruct exact booking flow, handle disputes.

What changes after this realization:

You stop thinking "CRUD" (Create, Read, Update, Delete). You start thinking "What happened?" instead of "What is?"

You recognize events as first-class citizens:

You understand trade-offs:

You learn event schema design:

// ❌ Bad event (imperative, no context)
{ type: "UPDATE", field: "balance", value: 100 }

// βœ… Good event (declarative, business meaningful)
{
  type: "MoneyDeposited",
  accountId: "123",
  amount: 50,
  depositedBy: "ATM_456",
  timestamp: "2024-01-02T14:30:00Z",
  reason: "Salary payment"
}

Good events are:

  1. Past tense (MoneyDeposited, not DepositMoney)
  2. Business meaningful (not technical)
  3. Immutable (never modified after creation)
  4. Self-contained (all info to process)

Meta-insight:

Event Sourcing inverts database philosophy. Traditional DB: State is truth, changes are side effects. Event Sourcing: Changes are truth, state is side effect.

This mirrors how humans think about stories:

The deepest lesson: Time is fundamental to reality. Physics records events (spacetime), not states. Causality flows through events. Event Sourcing acknowledges that systems exist in timeβ€”every state has a history, every decision has a cause.

By storing the timeline instead of a snapshot, we preserve the truth about what actually happened. Current state is an opinion (derived from events). Events are facts.

πŸ“– Detailed Curriculum (Optimized for 60 min)

  1. Video Introduction (15 min) ⭐ START HERE

  2. Greg Young: "Event Sourcing" (CQRS/DDD Europe)

  3. Video Link
  4. Core concepts and motivation

  5. Core Reading (15 min)

  6. Martin Fowler: "Event Sourcing"

  7. Article
  8. Focus: Pattern description, benefits, and when to use

  9. Quick Synthesis (5 min)

  10. Write: "Event Sourcing in 3 key ideas"
  11. Draw simple event store diagram
  12. Note biggest insight

πŸ“‘ Resources

🎯 Core Resources (Use Today)

⭐ Bonus Resources (If Extra Time)

✍️ Practical Activities (25 min total)

1. Build Simple Event Store (15 min)

Implement a basic event-sourced bank account in pseudocode/your language:

// Events
AccountCreated { accountId, ownerId, timestamp }
MoneyDeposited { accountId, amount, timestamp }
MoneyWithdrawn { accountId, amount, timestamp }

// Event Store
class EventStore {
    events = []

    append(event) {
        events.push(event)
    }

    getEvents(accountId) {
        return events.filter(e => e.accountId == accountId)
    }
}

// Account (reconstructed from events)
class Account {
    id, balance = 0

    static fromEvents(events) {
        account = new Account()
        for event in events {
            account.apply(event)
        }
        return account
    }

    apply(event) {
        match event {
            AccountCreated => this.id = event.accountId
            MoneyDeposited => this.balance += event.amount
            MoneyWithdrawn => this.balance -= event.amount
        }
    }
}

Tasks:

2. Event Diagram (7 min)

Draw a sequence diagram showing:

User β†’ Command β†’ Event Store β†’ Event β†’ Read Model
                     ↓
                  Event 1, 2, 3...
                     ↓
                  Replay β†’ Current State

3. Reflection (3 min)

Answer:

🎨 Creativity - Quick Mental Reset (5 min)

Quick Exercise: "The Event Timeline"

Draw a visual timeline of your day as events:

Purpose: Experience thinking in events vs state!

Take 3 min to draw, 2 min to reflect on the difference between storing "CurrentState" vs "EventHistory"

πŸ”— Connections to Previous Learning

From Month 1:

Building Forward:

βœ… Daily Deliverables (Must Complete)

⭐ Bonus (If Extra Time)

🎯 Success Criteria

By the end of today, you should be able to:

  1. βœ… Explain what event sourcing is and why it's useful
  2. βœ… Describe the difference between events and state
  3. βœ… Implement a simple event store
  4. βœ… Reconstruct state from event history
  5. βœ… Identify when event sourcing is appropriate
  6. βœ… Understand event sourcing trade-offs

⏰ Total Estimated Time (OPTIMIZED)

Note: Focus on understanding over perfection. A simple working event store that demonstrates the core concept is excellent for day 1!


πŸ“ Today's Big Ideas

  1. Events Are Facts: They never change, only accumulate
  2. State Is Derived: Current state = replay all events
  3. Time Travel: You can reconstruct any past state
  4. Audit Trail: Perfect history of what happened when
  5. Flexibility: Multiple read models from same events

πŸš€ Tomorrow's Preview

CQRS: Command Query Responsibility Segregation

You'll discover how separating writes (commands) from reads (queries) enables incredible scalability and flexibility. Event Sourcing + CQRS = πŸ”₯


"In event sourcing, the events are the source of truth, not the current state." - Greg Young

You're building production-grade patterns! πŸ’ͺ



← Back to Learning