Debunking Event Sourcing by Eduardo Bellani
Are you looking into event sourcing? I hope this article gives you enough information for you to properly contrast it with what I consider an overall better alternative: temporal tables.
The context: my last article (Are you considering Event Sourcing? Think again) has produced some heated responses. One of the responders published an article (Dear Temporal Table Developers ❤) explaining
.. why temporal tables are … an inferior choice, especially for systems that require scalability, flexibility, and resilience in an ever-changing world.
Since the published reply contains an amalgamation of common positions on this matter, I want to use it as an opportunity to create a reference for myself and others in the future when debating this topic. Therefore, I’ll go topic by topic, linking to the appropriate place
Temporal Tables Aren’t True History
Events (allow) you to understand both the “what” and the “why” in a meaningful way.
Here the author is referring to the name of the event that should
map
to an use-case, and claiming that this is impossible with the relational
model.
This is a bogus claim. If such data is demanded by your business rules, there is no reason why it can’t be expressed as part of a table. Here is an example:
{
"name": "reservation-bought",
"reservation-id": 1,
"user-id": 33,
"seat-id": 100,
"venue-id: 12,
}
In a SQL version, all you need is to add the intent as a desired attribute.
create table reservation (
user_name references user (name),
seat int,
venue string,
intent text,
CHECK (intent in ('buy', 'rent'))
Temporal Tables Impose Rigid Structure
This seems to be the main point of the article. So I’ll break it down in parts and index my replies below:
One of the biggest pitfalls of temporal tables is the inherent rigidity of the relational model.
As your application grows and evolves, so do your requirements, and changing a temporal table schema can become a significant burden.
Event Sourcing lets you evolve your system naturally. Each new feature or behavior can be introduced as a new event type, without the need to retroactively change the structure of your past data.
-
This point seems to imply ignorance of what the relational model (RM) is. The RM is a logical model based on set theory and predicate logic. One of the major points of the RM is to allow developers the flexibility to choose access paths after database design.
-
Changing the schema of a temporal database can potentially be serious and delicate work, since it might involve changing what you claimed were your past beliefs. This is an universal point.
-
Given the previous point, versioning in an event sourced system can be at least as hard as versioning any other. As one of the leaders of the ES/CQRS community puts it:
Over the years, I have met many developers who run into issues dealing with versioning, particularly in Event Sourced systems. This seems odd to me. As we will discuss, Event Sourced systems are in fact easier to version than structural data in most instances, as long as you know the patterns for how to version, where they apply, and the trade-offs between the options. dealing with versioning, particularly in Event Sourced systems. (Young 2017)
In fact, I’ll claim that managing the evolution of a temporal structure in event sourced systems is harder. I’m not alone in this assessment:
Data conversion in event sourced systems introduces new challenges, because of the relative novelty of the event sourcing architectural pattern, because of the lack of standardized tools for data conversion, and because of the large amount of data that is stored in typical event stores.(Overeem, Spoor, and Jansen 2017)
Temporal Tables Aren’t Built for Distributed Systems
.. temporal tables simply don’t cut it. They are designed with a single-node, relational mindset, which makes them ill-suited for large-scale, distributed architectures.
I think the author here is confusing a logical approach, temporal tables, with an implementation in a DBMS, such as PostgreSQL or SQL Server. One can certainly scale a modern DBMS to impressive results(Justin Kwan 2022).
Complex Queries and Performance Overhead
With CQRS, you avoid this mess entirely. Instead of bloating your read models with historical data, you can create dedicated read projections that are optimized for the specific queries you need. Event-driven architectures naturally lend themselves to this approach, allowing you to create purpose-built views without overloading your database.
The author seems to be impliying that creating projections are in any way better than creating queries. This is the opposite of reality, because:
- You will pay the cost of maintaining each read projection(Kiehl 2019) as you would with a view or a snapshot
- SQL is a DSL specifically designed for querying
- CQRS itself adds
risky
complexity(Fowler 2011). A very risky kind of complexity indeed: consistency problems.
A False Sense of Auditability
This is just restating Temporal Tables Aren’t True History.
Temporal Tables Lack Flexibility
This is just restating Temporal Tables Impose Rigid Structure.
Event Streams Are the Real Temporal Model
This is just restating Temporal Tables Aren’t True History.
Temporal Tables Create Monoliths, Not Microservices
This is confusing logical and physical concerns, or, as I put it in another article (see How to avoid frustration with software architecture):
Fundamentally, I think the problem that originated the current dissatisfaction with microservices is a double confusion:
- between the form (modules) and the matter (interacting running processes) of software and;
- between the the form (modules) of software and the form of software building organizations (teams, executing environments, deployment pipelines …)
My conclusion
The preference for Event Sourced systems seems to stem from a confusion
of physical and logical concerns and a vague desire for
scaleability
.