I'm currently evaluating Event Sourcing and CQRS for an implementation of a new business requirement at my day job. While I can't really speak about the actual business problem, I can give a few reasons for why we think that Event Sourcing might be a good fit:
- great auditing capabilities based on the history of events
- "travelling back in time" to recreate a previous state of an aggregate (e.g. for debugging purposes)
- the ability to create new projections that take the full history into account
Since I can't go into detail about the exact domain we're in, I will describe my problem using the domain described in this Kata dealing with quiz games.
I think I got the general idea of Event Sourcing and how CQRS links to it. However, all examples I can find use domains with clear separations between aggregates as well as between different instances of the same aggregate (in the Kata mentioned above, quizzes and games have a clear relationship. There's no interdependence between different quizzes or different games).
The problem
In my case I have the problem that it must be possible to merge different instances of the same aggregate (in our sample domain this could mean that it must be possible to merge different quizzes together into one quiz) as well as undoing this merge later on (reconstructing the two original quizzes from the merged one).
This constraint adds quite some complexity when it comes to constructing the current state of an aggregate, because it's necessary to read the whole event stream from the beginning to be sure that all relevant events are taken into consideration. It's not possible to partition the event stream in a useful way because it's impossible to tell which aggregates will be merged later in the future. It might even be a problem when the event stream gets partitioned, because the temporal order of related events gets lost.
From what I understand, partitioning the event stream allows for a fast provision of the events that are necessary to build up the current state of an aggregate. For instance, if I want to know the current state of the quiz with ID 124ecf
, I technically could filter the event streams to just have the events for this exact ID which would drastically reduce the number of events. If this is not possible, like in my case, reading the event stream ad hoc to recreate the state of an aggregate will become very slow and impractical over time.
The solution I came up with so far
The only solution for this problem that seems to be possible to me is to work with rolling snapshots for all necessary projections. The snapshots would update themselves continuously, building up a state optimized for their specific use case (processing commands, answering queries etc.).
I'm skeptical about this idea, because it requires quite some effort. Most of the implementations of typical applications don't require rolling snapshots for most use cases because building up the desired state from the event stream is fast enough. This simplicity is lost in my case.
The question
My question could be split up in several parts:
- Is it a good idea to use Event Sourcing for domains like these where it's not possible to draw clear boundaries between different instances of the same aggregate?
- Does it make sense to heavily rely on using rolling snapshots to get the desired performance?
- Is there another way other than rolling snapshots to implement this?
- I can't think of a way for partitioning the event stream. Am I missing something? Are there some techniques that allow partitioning/sharding under the given circumstances?