4 min read

Intuiting Event Sourcing

Intuiting Event Sourcing
Photo by Omar Flores / Unsplash

The goal of this article is to establish intuition for event sourcing. It will not cover any implementation details or even mention of technology. These more in-depth topics will be covered in future posts.

Take some time to navel-gaze on the first sentence of this article by Martin Fowler.

Capture all changes to an application state as a sequence of events.

Fowler's article is written with software applications as the central topic. However, event sourcing exists in everyday areas of life.

  • bank deposits and withdrawals
  • retail order placement and fulfillment
  • movie/show watch history
  • medical care history1
  • your life itself2

The banking example is generally the simplest to understand (and most often cited) because it is so familiar. Conceptually, deposit and withdrawal transactions correspond to the events while the available and ledger balances are the derived state.

Think for a moment if you couldn't see the transactions at all. You log into your bank website and you only see the available and ledger balances. What if your ledger balance shows a huge decrease that you didn't expect? Without the list of transactions, you would not know which withdrawal caused the decrease.

This historical/audit log is one inherent property of event sourcing that is necessary for certain domains (finance, healthcare), but virtually all domains can leverage it.

To prevent further navel-gazing, let's jump into a few more concrete details.

More concrete

Above, I stated that transactions are conceptual events and the balances are the conceptual state. When modeling a problem or a solution, there are, generally, three core primitives to work with.

  • Event - something that happened, e.g. deposited or withdrew (past tense)
  • Command - an intention to do something, e.g. a deposit or withdraw (imperative)
  • State - point-in-time information necessary to evaluate the command, e.g. the available and ledger balance

In practice, events don't exist in a vacuum. There is always an action that results in an event. We define commands as an intention to perform an action. Likewise, as events occur, we can derive information from these events in order to build up the state necessary to evaluate the next command.

The basic flow of receiving a command and, if accepted, producing an event. The event is then fed back into the state for the next command to be evaluated. The bounding box of the state represents the command handler which encapsulates the logic for evaluating the command against to the state.

The command is the intention to make a change. If that change is accepted, an event is produced that describes that change. Determining if the change can be accepted depends on information from the previous events.

Given-When-Then table showing progression of the state when commands are received.

The above diagram is one way to demonstrate the Given-When-Then relationship between the state, command, and event using only the available balance for simplicity. This can be read as "given $0 available, when a deposit of $10 occurs, accept that $10 were deposited". Notice the produced event is fed back into the state for when the next command is received.

You can follow this a couple more times until the last column where a command is received that cause the available balance to go below zero. Assuming this should not happen (your bank doesn't take advantage of overdraft fees..) then the command would be rejected.

If you are more into a state machine-type of layout, below shows what this might look like.

Pseudo-state machine layout of deposits and withdrawals.

The left side still includes the commands and resulting event leading to the next state. The right side omits these to reiterate how unsettling this might be if you did not have the transaction information available. Each time you view your available balance, it is a different number without any other information (not even the previous states).

My opinion

For me, events as a way of modeling are more intuitive. You can start with thinking "this happens, then this, then this" etc. Time and causality is first-class (like the real world) and adapting to changes in the domain is simpler since every event represents an isolated state change. The focus is on actions and reactions, behavior, and workflow, not just on entities that are being affected.

In terms of data modeling, event sourcing sits at a lower level than other common types like relational, document, and graph. These latter data models, which often model state, can all be derived from an event log, but the reverse is not true.

If you are curious to learn more, please check back for more in-depth articles on the topic. There are also a plethora of existing resources to learn from.

1. Your medical care history is recorded as a series of encounters including observations, diagnoses, procedures, medications, etc. Some of the events are explicitly ordered such as an observation followed by a diagnosis, followed by a procedure. From a doctor's point of view, your health posture is the state they care about. It certainly includes a lot of information, much of which is detailed and highly personal. However, other life events like what article you read before bed, the flavor of cream cheese you ate this morning, or the movie you went to see last weekend does not have any relevance to your health if you come in for a broken wrist.

2. I don't want that example to dilute the concept, but if you think about all of your experiences in life, everything that has happened to you (regardless of how it happened), one could argue a person is largely the result of their past experiences. Many of your future decisions are based on past experiences. The key bit to understand, just like in the world we live in and observe, events occur which can manifest in many different ways depending on the context. That is, the state (or interpretation) of an event by a person, organization, government, or some other entity, will all vary. However, the event itself is pure and indisputable since it happened.