🔥 0
0
Lesson 2 of 6 20 min +200 XP

Event Sourcing Basics

What if instead of storing the current state of your bank account ($1,000), you stored every transaction that ever happened? Deposit $500, withdrawal $200, deposit $700...

You could always derive the current balance by replaying the transactions. But more importantly, you'd have a complete audit trail. That's Event Sourcing.

State-Based vs Event-Based

TRADITIONAL: Store Current State

Account: #12345
Balance: $1,000
Updated: 2024-01-15

(What happened? No idea.)

EVENT SOURCING: Store What Happened

AccountOpened  { amount: $0 }
MoneyDeposited { amount: $500 }
MoneyWithdrawn { amount: $200 }
MoneyDeposited { amount: $700 }

Current: $0 + $500 - $200 + $700 = $1,000

Events Are Immutable Facts

Events describe something that happened in the past. They are:

🔒
Immutable

Cannot be changed or deleted

📅
Ordered

Sequence matters for replay

⏮️
Past Tense

OrderPlaced, not PlaceOrder

📦
Self-Contained

All relevant data included

Modeling Domain Events

Events should capture business meaning, not technical changes:

// BAD: Technical, meaningless
interface RowUpdated {
  table: string;
  column: string;
  oldValue: any;
  newValue: any;
}

// GOOD: Business-meaningful events
interface OrderPlaced {
  orderId: string;
  customerId: string;
  items: Array<{ productId: string; quantity: number; price: number }>;
  totalAmount: number;
  placedAt: Date;
}

interface OrderShipped {
  orderId: string;
  trackingNumber: string;
  carrier: string;
  shippedAt: Date;
  estimatedDelivery: Date;
}

interface OrderDelivered {
  orderId: string;
  deliveredAt: Date;
  signedBy: string;
}

The Event Stream

An aggregate (like an Order) has an event stream - the complete history of everything that happened to it:

Order #ORD-123 Event Stream:
─────────────────────────────────────────────────
│ Seq │ Event            │ Data                  │
─────────────────────────────────────────────────
│  1  │ OrderPlaced      │ {items: [...], ...}   │
│  2  │ PaymentReceived  │ {amount: $99.99}      │
│  3  │ OrderShipped     │ {tracking: "1Z999"}   │
│  4  │ OrderDelivered   │ {signedBy: "John"}    │
─────────────────────────────────────────────────

Current State = Apply(event1) → Apply(event2) → Apply(event3) → Apply(event4)

Rebuilding State from Events

interface OrderState {
  id: string;
  status: 'pending' | 'paid' | 'shipped' | 'delivered';
  items: OrderItem[];
  totalAmount: number;
  trackingNumber?: string;
}

function rebuildOrder(events: OrderEvent[]): OrderState {
  // Start with empty state
  let state: OrderState = {
    id: '',
    status: 'pending',
    items: [],
    totalAmount: 0
  };

  // Apply each event in order
  for (const event of events) {
    state = applyEvent(state, event);
  }

  return state;
}

function applyEvent(state: OrderState, event: OrderEvent): OrderState {
  switch (event.type) {
    case 'OrderPlaced':
      return {
        ...state,
        id: event.orderId,
        items: event.items,
        totalAmount: event.totalAmount,
        status: 'pending'
      };

    case 'PaymentReceived':
      return { ...state, status: 'paid' };

    case 'OrderShipped':
      return {
        ...state,
        status: 'shipped',
        trackingNumber: event.trackingNumber
      };

    case 'OrderDelivered':
      return { ...state, status: 'delivered' };

    default:
      return state;
  }
}

Real-World: Accounting Systems

Double-Entry Bookkeeping: The Original Event Sourcing

Accountants figured this out 500 years ago. In double-entry bookkeeping, you never modify a ledger entry - you add correcting entries. Every transaction is recorded, and the current balance is derived by summing all entries. Event Sourcing applies this same principle to software.

Why Event Sourcing?

Benefit Why It Matters
Complete Audit Trail Every change is recorded. Perfect for compliance, debugging, analytics.
Time Travel Rebuild state at any point in time. "What was the order at 3pm yesterday?"
Retroactive Bug Fixes Fix a projection bug, replay events, correct all affected data.
Event-Driven Integration Other services can subscribe to events. Natural fit for microservices.
Multiple Read Models Build different views from the same events. Analytics, search, reporting.

Real-World: Event Sourcing at Scale

Netflix

Uses event sourcing for their billing system. Every subscription change, payment, and plan modification is an event. They can replay history to fix billing issues or generate accurate revenue reports.

Uber

Trip events (request, match, pickup, dropoff, payment) are stored as an event stream. Enables real-time tracking, billing accuracy, and dispute resolution by replaying exact trip history.

The Challenges

Event Sourcing Isn't Free
  • Event Schema Evolution: How do you handle old events when the schema changes?
  • Replay Performance: Rebuilding state from millions of events is slow (solved by snapshots)
  • Event Ordering: Distributed systems make global ordering hard
  • Learning Curve: Teams need to think differently about data

Commands vs Events

Don't confuse them:

COMMAND (Intent to do something)     EVENT (Something that happened)
─────────────────────────────────    ─────────────────────────────────
PlaceOrder                      →    OrderPlaced
CancelOrder                     →    OrderCancelled
ShipOrder                       →    OrderShipped

Commands:                            Events:
- Imperative: "Do this!"             - Past tense: "This happened"
- Can be rejected                    - Already happened, can't reject
- Represents intent                  - Represents fact

Key Takeaways

  • Events are the source of truth - Current state is derived, not stored directly
  • Events are immutable facts - Past tense, self-contained, never modified
  • Rebuild state by replay - Apply events in order to get current state
  • Complete audit trail - Every change is recorded forever

Next up: Projections - Building optimized read models from your event stream.

🧠 Quick Quiz

Test your understanding of this lesson.

1

In Event Sourcing, what is the 'source of truth'?

2

What is the key characteristic of events in Event Sourcing?

3

How do you get the current state of an entity in Event Sourcing?

What is CQRS?