My plant died from neglect while Grandma's thrived. Learn how reconstituting state from events lets you replay history and understand success.

Growing Marijuana with Event‑Sourcing — Reconstitution

Understanding success through reconstitution

Plant state comparison

After myPlant died, I stared at Grandma's notebook filled with her meticulous event log. Every watering, every trimming—all timestamped, all recorded.

"What if," I thought, "I could replay her events and see exactly how her plant thrived?"

This process of rebuilding state by replaying events is called reconstitution.

Starting the experiment

First, let me load Grandma's complete event stream:

const grandmasPlantEvents: PlantEvent[] = [
  { type: "Seeded", plantId: "grandmasPlant", occured_at: new Date("2023-08-01T10:00:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-02T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-03T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-04T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-05T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-06T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-07T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-08T08:30:00") },
  { type: "Trimmed", plantId: "grandmasPlant", occured_at: new Date("2023-08-09T09:00:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-09T09:15:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-10T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-11T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-12T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-13T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-14T08:30:00") },
  { type: "Trimmed", plantId: "grandmasPlant", occured_at: new Date("2023-08-15T09:00:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-15T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-16T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-17T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-18T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-19T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-20T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-21T08:30:00") },
  { type: "Trimmed", plantId: "grandmasPlant", occured_at: new Date("2023-08-22T09:00:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-22T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-23T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-24T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-25T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-26T08:30:00") },
  { type: "Trimmed", plantId: "grandmasPlant", occured_at: new Date("2023-08-27T09:00:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-27T08:30:00") },
  { type: "Watered", plantId: "grandmasPlant", occured_at: new Date("2023-08-28T08:30:00") },
];

Now I need a way to track the state as I replay Grandma's actions. Let me build a reconstitution function:

interface PlantState {
  id: string;
  isAlive: boolean;
  totalWaterings: number;
  totalTrimCount: number;
}

function reconstitute(events: PlantEvent[]): PlantState {
  const state: PlantState = {
    id: "",
    isAlive: false,
    totalWaterings: 0,
    totalTrimCount: 0
  };

  // Replay each event in order
  for (const event of events) {
    switch (event.type) {
      case "Seeded":
        state.id = event.plantId;
        state.isAlive = true;
        break;

      case "Watered":
        state.totalWaterings += 1;
        break;

      case "Trimmed":
        state.totalTrimCount += 1;
        break;

      case "Died":
        state.isAlive = false;
        break;
    }
  }

  return state;
}

Now I can replay any sequence of events and see what state emerges.

Time travel: comparing different points in time

Now let me compare Grandma's plant at two different points in time—after the first week versus at the end of the month:

const firstWeek = grandmasPlantEvents.slice(0, 8);

console.log(reconstitute(firstWeek));
// {
//   id: "grandmasPlant",
//   isAlive: true,
//   totalWaterings: 7,
//   totalTrimCount: 0
// }
// After 1 week: 7 waterings, 0 trims
// Early growth phase
const fullMonth = grandmasPlantEvents;

console.log(reconstitute(fullMonth));
// {
//   id: "grandmasPlant",
//   isAlive: true,
//   totalWaterings: 27,
//   totalTrimCount: 4
// }
// After 1 month: 27 waterings, 4 trims
// Mature, healthy plant

This is the power of reconstitution: I can "time travel" to any point in Grandma's event stream and see exactly what the plant's state was at that moment. With CRUD, I could only see the final state. With Event Sourcing, I can replay history and understand the complete journey from seedling to mature plant.

Summary

Reconstitution is the process of rebuilding state by replaying events in order:

  1. Start with empty state - No assumptions, just a blank slate
  2. Replay each event - Apply events one by one in chronological order
  3. Build up state - Each event modifies state deterministically
  4. Stop at any point - Can reconstitute state at any moment in history

This enables powerful capabilities that CRUD cannot provide:

In Part 1, we learned that events answer "How did we get here?" In Part 2, we learned that reconstitution answers "What if I could do it again?"

Next: Reconstitution is pure and deterministic—no validation, just state building. But what happens when we want to create new events? How do we prevent invalid operations like watering a dead plant? That's where aggregates and business rules come in.

Comments

Have questions or suggestions? I'd love to hear from you and help improve this content.