Probably, about the Event Sourcing heard everyone who at least once intersected with the theme of CQRS and DDD. This is a data storage approach, in which instead of the final result a series of records about events that have occurred with a certain entity is stored. On the Martin Fowler website there is a
detailed description , and we will focus on the foundation, the main cookies, and the problems in its application.
Foundation
Key mechanisms that just allow you to build different useful features are as follows:
- Each event is given a name that determines its value, i.e. semantics is present. Agree there is a huge difference between " Event 1 " and " Ship Sailed ".
- There are no restrictions on the number of events for the entity. Accordingly, new events can reflect, as well as new types of committed actions, and expand existing ones, say, added a new property in its 2nd version.
- The events that have occurred are unchanged (“immutable”).
"Cookies"
Naturally, once the approach is applied, it means that there is the very “IT” for which the game is worth the candle.
History of events
To begin with, Event Sourcing is a dream for those who want to remember everything “how and why”, “what and when”, happened in the system. Let's say this is a record audit, only better yet by storing the “why” information. I remembered an example that Greg Young used in one of his presentations:
')
The bank stores information about where their customers live and in one day one of the email addresses is changed. When storing information in the table, we will be able to see the maximum that the record is updated. If an audit was connected, then in general we can look at the history of all previous values. But can we find out why it has changed: maybe it was the original mistake?, And maybe the client has moved to another place? With Event Sourcing, we would be able to answer this question, because we would have 2 events: Client Moved , Fixed Addres Error .
Projections
Naturally, since all the useful information about the entity is stored in the stream of events, you cannot use it directly. For UI, we need flat models (projections), which we create using event handlers called denormalizers. A distinctive feature can be called the fact that such a handler can be changed and added, as and when you want. At any time, the projection can be "thrown out", play all the events from the beginning and the new one is ready. A small code example:
public void Consume (ShipArrived message) { readModel.Dock.Ships.Add(message.Ship); } public void Consume (ShipDeparted message) { readModel.Dock.Ships.Remove(message.Ship); }
Of course, besides the projections for the interface, the event normalization is a powerful tool for building a variety of reports and analyzing event sourced entities.
Process oriented UI
Replacing the main data store (source of Truth) with normalized data in the tables, and CRUD operations on them, with event records, pushes for changes in the design approach. It is not profitable to have events in the style of CRUD, because then all meaning is lost in their semantics and binding to what is happening. So you need to build an interface where the user performs small atomic actions on the entity. Those. interface design should be workflow driven, not data input-based.
In general, this coincides with the tendency to improve the user experience with the application and to replace multi-page instructions with hints when performing actions, i.e. learning by the application itself.
Technical points
A couple of technically interesting utilities with this approach:
- When integrated with external systems, you can send a filtered stream of events. This can simplify the task in some cases.
- Event Store can be made very fast and expandable, because events are unchanged and can only be added.
- Projections can be geo-replicated.
Problems
As you might guess, they are significant.
Hell for refactoring
So, about a miracle, our events immutable, and their flow append-only. Hm, so what does it mean? This means that any event that happened once must be
maintained forever . They can neither be canceled nor deleted. You can create new versions of events, events that compensate for errors, and these are all new and new classes that need to be added to existing handlers and carried through the entire chain of use of the entity. It is like taking away the right to make mistakes from the programmer, and no “rollback” plan to you. Is that to return the database of events to the previous snapshot, losing all user actions, unless of course you agree to this :-)
No, of course, each of us can, having become freaked out, take a sledgehammer, a puncher and go to modify the events that occurred in the repository, but this would rather resemble correcting the data in the SQL database, modifying the data and index files.
Summing up, this means that the event model must be carefully thought out, drawn, and you will not let junior / middle to it. And if events go to other components ... in general, it is necessary to distinguish between external events and internal ones at once, and also to lock their definition into a separate repository. Refer to only via NuGet.
No ready tools
Starting development using Event Sourcing, be prepared for the fact that you will have to write all the tools for working with events yourself. Of course, there is an
EventStore from Jonathan Oliver, but this is only a small part. You will need a graphical and software interface for managing them: viewing and searching, building and updating projections, creating snapshots for optimizing reading, etc.
Mutually compensating events
For example, if a user unsubscribes from the news, and then subscribes ... and so 50 times (throughout the year). As a result, there is only the current state that it is signed or unsubscribed and everything is ok. However, if you need to build a new report or projection, where this data is used, the processing of such events will uselessly take time, but it will load the machine well.
Support
Maintaining a decision on Event Sourcing is expensive and difficult. First of all, due to the considerable time at the design stage, as well as a large number of different events that are necessary to create for each specific type of operations to comply with the semantics.
findings
As one of my friends said: “We do not solve problems, but transfer them to a more comfortable plane.” You can also say about the Event Sourcing. Everyone must determine whether he is needed for a particular task or not.
I can say the following: use Event Sourcing for well-studied entities and pointwise, do not try to build the whole system on it. It is desirable when this is not the first, and maybe not the second of its implementation.