I recently ended up in a discussion on when Event Sourcing is the right architecture style or not. As the universal answer to this question tends to be "it depends", I started thinking about the typical problems where I would use Event Sourcing. I came up with a couple of them, some more functional and some more technical. Here's a summary of those thoughts.
- Auditing; Since the truth behind the domain in Event Sourcing are the domain events, they form a natural and unambiguous log of what happened exactly in time. Although this is often used as one of the USPs of Event Sourcing, I don't think it is a very strong one. Most databases already provide some kind of change log out of the box, even though they are often much more technical compared to the business intent typically captured by domain events.
- Replaying production issues; Imagine your domain has complicated or dynamically toggleable business rules and you want to be able to replay the exact steps that happened during that production issue. This is where Event Sourcing shines. You just replay the events one by one and see how that affects the state of the domain every step of the way. And this is not just a theoretical idea. We really solved several production issues that we would have never solved without Event Sourcing.
- Collaborative domains; A lot of software systems have a domain where it's not very common that multiple users act on the same domain objects at the exact same time. Using optimistic concurrency where a version number is used to detect concurrent updates is often enough. But in a domain where this is no longer acceptable, even if it exists out of small entities, Event Sourcing provides a unique solution: event merging.
With this, you can compare the domain events that two users triggered concurrently, and based on functional rules decide on whether they really are in conflict. And you can be pretty smart about it. Some events may use simple policies like last/first-one-wins, but others may use a more sophisticated algorithm. Event merging is the perfect opportunity to get some deep involvement from the Product Owner.
- Apply new rules on existing data; In financial systems it is common that regulations change often, or rules that get effectuated at a certain point in time. The ability to determine what value changed when and why is incredibly useful. If rules change, you have at least two options to deal with this. You could append new events to compensate for the changes caused by the new rules and regulations. But you can also leave the events as-is, and just project the historical data in a different way.
- Temporal analysis; Closely related to the above is the ability to base decisions on the entire history of how that data came to be. Rather than just the what, you will also get the who, the why and the when. Of course, all of that provided you have been scoping your events at a size that ensures they convey the business intent of the users (provided you have been adopting the language of the business domain).
- Replication; A group of events happening at the same time on the same entity are the perfect unit for replicating data between multiple systems, each having their own event store. Even better, if you make that a bi-directional thing, you'll end-up with the perfect solution for synchronizing data between cloud-based and (occasionally connected) on-premise instances of your systems. And if it is to be expected that the same entities will be modified across those systems you can combine that with event merging.
- Out-of-place upgrades; Similar to the replication problem, you can also incrementally build a clone of the event store side-by-side with the original event store while the original system is still in operation. Determining the delta between the two stores is quite trivial, so it's relatively easy to employ this in a fully automated blue/green deployment with practically no down-time. Just keep copying the events from the old to the new event store until the new one caught up, bring the old system down, copy the remainder of the events and then bring the new one on-line. You can even inject the upconverters so that the new system doesn't need to handle the old events.
- Off-line editing in a PWA; You could debate whether this is really Event Sourcing, but several developers have used it as a technical solution to implement off-line editing in a Single Page Application. They store the off-line modifications as events in a front-end store such as Redux, and then, when the connection is reestablished, forward them to some HTTP API. And just like with the replication problem, they can employ event merging to handle conflicts caused by different users.
- Scaling out the read side; Event Sourcing doesn't require CQRS (Command Query Responsibility Segregation), but they can be a very happy marriage. It allows you to scale out the read models you will build from the domain events in completely different ways than you would scale out the write side. You can build highly optimized projections using whatever database technology you prefer. Whether it is a plain old RDBMS database, a NoSQL solution, Elastic Search or some kind of cloud-native solution, you can use whatever gives you the best results. You can go even further by making this projection building asynchronous from the writes and combine that with sharding or partitioning to improve the performance and scalability to the next level.
- Cross-domain communication; Domain events are specific to the domain and should never be used as an integration layer or exposed to other modules or subsystems. But to support cross-domain or cross-system communication, it isn't very difficult to project those fine-grained events into a new "event" store containing coarse-grained events. You can then safely publish those well-defined and versioned events on some kind of message bus or to implement a webhooks mechanism that subscribes on those events.
I guess it should be clear by now that Event Sourcing can solve a lot of different functional and technical problems. But it doesn't come for free. Just like every architectural style, it has pros and cons. Event Sourcing is not a top-level architecture. Every module or (sub)domain in the system can use a different architecture style given its purpose and requirements. In other words, even if you recognize yourself in one of the problems above, you don't have to use Event Sourcing everywhere. Nonetheless, given I've experienced a lot of those pros and cons first-hand, I feel quite comfortable with it and have made it my first choice for rich domains.