Oskar Dudycz

Pragmatycznie o programowaniu

Why a bank account is not the best example of Event Sourcing?

2020-12-09 oskar dudyczEvent Sourcing

cover

While explaining the Event Sourcing, bank account balance calculation is a common starting point. I claim that even though it sounds right, then it’s not the best example to show at first.

Term “Event Sourcing” directly means that events are the source of truth. We keep the system state as a series of consecutive events. That means that if you’re modifying the state of your system, for each change you log (store) the event representing the result of the action.

It’s like when describing your day to someone: “You know, the bus was late for me, so I was late at the job. That’s why I had to stay longer, and I was late for our meeting”. After all, we rarely say “I’m late, why to go on about it”. There must be an excuse. Similarly, it usually turns out that the business expects to build the system with the ability to tell the story of what has happened.

Getting back to the banking example. In such a case, we record all transactions for a given account, so inflows (e.g. salaries, payments, etc.) and expenses (e.g. card withdrawals, fees, etc.). Each of these transactions:

  • carries specific business information,
  • occurs within a particular time,
  • follows one another,
  • is immutable (we cannot undo a money transfer once it has been made).

Everything seems okay, why am I picking on it? I am not a saint myself. I also gave such examples before.

Why am I saying then that this example is problematic? In my opinion, it’s not a typical problem solved in Event Sourcing. Providing Bank Account as an example makes it easy to accuse it of performance problems. It’s easy to generalise that the whole Event Sourcing is not efficient. Let’s try to do a small calculation. Let’s say we do three transactions a day, milk in the store, cigs in the newsagent’s, transfer from grandma. 3 times 365 = 1095. This number is the sum of the annual transactions. I have a bank account, which I set up at the age of 18. It is 17 years old now. 17 x 1095 = 18615, plus four days for leap years. What is this math for?

In Event Sourcing, the current state of our model/entity is aggregated by applying events one by one. For a bank account, if we have earned 1000 EUR, we add it to the account balance, if we have withdrawn 257 EUR, we subtract it, and receive the final account balance of 743 EUR. Taking the example of my account, we would have to download 5840 events and then apply them one by one? Crazy! It can’t be efficient, and it won’t!

Typically, objects in our systems do not have so many events and do not live that long. Helpdesk ticket - 2 weeks, several changes (received, verified, triaged, closed). E-commerce orders, 2-3 days and a few changes (sent, handed over to a courier, dispatched, sent to another city, etc.). Usually downloading a few simple events (even 20) is not a big deal. Most applications don’t have such high-performance needs.

However, if performance is a critical factor, then you can use some of the optimisation techniques as, e.g. snapshots. What is a snapshot? It is the state of our model at a given time, e.g.:

  • The current state of the object - it can be stored, e.g. in a relational table, where each field of the is a separate column. The other option is to store it in the form of a key-value. The key is the entity identifier, and the value is, e.g. JSON. That’s how Marten is doing - see more in https://martendb.io/documentation/events/projections/. All the document, key/value databases also apply here,
  • The state at a given point in time - e.g. the account balance at the beginning of the month, we can then get, e.g. snapshot from the beginning of the month, then get all the events that happened later and apply them,
  • The state after each transaction - then we get the history and all state changes of our model.
  • The con of snapshot is that you need to maintain it and keep the same lifetime strategies as in the regular systems, e.g. migrations.

Another option is to send a “summary event”, which will contain the state of the object for a given moment. What does it mean in practice? Even in the financial domain, data is kept with some cadence. Usually, such systems are interested in a specific period - e.g. billing period. Even financial data do not have to be kept forever - e.g. five years for invoices in Poland. Having that, we can send a “Finished Financial Year” event for the account. It will contain the current state and other needed information. After that, we’re free to and archive old events (e.g. move to another database from where we can get the full history on demand). Thanks to this we have complete information and can still keep the advantages of Event Sourcing. Take a look at an excellent description of Mathias Verras Verras with the “Summary Event” pattern - http://verraes.net/2019/05/patterns-for-decoupling-distsys-summary-event/. I also encourage you to do the exercises from my “Built your own event store Self-paced kit” https://github.com/oskardudycz/EventSourcing.NetCore/tree/main/Workshops/BuildYourOwnEventStore.

To sum up. Bank Account as an example is sufficient for a basic introduction, but it can quickly derail discussion with going to early performance optimisations. You can present those two of the potential solutions, but it can make the Event Sourcing seem more complicated than it is.

It’s also a complex domain. Explaining the boundaries and providing proper aggregates structure might be hard, e.g. how to setup aggregates (“is transaction an aggregate?”). Then next questions may appear: “How to make money transfer between accounts without updating two aggregates at once etc.”. You may end up with explaining concepts of distributed processing like Saga, Process Manager, Choreography etc. Of course, it’s valuable to explain them, but in the beginning, it may be overwhelming. Someone might get the impression that those concepts are part of Event Sourcing, while with regular approach you’ll face the same issues (if you try to model a distributed banking system).

What could be a better example? It could be a tedious but well-known Order example or Helpdesk ticket. Another one could be the meetup of a programming group. These are things that are closer to the everyday problems solved in Event Sourcing. They do not differ at all from the typical programmer’s topics. What makes Event Sourcing different from traditional programming is what Greg Young said:

“When you start modelling events, it forces you to think about the behaviour of the system. As opposed to thinking about the structure of the system.”

Do you know better examples? Or maybe you know even worse ones? Do you agree or disagree? Feel free to comment - I’d like to know your perspective!

Oskar

👋 If you found this article helpful and want to get notification about the next one, subscribe to Architecture Weekly.

✉️ Join over 11500 subscribers, get the best resources to boost your skills, and stay updated with Software Architecture trends!

Loading...
Event-Driven by Oskar Dudycz

cover

Through my window, I see the result of good plans but poor execution. Opposite my flat, there is a partially completed construction place. Buildings were supposed to be eye-catching Mediterranean style apartments. Delivery date? Two years ago. Actual? More and more unknown.

Some time ago, I heard that using Event Sourcing makes creating Event-Driven Architecture easier. The arguments were correct, that if we’re already publishing events to trigger business workflows, then at some point, we may want to also store events to not lose information. Agreed. However, I also heard that keeping the state as events will simplify things. We’ll have a source of truth with a record of the system behaviour. This will allow, e.g. to confront the results of the operations with the recorded state. I’d agree with that, with one distinction. It’s easier as long as you already know Event Sourcing.

Many people in the DDD community claim that the essential is to properly break down the system into autonomous parts called bounded contexts. Once we have it, the rest is secondary and will sort itself out. For sure.

Many seasoned programmers speak similarly about new technologies. They claim that they can translate past experience into new technologies. That’s true that by analogy, they can catch the big picture quicker. But isn’t it a bold assumption to say that Win.Forms specialist will learn Angular quickly?

The end result may differ a lot from the initial ideas. I saw the plan of those buildings next to me. Now I can see the effects of the execution. Or actually, the lack.

I believe that we should carefully acknowledge not only the point of view of our authorities but also their seating point. If we want to find out how to form a wall, do we ask an architect or a foreman? An architect may know the theory, but the practice is what we’re looking for. On the other hand, if you want to know where to put the wall, you prefer the architect to do measurements. At least if you don’t want to have the roof falling to your head.

After I had torn a ligament in my knee, I went to two qualified orthopedists. One said I should have surgery and do a reconstruction. The second stated that there is no need for that; rehabilitation should be enough. Guess which one had a specialization in surgery and which in rehabilitation?

People usually give us advice from the point where they’re currently standing. They are entitled to a biased view. An architect who rarely does programming will tend to downplay the value of implementation and tactical patterns. Midlevel developers will focus on technicalities instead of the global system impact. The team manager or consultant will emphasize the importance of soft skills (or esoteric techniques known only to them).

The truth is that we need all of them. The excellent plan will fall on the bad execution. The best execution for the wrong case will be just a waste of time. We should carefully evaluate the advice considering what we need and what an expert can give us.

Therefore, when we’re reading an article, watching a talk, let’s also pay attention to the place where the person is standing. The perspective from there may be much different from where we are right now. That can be good, as it may push us in the right direction. But it may also be misleading, as we accidentally take biases of this person without understanding the tradeoffs. Personally, I prefer to follow not only people from pedestal but also those that are closer to my position. A bit further in the journey, but not too far. That helps me to calibrate my view as those people are more relative to my daily struggles.

Polish historical leader Józef Piłsudzki reportedly used to say: “Right is like an ass, everyone has its own”.

Cheers!

Oskar