Assuming Stack Overflow domain problem and the following definition of events:
UserRegistered(UserId, Name, Email) UserNameChanged(UserId, Name) QuestionAsked(UserId, QuestionId, Title, Question)
Assuming the following state of event store (in the order of appearance):
1) UserRegistered(1, "John", "[email protected]") 2) UserNameChanged(1, "SuperJohn") 3) UserNameChanged(1, "John007") 4) QuestionAsked(1, 1, "Help!", "Please!")
Assuming the following denormalized read model for questions listing (for the first page of SO):
QuestionItem(UserId, QuestionId, QuestionTitle, Question, UserName)
And the following event handler (which builds denormalized read model):
public class QuestionEventsHandler { public void Handle(QuestionAsked question) { var item = new QuestionItem( question.UserId, question.QuestionId, question.Title, question.Question, ??? /* how should i get name of the user? */); ... } }
My question is how can i find the name of the user who asked a question? Or more common: how should i handle events if my denormalized read model requires additional data which is not exists in the particular event?
I've examined existing samples of CQRS including SimpleSQRS of Greg Young and Fohjin sample of Mark Nijhof. But it seems to me that they are operate only with data that is included in events.
Solution. The Event Sourcing pattern defines an approach to handling operations on data that's driven by a sequence of events, each of which is recorded in an append-only store.
A read model is a model specialized for reads, that is, queries. It takes events produced by the domain and uses them to build and maintain a model that is suitable for answering the client's queries. It can draw on events from different aggregates and even different types of aggregate.
CQRS is implemented by a separation of responsibilities between commands and queries, and event sourcing is implemented by using the sequence of events to track changes in data.
Event sourcing has several benefits: It solves one of the key problems in implementing an event-driven architecture and makes it possible to reliably publish events whenever state changes. Because it persists events rather than domain objects, it mostly avoids the object‑relational impedance mismatch problem.
Personally I think there's nothing wrong with looking up the user's name from within the event handler. But if you're in a position where you can't query the name from the User's read model then I'd introduce an additional event handler to QuestionEventsHandler, to handle the UserRegistered event.
That way the QuestionEventsHandler could maintain its own repository of user names (you wouldn't need to store the users email). The QuestionAsked handler can then query the user's name direct from it's own repository (as Rinat Abdullin said storage is cheap!).
Besides since your QuestionItem read model holds the user's name, you would need to handle the UserNameChanged event within the QuestionEventsHandler as well to ensure the name field within the QuestionItem is up-to-date.
To me this seems less effort than 'enriching the events' and has the benefit of not building dependencies on other parts of the system and their read models.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With