Thinking in Events¶
Most of us never learned Event Sourcing as a way of thinking. We learned it as a collection of parts. An event store goes here. A read model goes there. When things turn asynchronous, you reach for a saga, and when reads and writes start pulling in different directions, you reach for CQRS. We assemble the pieces the way the tutorials drew them, and for a good while the system holds together.
Then a question arrives that no tutorial covered. Should this be one stream or two? Does this failure belong in the log? Who owns this piece of state? The patterns go quiet, because we learned their shapes without the reasons that gave rise to them. Underneath the patterns, though, there is something smaller and steadier, and a while ago we tried to write it down: a short manifesto that everything else turns out to be a consequence of. Here it is, and here is what it means.
Patterns Are Consequences, Not Rules¶
A rule tells you what to do. An axiom tells you why. When all you have is a bag of rules, every new situation becomes a lookup, and the lookup can miss, because nobody wrote a rule for the exact case in front of you. When you have the foundation instead, you do not look anything up. You derive the answer, the same way you would derive it for a case no one has seen yet. The patterns are not the starting point. They are what falls out once the foundation is in place.
This is also why so many teams can recite the patterns and still build something that fights them. They have memorized the conclusions without ever meeting the premises, and conclusions without premises are just folklore. We have circled this before, in It Was Never About the Database and in DDD: Back to Basics: the value was never in the machinery, but in the understanding the machinery is meant to serve.
So a while ago we tried to compress that understanding into something you can hold in your head. Not a tutorial, not a checklist, but a manifesto. Four sentences, each with a few words of explanation, and nothing more.
A Foundation in Four Sentences¶
Event-based software development rests on three notions: Commands (intent), Events (fact), and State (interpretation). It reaches beyond this triad into Integration.
Commands are intentions, the origin of Events. Everything begins with an intention. Someone wants something, and from that intention a fact arises. The Command faces the future, the Event the past. Yet the step from intention to fact is not automatic. Between them stands a decision. A Command may be refused. An Event, once it happened, cannot.
Events are the natural language of stories, immutable and ordered. They tell what happened, in the language of the domain. Once written, they never change, and they stand in an order that makes cause and effect visible. Whoever has the Events of a story has the story. And when something was wrong, we do not erase the past. We add to it. A correction is a new Event, never a changed one.
State is an interpretation of Events, one of many. State is not the truth. The truth lies in the Events. What we call State is a view, derived from Events, for a particular purpose. For every question asked of the story there is its own interpretation. Many are possible, side by side. And because State is derived, it can be discarded and rebuilt at any time.
Integration rests on Events, not on shared State. Systems and contexts do not meet through shared databases, but through what they tell each other. An Event that crosses a boundary is a message from one story, which the other translates into its own. And an Event crossing a boundary may become the origin of a new intention on the other side.
These four sentences are not a textbook, but a foundation. From them the familiar tools follow as consequences, not as rules: Ubiquitous Language and Bounded Contexts, Event Stores, CQRS and projections, Sagas and Context Mappings. And when a decision grows difficult, or when someone asks why, the path leads back to these four.
That is the whole of it. What follows is not more manifesto, but a walk through the weight each sentence carries, because a foundation you cannot feel is just a slogan.
Commands, and the Decision That Can Say No¶
Start with the first sentence. Its explanation hangs on one small word, the one that does the most damage when it is missed: refused. Because a Command can be turned down and an Event cannot be unsaid, the two are not one thing in two tenses, however much BorrowBook and BookBorrowed look like a matched pair. They differ in whether they can fail, and that single difference reshapes everything downstream, which is the case we made in Commands Aren't Just Events in Reverse.
To refuse a Command well, you have to look at what has already happened, which means you have to look at State. So the triad is not a line but a circle: State and a Command produce a decision, the decision produces an Event, and the Event folds back into State for the next time around. Decide, evolve, repeat is the heartbeat of every write model, and it has a post of its own in Decide, Evolve, Repeat.
The circle also explains where the building blocks come from. A decision needs a consistent view of the past, so it needs a boundary inside which that view holds. People call that boundary an aggregate, though it is a decision boundary and not a storage layout, as we argued in Your Aggregate is Not a Table. EventSourcingDB gives the boundary teeth through preconditions: a write lands only if the past still looks the way the decision assumed. Nobody invented optimistic concurrency as a rule. It is what the first sentence demands the moment a Command is allowed to say no.
Events, and Why We Never Erase¶
The second sentence sounds gentle until you collide it with reality: if an Event can never change, what happens when one was wrong? The manifesto's answer is to add, not to erase, and the consequence is larger than it looks. Because nothing is overwritten, you end up with a complete, ordered record of what occurred, which is precisely what an audit is. In EventSourcingDB that record is hash-chained, so the history is not only complete but tamper-evident, and auditing the event store is a matter of reading the log rather than reconstructing it.
It is the same property that lets investigators rebuild a flight from the black box, the parallel we drew in What Aviation Teaches Us About Auditing. And it is why reaching for a delete is the wrong reflex: a delete throws away a fact, and facts are the one thing the second sentence promises to keep, which is the argument behind Soft Delete Is a Workaround.
If Events are the language of the story, the words have to be chosen with care. A history told in OrderUpdated and DataChanged is a story told badly. Events earn their place when they name what happened in the words of the domain, the point we pressed in Naming Events Beyond CRUD, because those are the words everyone, technical or not, already shares.
State, and the Freedom of Being Derived¶
The third sentence quietly dissolves an entire architecture debate. If State is only ever an interpretation of Events, then separating the side that writes facts from the sides that read interpretations is not a pattern you adopt. It is a description of what is already true, which is why CQRS Without the Complexity treats it as the natural shape rather than an advanced move.
And because an interpretation is derived, it is cheap. You can keep many side by side, each shaped for a different question, from the menagerie in The Read Model Zoo to the cases where a read model does not need a database at all. You can throw one away and rebuild it from the Events when it is wrong, or add a brand-new one tomorrow for a question nobody asked today. Even a snapshot loses its mystery: it is not a second source of truth but a cached interpretation, the reframing in The Snapshot Paradox and the reason EventSourcingDB builds snapshots from Events rather than from a store of their own.
Because the Events are ordered in time, you can also stop reading at any point you like. State as of last Tuesday is simply the interpretation that ignores everything after Tuesday, which turns time travel from a feature into a consequence, the thread of Time is of the Essence.
If you would like to watch the circle turn for yourself, it takes about a minute. EventSourcingDB runs in a development mode with ephemeral storage and a built-in management UI, so there is nothing to provision and nothing to clean up: you can write the Event a Command produced, watch it land, and build a small interpretation of it before your coffee is cool. The installation is a single command, and the rest is the four sentences in motion.
Integration, and the Loop Between Stories¶
The fourth sentence is about what happens when stories meet, and it draws a hard line: they meet through Events, not through shared State. Shared State is shared coupling, because the moment two contexts read and write the same tables, neither can change its mind without the other's consent, the trap of One Database to Rule Them All. Events sidestep it by carrying facts instead of structure. The publisher says what happened and stops caring; the subscriber decides what, if anything, that fact means on its own side, which is why integration through Events needs no outbox bolted onto a transaction, as You Don't Need an Outbox shows, and why a context's internals stay none of anyone else's business.
Now watch the circle from the first sentence reappear, one boundary over. A fact in one story can be the reason for an intention in another: PaymentReceived here becomes ShipOrder there. Fact turns into intent, intent into a new fact, and the loop that drove a single story starts driving a conversation between stories. That loop, made explicit and given a memory, is what people call a saga or a process manager, the distinction of Sagas vs Process Managers, and the translation between one context's language and another's is what Domain-Driven Design calls context mapping, the territory of Two Maps, One Domain. Neither was a rule we picked. Both are what the fourth sentence produces when stories have to meet.
When the Decision Gets Hard¶
Look back at the toolbox now, the one the manifesto promised would follow. Ubiquitous Language is what you get when Events are the language of the story. Bounded Contexts are the boundaries a decision needs and Integration crosses. Event Stores hold immutable, ordered facts. CQRS and projections are State being many interpretations of one history. Sagas and context mappings are the circle running between stories rather than within one. Not one of them is a rule to obey. Each is a sentence taken seriously.
That is the quiet use of a foundation: the patterns stop being things you memorize and become things you can rederive, so you are no longer stranded when a case shows up that no tutorial covered. Should this be one stream or two? Ask which facts must be consistent for a decision, because that is what a boundary is for. Does this failure belong in the log? Ask whether it is a fact the business cares about or just the system arguing with itself. Who owns this piece of state? No one, because State is an interpretation, and interpretations are cheap, disposable, and many.
The four sentences are not a textbook. They are a place to stand. When a design decision grows difficult, or when someone asks why we do it this way, the most useful move is not to reach for a pattern. It is to walk back to the sentence the question touches and let the answer follow from there.
If this is already how you think, or how you want your team to think, cqrs.com is where we go deeper into Event Sourcing, CQRS, and Domain-Driven Design as one connected whole. And if you would like a second pair of eyes while you put this foundation under a real system, in a workshop or a focused review, we would genuinely enjoy the conversation. Write to us at hello@thenativeweb.io.