Event Sourcing: When History Matters More Than State
I deleted a user's order. Not intentionally. A bug in our payment processing system overwrote the order state. The customer called, furious. "Where's my order?" I had no idea. The database showed nothing. The logs showed nothing useful. We lost the history.
That's when event sourcing clicked for me.
Most systems store current state. You update a row. The old value disappears. History is gone. Event sourcing flips this. Instead of storing what something is, you store what happened to it. Every change becomes an immutable event in an append-only log.
What Event Sourcing Actually Is
Event sourcing means storing all changes to application state as a sequence of events. Instead of updating a record, you append an event. The current state is computed by replaying events from the beginning.
Think about a bank account. Traditional approach: balance is 1000. Someone withdraws 200. You update balance to 800. The 1000 is gone. The 200 withdrawal is gone. You only know the current state.
Event sourcing: AccountCreated with initial balance 1000. WithdrawalRequested for 200. WithdrawalCompleted for 200. The current balance is 800, but you have the full history. You can see every transaction. You can rebuild state at any point in time.
This isn't just about audit trails. It's about building systems that don't lose information.
Why This Matters in Production
I've seen too many systems lose critical information. A payment gets processed twice. The database shows one payment. The logs are rotated. You can't prove what happened. You can't debug the issue. You can't fix it properly.
Event sourcing solves this by making history the source of truth. Events are immutable. Once written, they don't change. You can replay them to rebuild state. You can query them to understand what happened. You can use them to debug production issues.
At MADE.com, we use Event Store for messaging between services. But event sourcing goes deeper. It's not just about messaging. It's about how you model your domain.
The Append-Only Log
The core of event sourcing is the append-only log. Events are written sequentially. They're never updated. They're never deleted. They're just appended.
This sounds simple. It is. But it changes everything about how you think about data.
Traditional databases are optimized for updates. You read a row. You modify it. You write it back. The database handles concurrency. It handles transactions. It's built for mutable state.
Event stores are optimized for appends. You write events. You read events. You don't update them. You don't delete them. This makes them fast. This makes them reliable. This makes them simple.
But it also means you can't just query for current state. You need to build read models. You need to project events into views. This is where CQRS comes in.
Event Sourcing and CQRS
Command-Query Responsibility Segregation separates reads from writes. You write to one model. You read from another. They're optimized for different things.
With event sourcing, your write model is the event log. Commands create events. Events are appended. That's it. Simple. Fast. Reliable.
Your read models are projections. Events flow through handlers. Handlers update views. Views are optimized for queries. They're denormalized. They're fast. They can be rebuilt from events.
This separation is powerful. Your write model stays simple. Your read models can be complex. They can be optimized for different queries. They can be rebuilt when you need to change them.
But it's also more complex. You have two models to maintain. You have eventual consistency to deal with. You have projection failures to handle.
The Trade-Offs
Event sourcing isn't free. It comes with costs.
First, storage. You're storing every change. Not just current state. Everything. This can grow large. You need strategies for archiving. You need strategies for snapshots.
Second, complexity. You need to build read models. You need to handle projection failures. You need to deal with eventual consistency. You need to version your events.
Third, learning curve. Your team needs to understand events. They need to understand projections. They need to understand replay. This takes time.
But the benefits are real. You get complete history. You get auditability. You get the ability to rebuild state. You get the ability to query history. You get the ability to debug production issues.
The question isn't whether event sourcing is good or bad. It's whether the benefits outweigh the costs for your use case.
When Event Sourcing Makes Sense
Event sourcing shines when history matters. When you need to know what happened. When you need to debug issues. When you need audit trails. When you need to rebuild state.
Financial systems. Order processing. Inventory management. Systems where losing history is expensive. Systems where you need to prove what happened.
It also works well with event-driven architectures. Events flow between services. Services react to events. The event log becomes the integration point. Services can replay events. Services can build their own views.
But it's overkill for simple CRUD. If you just need to store and retrieve data, traditional databases work fine. If you don't need history, don't pay the cost.
Internal Versus External Events
There's an important distinction between internal and external events. Internal events are for your domain model. They represent things that happened in your system. OrderAllocated. PaymentProcessed. InventoryUpdated.
External events are for integration. They're published to other systems. They're part of your API. They need to be stable. They need to be versioned. They need to be documented.
Not all internal events become external events. Some events are just for your domain. Some events get upgraded and published. This distinction matters. It keeps your domain model clean. It keeps your integration layer stable.
Versioning Events
Events will change. Your domain will evolve. Your requirements will change. You'll need to add fields. You'll need to change semantics. You'll need to handle old events.
This is hard. You need versioning strategies. You need migration paths. You need to handle old events when replaying. You need to handle schema evolution.
Greg Young wrote an entire book on this: Versioning in an Event Sourced System. It's worth reading. Event versioning is one of those problems that seems simple until you try to solve it.
The Reality of Event Sourcing
Event sourcing is powerful. But it's not a silver bullet. It solves real problems. But it introduces real complexity.
I've seen teams adopt event sourcing because it sounds cool. They end up with systems that are harder to understand. Harder to maintain. Harder to change.
I've also seen teams avoid event sourcing because it sounds complex. They end up with systems that lose history. That can't be debugged. That can't be audited.
The truth is in the middle. Event sourcing is a tool. Use it when it makes sense. Don't use it when it doesn't.
For systems where history matters, event sourcing is worth the complexity. For systems where it doesn't, traditional approaches work fine.
The key is understanding the trade-offs. Understanding when the benefits outweigh the costs. Understanding when you need history more than you need simplicity.
Building with Events
If you're going to use event sourcing, start small. Model one aggregate with events. See how it feels. See if it helps. See if the complexity is worth it.
Use an event store. Event Store. Kafka. Something built for this. Don't try to build it yourself. Don't try to use a regular database. Use the right tool.
Build read models. Project events into views. Optimize for queries. Rebuild when you need to change.
Handle failures. Projections can fail. Events can be out of order. You need idempotency. You need retry logic. You need monitoring.
Version your events. Plan for change. Design for evolution. Handle old events gracefully.
The Bottom Line
Event sourcing changes how you think about data. Instead of storing state, you store history. Instead of updating records, you append events. Instead of losing information, you preserve it.
This comes with costs. More storage. More complexity. More things to learn.
But it also comes with benefits. Complete history. Full auditability. The ability to rebuild state. The ability to debug issues.
The question isn't whether event sourcing is good or bad. It's whether it's right for your problem.
If history matters, if you need to know what happened, if you need to debug production issues, event sourcing might be worth it.
If you just need to store and retrieve data, traditional approaches work fine.
The key is understanding the trade-offs. Understanding your requirements. Understanding when the benefits outweigh the costs.
I learned this the hard way. By losing data. By not being able to debug issues. By not having the history I needed.
Now I think about events differently. I think about history. I think about what happened, not just what is.
What's your experience with event sourcing? Have you seen it help? Have you seen it hurt? When does history matter more than state in your systems?
