Skip to content

Concepts

You Don't Need an Outbox

The outbox pattern has quietly become canonical in microservice tutorials. It has a name, library support, conference talks, and a steady stream of blog posts that walk through implementing it. It's blessed. And yet, every time it shows up in a system, it's a sign that something else has gone wrong upstream.

The pattern itself is clever. It works around a real, structural problem: two systems that need to agree but can't share a transaction. The question worth asking is whether you need to have that problem in the first place. Once you take that seriously, the outbox stops looking like a pattern and starts looking like an admission of defeat.

Commands Aren't Just Events in Reverse

BorrowBook and BookBorrowed. ReserveSeat and SeatReserved. AcquireBook and BookAcquired. The first half is what someone wants, the second half is what happened, and the only visible difference is the tense. Most diagrams in most Event Sourcing tutorials draw the two as a pair, and after enough examples, your brain quietly starts assuming they always will be.

That picture gets people started, and it isn't wrong, exactly. But the more real your system becomes, the less it matches the shape of what's happening underneath. Commands and events look symmetric on the surface, and they're not. They're not symmetric in whether they can fail. They're not symmetric in who they speak to. They're not even symmetric in number. Treating them as if they were is one of the quietest, most expensive mistakes we see, because the code keeps working long enough for the asymmetry to set in everywhere before anyone notices.

Email Uniqueness in Event Sourcing

Recently, a reader asked us how to enforce email uniqueness when registering users in an event-sourced system. It is a fair question. In a relational database, you add a column, slap on UNIQUE, and the problem is solved. The database does the heavy lifting, and you move on with your day. In Event Sourcing, that easy answer simply does not exist.

The good news is there are several reasonable ways to solve it. The bad news is that none of them is free. Each one pays for uniqueness somewhere, whether in scale, in latency, in user experience, or in operational complexity. Choosing among them is not a technical question. It is a question about what your business actually means by "unique."

Sagas vs Process Managers

The moment a workflow spans more than one aggregate or service, someone will say: "We need a saga." It has become the default term for anything that coordinates multiple steps in an event-driven system. Book a flight, reserve a hotel, charge the credit card, and if any step fails, roll everything back. That's a saga, right?

Not quite. What most people describe when they say "saga" is actually a different pattern with a different name, different responsibilities, and different trade-offs. The confusion is not just semantic. It leads to architectural decisions based on the wrong mental model, and those decisions are surprisingly hard to reverse.

Decide, Evolve, Repeat

Almost every Event Sourcing implementation starts with aggregates. You define a class, give it a method for each command, mutate internal state when events are applied, and wire it all up with a framework. This works. Countless systems have been built this way. But if you step back and ask what Event Sourcing actually needs at its core, the answer is surprisingly minimal.

The Decider pattern, introduced by Jérémie Chassaing, strips Event Sourcing down to three functions. No classes. No inheritance. No framework. Just three pure functions that capture everything an event-sourced component does. It is one of the most elegant ideas in the Event Sourcing space, and once you see it, it changes how you think about the entire approach.

The Snapshot Paradox

When developers discover Event Sourcing, one of the first concerns that arises is replay performance. "What if a subject accumulates thousands of events? Won't rebuilding state become painfully slow?" The answer that usually follows is snapshots. Store the current state periodically, and start replaying from there instead of from the beginning. Problem solved, right?

Not quite. In our experience, snapshots are one of the most overrated concepts in the Event Sourcing toolbox. They solve a problem that rarely exists, and when they seem necessary, they often point to a deeper issue that snapshots merely paper over. That's the paradox: the feature designed to optimize performance frequently masks a modeling mistake that, if fixed, would make the optimization unnecessary.

DDD: Back to Basics

A few months ago, I wrote about what went wrong with Domain-Driven Design. In If You Apply DDD to DDD, You Won't Get DDD, I argued that the patterns became the goal, the terminology became a barrier, and the human work got buried under technical abstractions. That criticism stands. But criticism alone is incomplete.

Because not everything in DDD is noise. Strip away the pattern theater, the academic language, the certification industry, and you find a core that actually matters. Commands. Events. State. Aggregates. Ubiquitous Language. Bounded Contexts. These concepts are worth understanding, worth keeping, worth building on. This post is about that core.

The Three-Cent Problem

A few years ago, a bank where we had one of our business accounts lost a transfer of 35,000 Euros. The money left one account but never arrived at the other. It happened between Christmas and New Year, so at first we assumed it was just slow. It was not slow. It was gone.

We complained. We got the money back. We changed banks. So far, so good.

But here is the thing: 35,000 Euros is noticeable. Someone checks the account, sees a missing chunk, raises the alarm. But what if it had been 3 Euros? Or 3 cents? Would anyone have noticed?

Your Aggregate is Not a Table

When developers first encounter Event Sourcing, they bring their mental models with them. Years of working with objects and tables have shaped how they think about data. And so, when they hear the word "Aggregate," something familiar clicks in their brain: an Aggregate must be like an object, and objects map to tables. This intuition feels right. It's also wrong, and it leads to Event Sourcing that looks suspiciously like CRUD with extra steps.

Time is of the Essence

First of all: We wish you a happy new year! We hope you had a wonderful Christmas and an amazing time! 🎉

Speaking of time, let's talk about one of the most commonly misunderstood concepts in event sourcing: when did something actually happen?

If you've worked with events for a while, you've probably noticed that every event comes with a timestamp. In CloudEvents, this is the time field, which EventSourcingDB sets automatically when an event is stored. It's tempting to use this timestamp for business logic. After all, it's right there, readily available. But doing so can lead to subtle bugs and incorrect assumptions. Here's why, and what to do instead.