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
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:
- Start with empty state - No assumptions, just a blank slate
- Replay each event - Apply events one by one in chronological order
- Build up state - Each event modifies state deterministically
- Stop at any point - Can reconstitute state at any moment in history
This enables powerful capabilities that CRUD cannot provide:
- Time travel: See what the state was at any point in the past
- Reproducibility: Replay the same events, get the same state every time
- Experimentation: "What if I had done what Grandma did?"
- Debugging: Understand exactly how we reached the current state
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.