There is a special kind of fear that lives in software teams that handle money. It is the fear of the question “can you prove what happened?” An auditor asks it. A regulator asks it. A big customer asks it. And in many systems, the honest answer is “more or less.”
Most systems store only the current state. The database row says the balance is 500 dollars. How did it become 500? When? Who touched it? Which rule was applied? If you did not log it somewhere, that history is gone. Updated in place, overwritten, lost.
Event sourcing is the architecture pattern that makes this fear go away. And after working for years on software that moves real money for charities and companies, I can tell you the smile in the title is real.
The idea in plain words
Martin Fowler wrote the classic description back in 2005, and it is still on his site today. Greg Young then spent years pushing the pattern further and teaching it to the industry, usually together with CQRS.
The idea is this. Instead of storing the current state, you store every change as an event. Not “balance is 500.” Instead, a list. Account opened. Deposited 300. Deposited 300. Withdrew 100. The current state is not stored as the truth. It is calculated by replaying the events. The events are the truth.
Events are immutable. You never update one, you never delete one. If a mistake happens, you do not erase it, you add a correcting event. Just like accountants have done with their ledgers for hundreds of years. Accountants figured this out centuries before we had computers, and they figured it out because money plus disputes equals a need for history.
Why the auditor smiles too
Now the business value, because this pattern is not popular for technical beauty. It is popular where history is worth money.
Audit and compliance. When the auditor asks “show me everything that happened to this transaction,” you do not start a two week archeology project across logs, backups and the memory of a developer who left the company. You query the event stream. Every change, in order, with timestamps and who did it. What used to be days of expensive panic becomes a normal query. In regulated industries this is a direct cost reduction, and it also lowers the risk of failing an audit, which is the kind of failure that makes the news.
Dispute resolution. A customer says “I never approved this.” With current state only, it is your word against theirs. With events, you can show the exact sequence. Disputes close faster, refunds get fairer, and support spends less time investigating.
Debugging in time. A bug corrupted some data three weeks ago. In a normal system, you restore backups and pray. In an event sourced system, you can replay events and see exactly when and how things went wrong. Some teams even fix the bug and replay history through the corrected logic.
New questions about old data. The business asks “how many users tried to do X and gave up last year?” If you only stored final state, that answer does not exist. If you stored events, the answer was waiting there before anyone asked the question. I have seen this turn into real product decisions more than once.
The honest warning
Now the part that many event sourcing talks skip. This pattern is expensive, and using it everywhere is over engineering.
Event sourcing makes everything indirect. You cannot just open a table and see the data. You deal with event versioning, because events written three years ago must still be readable today. You deal with projections, replays, and eventual consistency between the write side and the read side. Your team needs to learn a different way of thinking, and new people take longer to get productive. All of that is cost, paid in time and salaries, every month, forever.
So the question is never “is event sourcing good?” The question is “does this part of the business need history badly enough to pay for it?”
For a money ledger, yes, almost always. For anything an auditor or regulator will look at, probably yes. For a user’s notification preferences? No. A simple table with updated rows is perfect there, and an updated_at column plus a basic audit log covers the rare question.
My rule is simple. Use event sourcing where history is a business requirement, not a developer wish. One or two bounded contexts in a system, usually the ones touching money or legal obligations. Everywhere else, boring CRUD wins, because boring is cheap and cheap is a feature.
How I keep it small
When I have a real case, I do not rewrite the system. I pick the one aggregate where history matters most. I model its events with the business people in the room, because event names are business language, not technical language. Build it, run it, learn the operational habits, and only then look at whether a second place deserves it.
And when I land in a system that handles money with no event history at all, the first thing I reach for is a simple append only audit log. It is not full event sourcing, but it is ninety percent of the smile when the auditor knocks, for ten percent of the cost.
The knock on the door will come. The only question is whether you will smile or sweat.
Pax et bonum.