Posts tagged ncqrs
Probably the most powerful CQRS/Event Sourcing platform in .NET
Jan 15th
In the beginning… there were two awesome pieces of code: Ncqrs created by Pieter and Event Store by Jonathan… Now, let me introduce them.
Ncqrs is highly focused on popularizing CQRS and Event Sourcing ideas and, because of that, it is not tied to one particular flavor of CQRS. With Ncqrs you can as well create simple projects backed by RDBMS event store without enforcing aggregate boundaries, as highly scalable reliable solutions without the need of 2PC. The true power of Ncqrs is it’s rich model for representing aggregates. It allows automatic mapping of event handlers using conventions, attributes and via an internal DSL. Ncqrs aggregates can contain entities and nested entities (entities inside entities).
On the other hand, Jonathan’s Event Store is focused on ‘hardcore’ Event Sourcing. The learning curve is high. With Ncqrs you can really write code in the ORMish style. I don’t think you should, but if you can, you have all the facilities, like Unit of Work. You can’t do this with Event Store. This also means that you have smaller chances to create a poorly designed solution. But the feature that makes Event Store a really an awesome tool is support for processing idempotency, integrity and optimistic concurrency based on very loose semantics of most NoSQL databases.
So, why not combine the rich aggregates and asynchronous event processing engine of Ncqrs with storage options (all flavors of SQL, RavenDB, MongoDB), concurrency and idempotency of Event Store? It turned out to be a fairly simple task.
Receiving a command
My first decision was to give up the Ncqrs commanding infrastructure. I wanted to address the scenario where commands are shared resources (e.g. in the enterprise) and they are not allowed to be dependant upon particular framework like Ncqrs (which is an implementation detail of one system). This decision lead me to swap a command service for an interface like this one
public interface IRemoteFacade
{
void Execute(CommandMetadata metadata, Action<AggregateRoot> commandAction);
}
public class CommandMetadata
{
public Guid CommandId { get; set; }
public int? LastKnownRevision { get; set; }
public Guid? TargetId { get; set; }
public Type TargetType { get; set; }
}
Instead of forcing command to implement and interface defined by me (or be decorated by my attributes) so that I can handle them in an automatic way, I acknowledge that commands are autonomous beings and that it is handler’s responsibility to extract necessary metadata from the command object. So, why don’t define ICommandHandler interface like this one
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
at this level? At first I thought it would be a good idea. Then I realized that this kind of model is already implemented in most transport-level frameworks like NServiceBus. I don’t want to duplicate their functionality. I’d like transport-level handlers (e.g. IHandleMessage<T> in NServiceBus) to call my IRemoteFacade.
Processing the command
After command metadata is extracted and command is handed over to IRemoteFacade, the real processing begins. First, a new instance of aggregate of specified class is created. Then, if the command is targeted against an existing aggregate, an event stream consisting of all events from the latest snapshot up to the last known revision is retrieved. If no revision is provided in the command (which means that optimistic concurrency is disabled for particular command), event are retrieved until most recent commit.
The state of the aggregate is reconstructed using retrieved events. Then, the action provided in Execute call is invoke against the aggregate object.
The last (but certainly not least) activity is saving the state of the aggregate. Events resulting from processing the command are retrieved from the aggregate object, transformed and pushed into the Event Store. If there were optimistic concurrency violations, exception will be thrown. Also, if Event Store detected duplicate command it will signal this by throwing an exception. It is up to IRemoteFacade caller to catch this exception and (most probably) swallow it.
Integration with NServiceBus
All this stuff would be useless if commands cannot be send to the IRemoteFacade. There has to be some transport mechanism. While I don’t want to tie to a single transport, I want to support some common (in my opinion) scenarios. I decided to add NServiceBus support first.
NServiceBus has a notion of message handlers defined as IHandleMessages<T> interface. OOTB you would have to code the facade calling code by hand. To avoid duplication I prepared a special base class:
public abstract class CommandHandlerBase<TMessage, TAggregateRoot> : IHandleMessages<TMessage>
where TMessage : IMessage
where TAggregateRoot : AggregateRoot
{
public IRemoteFacade RemoteFacade { get; set; }
public IBus Bus { get; set; }
public virtual void Handle(TMessage message)
{
var metadata = ExtractMetadata(message);
if (metadata.TargetType == null)
{
metadata.TargetType = typeof (TAggregateRoot);
}
try
{
RemoteFacade.Execute(metadata, x => Handle(message, (TAggregateRoot)x));
}
catch (DuplicateCommitException ex)
{
}
}
protected abstract CommandMetadata ExtractMetadata(TMessage message);
protected abstract void Handle(TMessage message, TAggregateRoot aggregateRoot);
}
The code is straightforward. All you have to do is create your own code for extracting command metadata (or its envelope) and for invoking particular action on the aggregate root. The Handle method is also a good place to put command validation logic. Now, how can I tell NServiceBus to use all this infrastructure? It is as simple as calling one method:
_bus = Configure.With()
.Log4Net()
.DefaultBuilder()
.XmlSerializer()
.MsmqTransport()
.IsTransactional(true)
.PurgeOnStartup(true)
.UnicastBus()
.LoadMessageHandlers()
.InstallNcqrs()
.UseInMemoryPersistenceEngine()
.CreateBus()
.Start();
The additional UseInMemoryPersistenceEngine method instructs Event Store which storage engine to use.
Summary and what’s next
By combining the strongest points of Ncqrs and Event Store I believe I created the most powerful and universal tool for implementing CQRS in .NET platform. Add NServiceBus for command transport and you have a complete end-to-end solution.
The source code can be downloaded from my fork of Ncqrs on github. It is still a prototype but you can see the power it brings.
The next goal is to integrate it smoothly with asynchronous event processing engine of Ncqrs.
Ncqrs ciąg dalszy
Jun 4th
W poprzedniej notce powiedziałem wiele dobrego na temat Ncqrs. Aby być fair, tym razem chciałbym się skupić na kilku mankamentach, które udało mi się zauważyć podczas zabawy z tym frameworkiem.
Ncqrs nie jest jeszcze gotowy do wdrożenia produkcyjnego out-of-the-box. Nie ma co udawać. Biblioteka potrzebuje jeszcze trochę czasu, aby dojrzeć. Z drugiej strony, jeśli komuś zależałoby na jej funkcjonalności i bardzo chciał jej użyć, zawsze może zostać commiterem i poprawić te i owe braki. Na obecnym etapie, do pracy z Ncqrs jest wymagana bardzo dobra znajomość jej wewnętrznych mechanizmów, co czyni ją niepraktyczną w standardowych zespołach deweloperskich (poza R&D).
Serce Ncqrs, czyli definicja korzenia agregatu, jest zbudowane w oparciu o dziedziczenie — klasy aplikacji dziedziczą z frameworkowych klas bazowych. To dobre na początek, jednak wcześniej czy później przychodzi czas, kiedy trzeba przejść na model POCO. Jest on nie tylko bardziej przyjazny dla dewelopera aplikacji, ale także dla twórcy rozszerzeń.
W Ncqrs w tym momencie brakuje możliwości definiowania encji zawieranych w agregacie (poza korzeniem oczywiście). Z mojego doświadczenia wynika, że takie encje to raczej rzadkość, jednak się zdarzają. Problem w tym, że kiedy się już zdarzają, to są bardzo potrzebne.
Nie pisałem tego wszystkiego ot tak sobie. Jeśli jesteś pasjonatem oprogramowania, masz trochę wolnego czasu i chciałbyś pobawić się z naprawdę ciekawymi problemami, Ncqrs czeka na Ciebie! Pracy jest dużo, a te trzy problemy, które wymieniłem w tym poście, to tylko wierzchołek góry lodowej.
Ncqrs
May 30th
W ciągu ostatnich dwóch tygodni moją uwagę przykuł na dobre nowy framework open source — Ncqrs (witryna CodePlex Ncqrs znajduje się tutaj). Jak sugeruje nazwa, Ncqrs służy do budowy systemów w oparciu o wzorzec architektoniczny Command-Query Responsibility Separation (CQRS). To, czego nazwa nie mówi, to fakt, że Ncqrs narzuca pewną specyficzną implementację wspomnianego wzorca, a mianowicie tę opartą o technikę Event Sourcing. Na podstawie posta Grega Younga można by się czepiać, że nazwa Ncqrs nie jest zbyt trafna, ale odłóżmy kwestie nomenklatury na bok. Czym jest Ncqrs i jak to się stało, że mnie tak zafascynował?
Zasada działania
Ncqrs jest całościowym rozwiązaniem służącym do budowy systemów opartych o silny model domeny, którego stan jest przechowywany za pomocą strumienia zdarzeń. Poniższy diagram prezentuje workflow dla pojedynczego przypadku użycia w Ncqrs.
Komendy
Punktem wejścia do Ncqrs są komendy. Są to obiekty, który reprezentują żądania wykonania pewnej operacji na modelu domeny. Komendy są mapowane na operacje za pomocą rozbudowanego rozszerzalnego mechanizmu. Najprostsza implementacja mappera opiera się na dwóch atrybutach, które określają, czy dana komenda ma wykonywać metodę istniejącego obiektu (w nomenklaturze Ncqrs — korzenia agregatu), czy też tworzyć nowy obiekt. Properties komendy są mapowane (na podstawie nazwy) do parametrów wybranej metody lub konstruktora. Ostatecznie, (jeśli to konieczne) z magazynu danych podnoszony jest odpowiedni obiekt i wykonywana jest odpowiednia metoda (lub konstruktor).
Operacje biznesowe
Operacje i konstruktory obiektów są w Ncqrs wywoływane tylko za pośrednictwem komend. Ich jedynym zadaniem jest wykonanie logiki biznesowej. Nie mogą one bezpośrednio modyfikować stanu obiektu. Zamiast tego, dozwolonym mechanizm modyfikacji stanu jest zgłaszanie zdarzeń. Operacje biznesowe mogą także komunikować się ze światem zewnętrznym.
Stosowanie zdarzeń
Jak już wspomniałem na wstępie, zdarzenia są sposobem przechowywania stanu obiektów w Ncqrs. Operacja biznesowa może zgłosić jedno lub więcej zdarzeń. Dla każdego z nich framework wyszukuje odpowiedniej metody je przetwarzającej. Mechanizm ten jest oczywiście rozszerzalny, a out-of-the-box Ncqrs zapewnia dwa sposoby wiązania zdarzenia z metodą obiektu biznesowego przeznaczoną do jego obsługi: za pomocą konwencji oraz za pomocą atrybutów. Ncqrs wywołuje znalezioną metodę przekazując jej zgłoszone zdarzenie.
Przetwarzanie zdarzeń
Metoda przetwarzająca zdarzenie modyfikuje stan obiektu na podstawie danych przekazanych zdarzeniu. Tylko tyle i aż tyle. Metoda ta nie powinna zawierać żadnej logiki biznesowej (warunkowej), ani mieć jakichkolwiek skutków ubocznych (komunikacja z innymi systemami itp.).
Zapewne chcielibyście zapytać po co tyle komplikacji? Dlaczego operacja biznesowa nie może zmodyfikować stanu? Odpowiedź jest prosta. Ponieważ stan obiektów jest reprezentowany jako strumień zdarzeń przez nie wygenerowany, aby odtworzyć obiekt niezbędne jest stworzenie jego pustej instancji, a następnie przetworzenie (w kolejności!) wszystkich zapisanych zdarzeń — oczywiście za pomocą odpowiednich metod przetwarzających. Metody te są więc nie tylko stosowane do modyfikacji stanu podczas przetwarzania, ale także do odtwarzania tego stanu podczas podnoszenia obiektu z trwałego magazynu.
Dzięki takiemu podejściu systemy Event Sourcing (jak Ncqrs) zapewniają, za darmo, ślad audytowy, który ma gwarancję poprawności, ponieważ jest on wykorzystywany do budowy obiektów podczas normalnego działania systemu.
Publikowanie i denormalizacja zdarzeń
Jeśli wszystko do tej pory przebiegło prawidłowo, wszystkie zgłoszone zdarzenia są publikowane. Oczywiście, także w tym wypadku Ncqrs pozwala wymienić mechanizm publikacji zdarzeń. Domyślny wykorzystuje komunikację wewnątrz procesu, ale dostępny jest także taki, który wykorzystuje NServiceBus.
Publikowanie zdarzeń ma dwa cele. Po pierwsze, pozwala powiadomić zainteresowane systemy zewnętrzne o zmianach stanu naszego systemu. Polega to na eskalowaniu “lokalnych” (dotyczących naszego systemu) zdarzeń do statusu zdarzeń “globalnych” (mających znaczenia dla całego środowiska systemów). Stąd już tylko jeden krok do pełnej Event Driven Architecture (EDA).
Drugim celem publikowania zdarzeń jest tzw. denormalizacja, czyli aktualizacja podsystemu obsługi zapytań. Jaki podsystem? O co chodzi? Dokładny opis zagadnienia CQRS znajduej się tutaj. W tym miejscu wspomnę tylko, że systemy CQRS wykorzystują zwykle dwa osobne magazyny danych dla przetwarzania komend oraz do realizacji zapytań. Do synchronizacji tego drugiego magazynu danych wykorzystywane są właśnie denormalizatory zdarzeń. Proces denormalizacji polega na wykonaniu w bazie danych dla zapytań modyfikacji, które wynikają z opublikowanego zdarzenia. Skąd taka nazwa? Otóż zdarzenia stanowią znormalizowaną (pozbawioną redundancji) postać danych. W magazynie dla zapytań zaś, te same dane mogą mieć wiele reprezentacji, ponieważ nadrzędnym celem jest optymalizacja czasu realizacji zapytań.
Dlaczego to może działać?
Jest kilka powodów, które sprawiają, że (pozornie) szalona idea reprezentacji stanu obiektów jako ciągu zdarzeń może działać w praktyce. Oto kilka z nich:
- zapewnia darmowy, gwarantowany, ślad audytowy
- możliwość wykonywania tzw. snapshot’ów (czyli pełnych zrzutów zserializowanego obiektu biznesowego) co N zdarzeń. Dzięki temu odtwarzanie obiektu wymaga jedynie przetworzenia zdarzeń, które nastąpiły po ostatnim snapthot’cie
- w klasycznym DDD (z użyciem O/RM) podczas podnoszenia obiektu z bazy danych tak naprawdę pobierane jest wiele wierszy danych (np. za pomocą podzapytań i złączeń). W przypadku Event Sourcingu pobieranych jest kilka wierszy przechowujących zdarzenia. Oba podejścia mają więc podobną złożoność na poziomie bazy danych.
Zapraszam Was do zabawy z Ncqrs. Postaram się odpowiedzieć na wszystkie Wasze pytania.




