Event Sourcing

Part I: Understanding what it is, core components, and common misconceptions

Mario Bittencourt
SSENSE-TECH
7 min readMay 22, 2020

--

Event Sourcing is an architectural pattern that has been available for many years, commonly used as part of complex software solutions. While discussing with peers in the industry, or simply by reviewing the approaches taken by some companies, it was clear that it is a subject of controversy, surrounded by misconceptions.

In this article I will introduce what Event Sourcing is really about, and highlight what it is not.

If you are interested, here are the other parts:

Part II — Implementing an end-to-end solution
Part III —Handling Different Access Patterns
Part IV — Evolving Your System

A Formal Definition (sort of…)

In the past, whenever I researched Event Sourcing, the sources I found hardly ever provided a definition of what it is, but instead focused on explaining how it works, what its components are, and how to integrate it into your application.

Don’t worry, I will also cover these aspects, but first, here goes my definition of Event Sourcing:

Event Sourcing is a way to architect your application such that its current state at any given time is not persisted, but reconstructed from all the events that happened up to that point.

Awesome, right? No? Okay, I guess it can benefit from some further explanation, so let’s break down the key aspects:

State: the state of the application, or more specifically, the state of the entities it manipulates. It contains the properties of the entity at a given point in time.

Not persisted: a non-Event Sourcing application stores only the current state, losing any previous information. With Event Sourcing, you don’t persist the current state, but the changes that happened thus far.

Reconstructed: since you don’t store the current state, in order to find out what the current state of an entity is, you have to reconstruct it by going over all the changes that have been made to that entity since its creation.

Events: indication that something has happened that changed the state of an entity.

With this definition set, let’s compare two applications:

Figure 1. Non-Event Sourcing application

In a non-Event Sourcing application, you are persisting, and therefore retrieving, the last state of an entity. Figure 1 illustrates an application retrieving a specific order, which is fetched from your persistence medium and returned as is. If you want to understand what happened before to that order, you are out of luck.

Figure 2. Event Sourcing application

Using the same use case, illustrated with Figure 2, but served by an Event Sourcing application is addressed by returning all the events associated with the requested order. It is now feasible to understand the evolution of the order through time. Which brings me to highlight a necessary shift when approaching your application: time becomes more important than data.

Modelling your application’s state through time becomes your first concern. Changes are now encapsulated in events, which can be traced back to the actions in your application which caused the change of state.

Figure 3. Chronology of command, entity, event

Anatomy of an Event Sourcing Application

The 3 principal elements of an Event Sourcing application are:

  • Entities

An entity is the domain concept that holds data (properties) and behavior. Entities change their state, and such state changes are emitted via events.

  • Events

An indication that something has happened with an entity. It contains enough information to identify what changed, and when.

  • Event Store

Provides persistence services that allow you to add an event and retrieve events for a given entity. Usually, Event Stores are designed to ingest and produce data streams, which group events following certain criteria, such as all events for a given entity identifier.

Creating an Entity

Figure 4. Creation of an entity
  1. A command creates the entity:
  • At this moment, the entity only contains its identifier.

2. Entity emits the event:

  • The event is created with the data that represents the new state of the entity.

3. Entity applies the event, updating its state:

  • By applying the event, the entity now reaches the desired state.

4. The Event Store accepts the event:

  • Since it is the first event, a new stream is created.

5. The event is added to the stream.

  • It is important to mention that the event should not interact with the Event Store by itself. Your application should take care of that.

Reconstructing an Entity’s State

Figure 5. Reconstruction of an entity
  1. The Event Store requests to find the entity with the identifier.
  • It is common to think of an Event Store as a series of streams, usually one per entity.

2. The Event Store locates the stream:

  • The stream contains all events for a given entity identifier, in chronological order.

3. The store then returns the events:

  • The event is returned in the same order, from oldest to newest.

4. An Entity is created:

  • At this point it only contains the identifier.

5. Events are re-applied:

  • For each event returned it is applied to the entity, updating its state.

Updating an Entity

Figure 6. Updating an entity
  1. Apply the new command on the entity:
  • Entity was reconstructed (see previous section) and only validates the command.

2. Entity emits the event:

  • The event is created with the data that represents the changes to the new state of the entity.

3. Entity applies the event, updating its state:

  • By applying the event, the entity now reaches the desired state.

4. The event is added to the Event Store:

  • Since it is not the first event, the stream that contains the older events is located and used.

5. The event is appended to the existing event stream.

  • We now have a full cycle, as we are capable of creating, reconstructing, and updating entities in our application.

Most applications will require other access patterns to its entities, usually to allow searches based on entity properties, or to provide some transformations or data aggregation. At this point, it is necessary to mention that Event Sourcing can be applied with another pattern called CQRS to address those access patterns, but detailing CQRS is outside the scope of this article. The Event Store represents your write model and every time a new event is stored in it, your read model is notified and updated to reflect the changes.

Figure 7. The read and write models in a CQRS solution

Common Misconceptions

“My application publishes/emits/uses events, therefore I am using Event Sourcing.”

Not necessarily.

The term event is fairly common in any modern application, especially those that are distributed in nature. As you interact with your application, it can emit events as part of fulfilling an operation, but if you are persisting only the current state, it is not an Event Sourcing application.

If you use events to communicate changes asynchronously with your own application, or other applications, it is only safe to say that your application follows an event-driven architecture.

“I can’t use Event Sourcing because it is going to be too slow.”

Not necessarily.

Like any pattern, Event Sourcing, provides a proven way to solve certain types of problems. You have to first assess if your application has the properties that can benefit from using this pattern.

The idea that reconstructing state by replaying the previous events is slow needs to be put in perspective:

  • What is the access pattern?

Is it a single entity being accessed by its identifier, or a multi-entity retrieval by some search criteria?

If it is being accessed by its identifier, you are retrieving the list of events based on the entity identifier, which gives you a fast access to them. If you have too many events, you can leverage the creation of snapshots. This is a technique to replay events and store the result up to that point and only apply subsequent events from that point in time.

If it is a multi-entity retrieval, you would be using a read model where the persistence technology and data stored would be optimized for your use case.

  • Who is the audience, and what is the intent of accessing?

Is it a restricted audience, accessing with intent of making changes, or a public read-only audience.

If it is a restricted audience with the intent of editing, then you should not see any issues as they would access the entity by its identifier.

If it is a public audience with read-only intent, the read model provides the means to achieve the performance you need.

So, what’s next?

Hopefully by now, you are clear on what distinguishes an Event Sourcing application from the rest, its main components, and how they operate. In part 2 of our Event Sourcing journey, I will present an implementation that showcases these elements, and discuss in detail some of the benefits of Event Sourcing.

Editorial reviews by Deanna Chow, Liela Touré, & Prateek Sanyal.

Want to work with us? Click here to see all open positions at SSENSE!

--

--