28

I've been researching Event Sourcing, and it seems there are two philosophies hidden within what I've read. The core difference is whether actors in the system are proactive, making changes first and publishing events based on what they have done, or reactive, consuming events and updating data based on those events.

However, the former isn't really Event Sourcing, right? The events aren't the source of change, but just a record of change. That's just an event-based log that can be used to rebuild the data later. When you rebuild the log, you're using different code than when you executed in the first place; in the original run, you send an event that you read the second time around. On top of all of that, you have to introduce commands to actually trigger those changes, which need to be sent directly to the consumer, causing a tighter binding.

Meanwhile, the "reactive" style reverses all of those concerns. Since every change is a reaction to an event, there's basically no difference between listening to the "live" system as it churns on and listening to a replay sometime later. There's no need for explicit "commands", because services aren't told what to do. Rather, they're in charge of maintaining consistency in the face of the events that occur elsewhere, and of notifying others of their own events. The flip side of this is an inversion of control: instead of knowing about other services/aggregates so you can tell them what to do, you just broadcast your event to the system and let them respond according to their rules. The only comparative downside I see is that you have to explicitly ignore new messages when replaying old messages, but that can be done with configuration/flags.

And yet, many guides and products seem to endorse a proactive style. For example, Event Store expects events to be divided into streams based on their target - meaning there is only one target per event, as if you're either sending it to a single, designated target (which makes it a glorified command) OR because the "target" is really just the source making a record of the action it took.

There must be a gap in my understanding, but after a week or so of reading I haven't come across a well-supported explanation for this. I suppose two questions come out of this:

  1. Which of these two approaches is truly Event Sourcing?
  2. Are there benefits that the proactive approach has over the reactive approach that I haven't mentioned here?
2
  • 2
    Fowler's definition definitely implies that change IS an event. In that sense, state of application becomes new after the event. Consider consistency requirements and error handling, and you can't interpret him in another way. Don't be confused by eventual consistency often used in complex UI. That's Observer, not Fowler's event Sourcing.
    – Basilevs
    Apr 20, 2020 at 18:49
  • @Basilevs unfortunately, your comment is unclear to me. "change IS an event" suggests that the change should be followed by a message describing the change, but "state... becomes new after the event" suggests that the stage is changed in response to the event. I would greatly appreciate if you could create an answer that corrects my misunderstanding. Aside from that, Fowler's 2005 article is described as "very much in draft form", so I don't wish to consider that a strong source. Apr 20, 2020 at 19:15

3 Answers 3

21

Reminder: it is not your fault that you are confused; the literature sucks.

Which of these two approaches is truly Event Sourcing?

"Event sourcing", as spoken by Event Store, Eventide project, and others, means storing state as a history of events. The event store replaces the RDBMS that we might normally use to remember our history. The history, as represented in an event store, is an append only sequence of events that describe how an entity has changed over time.

When you rebuild the log, you're using different code than when you executed in the first place; in the original run, you send an event that you read the second time around.

Sort of, but not in a way that is significantly different from how we do things in a relational world.

In the world of an O/RM, how do we remember where we are? Typically, when new information arrives, we load our own memory from the database, integrate the new information, and then store our new memory into the database (replacing the old). The old memory is loaded, the new memory is calculated. We store the new memory, and when we next need it, that memory is loaded.

With event sourcing, this basic protocol is unchanged - the significant difference is that we don't replace the old memory, but append new changes to it.

In Pat Helland's terms, event sourcing is about data on the inside; how the domain model in the past shares information with the "same" domain model in the future.

the "reactive" style reverses all of those concerns.... There's no need for explicit "commands", because services aren't told what to do

Not a difference worth worrying about. Messages arrive, the domain model changes, messages depart. Whether you label those messages as commands or events really doesn't matter very much

  • handle(Event) is a command
  • CommandReceived is an event

You can introduce semantic distinctions to separate messages that fan-in toward the authority (commands) from those that fan-out from the authority (events), but from the perspective of the domain the interesting bit is the information that the messages contain, and how the domain model changes in response to that information, not which pattern we think best fits the message.

One idea that may help in all of this is to keep in mind that event sourcing comes from a domain modeling tradition, meaning that we are managing lots of little state machines that have their own private data to track what state they are now in, and their own domain logic to compute what state they should be in next. Think "tell, don't ask" -- we feed new information into the domain model, and it decides for itself what state it should now be in.

Does one service tell another what to do, or does the first simply announce what it did and the second reacts?

This is your key confusion right here - this is a question about a communication pattern. It has nothing to do with event sourcing, which is a data representation pattern.

The most common (or at least, most commonly approved of -- aka "best practice") is that services share information with zero or more subscribers; which is to say that the messages are fan-out. The source service publishes a message, and the subscribers react to it, or not, as they see fit.

(The primary advantage here being that you can add/remove subscribers without deploying a new copy of the source service).

The mechanism of exchange of information between services is a separate concern (a separate design decision) from the arrangement of information within a service.

1
  • 1
    See edits above. The ddd-cqrs-es slack team might be a better forum for a long running discussion - and there are more people there who will have alternative perspectives/experiences to share. So you might consider joining: j.mp/ddd-es-cqrs Apr 21, 2020 at 14:04
1

Maybe looking at the approach of axoniq.io/ will shed some light? I quite like it and I suppose this would be reactive according to your definition.

In the Axon framework you have CommandHandlers and EventHandlers.

CommandHandler annotated method accepts the command and enforces the aggregate's (simplifying for those who are not into ddd: object which holds the state) invariants. So this is the place where you would potentially reject the command if you for example cannot like the same post twice. In here you will also create an appropriate event should you accept the command.

EventHandler annotated method on the other hand only receives an event (you cannot reject an event) and upon receival mutates the state of the object, applying changes.

Personally I tend to think that the reactive approach is the right one and it seems to make more sense to me, because:

  1. It solves the problem: "what if I changed the state, but then my application crashed and I didn't persist the event?". State of the application would diverge from the events. Instead: you first persist the event and only then do you mutate the state (after it's been saved successfully)
  2. Having separate commands and events lets you easily replay events. This makes sense when you e.g. send an email upon an accepted command. You wouldn't want to send an email everytime you restore your applications state and apply an event.
2
  • If I'm following, then in an abstract sense, CommandHandlers are validators for certain events that would come from an un-trusted source? May 14, 2020 at 17:08
  • It's more about aggregates rather than CommandHandlers, but it's a discussino about DDD more than event sourcing. If you're interested take a look e.g. at the article about model validations May 15, 2020 at 7:39
0

As for your first question: My understanding is that the idea of event sourcing is to be able to reproduce state from the sequence of [relevant domain] events that led to it. The events thus form the source of any future reconstructed state. The proactive or reactive style does not seem relevant to such a definition.

I will share a perspective on your second question, regarding the benefits of the two approaches.

Consider for a moment the way bounded contexts might communicate. The visibility (who knows who) is important. Here are two common ways with sharply contrasting implications:

  1. BC1 makes a direct call to BC2.

    • BC2 defines the API and guards its constraints, but does not care who invokes it.
    • BC1 knows about BC2 and its API, and is allowed to put it into action.
  2. BC1 broadcasts an event. BC2 and BC3 act on that event.

    • BC2 and BC3 have knowledge of BC1, and make their own choice to act on its events.
    • BC1 defines the event and broadcasts it when applicable, but does not care who may be interested.

For each of the above, it's very easy to come up with an example where that approach makes the most sense.

I believe these options are fairly well-established when it comes to protocols between bounded contexts. However, the concepts may apply within a domain model just as well! Interestingly, they match the proactive and reactive styles that you mention, respectively.

  1. DomainObject1 invokes a command on DomainObject2.

    • DomainObject2 defines the command and guards its constraints, but does not care who invokes it.
    • DomainObject1 has knowledge of DomainObject2, and is allowed to put it into action.
    • This is the proactive style.
  2. DomainObject1 broadcasts an event. DomainObject2 and DomainObject3 act on that event.

    • DomainObject2 and DomainObject3 have knowledge of DomainObject1, and make their own choice to act on its events.
    • DomainObject1 defines the event and broadcasts it when applicable, but does not care who may be interested.
    • This is the reactive style.

Both styles make perfect sense, wouldn't you say? Sometimes a model wants to proclaim what happened, not caring what should happen next. At other times, a model wants to be instructed to do something, not caring which situations warrant it. The distinction appears to be about responsibility and about having a chain of coupling that makes sense for the model. In many models, I would expect to see both.

To wrap up, let me try to answer the question in the title of your post.

Each event was caused by something. That thing could, very likely, be described as an event itself. However, we are generally only interested in relevant domain events. It may not be meaningful to consider a command as originating from a UserClickedButtonEvent. Disregarding the irrelevant events, we should be able to trace each event (potentially through prior events that caused it) back to a command, a declaration of intent. From that perspective, the declaration of intent came first, and events followed.

Not the answer you're looking for? Browse other questions tagged or ask your own question.