In this meeting Russell introduced us to Martin Fowler and the concept of Event Sourcing.
Martin Fowler seems to focus on code refactoring, design patterns and automated testing.
Event Sourcing can be summarized as the process of recording changes to an application state as a sequence of events.
Russell walked us through a code example which demonstrated a book being added to a library, borrowed and returned. The process started with the creation of a session factory and event handler registration. The session is to ensure the operation was fully successful, similar to a database transaction. The handlers were to do any extra business logic, similar to database triggers.
In this example the session was opened a book is created a book is added to a book repository The session was closed
Because a BookStateHandler was already registered with the DomainEvents it is called when the session is committed.
In this case the event contain book attributes. This is similar to
(sender, e) where e contains all the meaningful parameters to avoid changing the signature. Before calling Append to queue the event, the Book constructor calls Apply. Apply copies the BookRegistered event arguments into the Book object, similar to an UPDATE statement.At this point the event is in the queue and the book object is fully initialized. The only thing left is to commit the changes via
session.SubmitChanges().The commit process results in publishing (invoking) the queued events. The actual implementation was bogus, I would have liked to seen something maintenance free:
if (@event is BookRegistered)
DomainEvents.Raise((BookRegistered)@event);
if (@event is Event_Sourcing.BookRegistered.BookLent)
DomainEvents.Raise((Event_Sourcing.BookRegistered.BookLent)@event);
if (@event is Event_Sourcing.BookRegistered.BookReturned)
DomainEvents.Raise((Event_Sourcing.BookRegistered.BookReturned)@event);
The BookRegistered handler adds the event arguments to a book state query collection. This is not the same as the event queue. It is a data repository containing the current state of the book object. It could be DataTable with the book represented with a DataRow.
My Thoughts
There is a strong decoupling between the entity (Book), the event arguments (BookRegistered) and the captured state of the book (BookState). In this example the decoupling introduces much redundancy. Notice the duplicate members across these three classes:
public Book(BookId id, string title, string isbn)
{
this.id = id;
var @event = new BookRegistered(id, title, isbn);
Apply(@event);
Append(@event);
}
public BookRegistered(BookId id, string title, string isbn)
{
Id = id;
Title = title;
Isbn = isbn;
}
public class BookState
{
public BookId Id { get; set; }
public string Title { get; set; }
public bool Lent { get; set; }
}
I would have liked an explanation as to why Book, BookRegistered, BookState did not all reference a fourth object which actually defines the Id, Title and Lent status. I can speculate that it is because in larger projects there becomes a divergence in attribute space among these three classes.
Conclusion
Event Sourcing as presented in the example showed straight-forward transactional code with the details pushed into the event handlers. The book event history and the book state were maintained separately. Based on the definition of Event Sourcing I presume the events would be persisted to permanent storage before allowing the transaction to complete. Likewise I presume the state might be periodically persisted with a replay identifier to avoid parsing the entire event history to recreate the book state.
Additional Thoughts
In this simple example it would be possible to parse the event history backwards until the book state is fully realized. The additional logic may likely result in a performance gain when recreating the state but is likely too complex for real-world object. Simpler to persist.
Looks like Russell summarized this article:
ReplyDeletehttp://thinkbeforecoding.com/tag/Repository
For me an easier to read introduction to Domain Events is here with a nice closing thought:
ReplyDeleteIn working with your domain experts or just going through a requirements document, pay less attention to the nouns and verbs that Object-Oriented Analysis & Design call attention to, and keep an eye out for the word “when”. It’s a critically important word that enables us to model important occurrences and state changes.