What they don’t tell you about event sourcing

Hugo Rocha
10 min readAug 12, 2018

Event sourcing and CQRS gained a lot of popularity recently. The advantages are obvious and they share a very peculiar symbiosis with the current tech state of the art, making them very relevant. However, after working for several years with them in production there are several caveats that one should care for.

If you are not familiarized with event sourcing it comes down to instead of saving the application’s last state, to model it in the form of a sequence of immutable events. Changes to the state are reflected by saving the event that triggers that change instead of changing the current state. Processing each event in the stream will produce the latest state of that entity. You can find a detailed explanation by Martin Fowler here.

At first glance, it seems a terrible idea. Since each entity is represented by a stream of events there is no way to reliably query the data. I have yet to meet an application that doesn’t require some sort of querying. This is especially evident in data-intensive applications where much of the business value relies on analyzing the data. This difficulty by itself makes event sourcing unsuitable for most applications and only relevant for very isolated and specific use cases.

That’s when CQRS comes in. CQRS (command query responsibility segregation) describes the concept of having two different models one to change information and one to read it, completely separated from each other. Asking a question shouldn’t change the response. Martin Fowler has a very interesting article about it here.

Greg Young identified quite well how CQRS and event sourcing shares a symbiotic relationship. The limitation I talked earlier elegantly goes away applying event sourcing with CQRS. Having the write model separated from the read model enables the use of the most appropriate strategy for each model and allows both the write and read model to be scalable independently. Event sourcing is a particularly efficient write model since it works basically as an append log where new information is always added enabling minimal locking. Since each event is irremovable and immutable no updates or deletes are needed enabling good write performance. On the other hand, since the read model is completely independent allows the freedom to choose the most adequate…