DDD & co.
In many scenarios, it makes sense to separate the writing and reading side of an application on an architectural level. While the writing side takes care of maintaining consistency, the reading side allows for extremely efficient queries.
However, synchronization is required to update the reading side after having changed the data on the writing side. In principle, the procedure corresponds to mapping domain events to conventional CRUD logic.
Along the way, the writing side can be modeled with DDD, while the reading side provides pre-calculated tables for easy
SELECT queries. These can be read efficiently, and the database behind it can be easily scaled.
One aspect, however, must not be overlooked in all this: Synchronization takes a certain amount of time, which is why the update of the reading side takes place a little later than that of the writing side. How long it takes for both sides to be consistent depends on many factors and cannot be predicted.
If several databases are used for the reading side, the problem applies equally to the individual instances: Updating the instances may take place at different speeds. This means that the same query can return two different results depending on which instance is being queried.
The behavior is referred to as eventual consistent and means that the consistency is not guaranteed at once, but rather gradually. What's important about this is that the consistency is actually guaranteed - only its timing cannot be predicted.
At first glance, this seems to be a completely useless concept, especially in the context of databases. In reality, however, the model is much closer to reality than traditional distributed transactions that enforce consistency at a given point in time.
Reality is not consistent
For example, it is common to dine in a restaurant before paying the bill. Although food is exchanged for money here, there is no transaction. Leaving the restaurant without paying doesn't undo the consumption of food.
The same applies if you order a drink in a café like a coffee to go: Usually you pay first and then wait for the drink. If you leave the café prematurely, money was paid, but no value was created: There is no transaction.
Such situations are subject to business risks. It is virtually impossible to avoid a customer boucing the coke. It is therefore important to limit the damage and assess risks in advance. However, such situations cannot be prevented technically. From this point of view, reality is not consistent.
Subject-specific solutions instead of technical ones
Technical systems often try to solve such problems technically - instead of treating them as what they are: Business risks. Those who try to solve any business risk technically waste a lot of time and money in most cases. It would be far more reasonable to solve such risks professionally.
A booking system that manages the sale of a limited number of tickets could, for example, allow overbooking in case of doubt. This could be taken into account a priori. In addition, you can also expect to have one or two cancellations typically, which will cause things to balance out.
Last but not least, it would also be possible to consider how a customer could receive fair compensation in the event of a case where participation is actually not possible despite the purchase of a ticket. Since this is an unlikely exception, the risk can be estimated and managed accordingly.
Choosing the right tool
Of course, there are scenarios for which this behavior is not acceptable. These include, for example, all applications that have a direct impact on health or life. They usually require a true transaction-based consistency. However, such applications are the exception.
As always it is important to choose the right tool for the given task. In many more cases than one would initially expect, the use of eventual consistency is a viable option. However, it requires some kind of rethinking - on the professional side, but first of all also on the technical side.