Posts tagged DDDSample

DDDSample 0.7

0.7 release of DDDSample is there. Go, download it, and say if you like it. There are now really five different versions in the package:

  • Classic with synchronous communication
  • Classic with asynchronous communication via NServiceBus (these two can be switched using compilation target)
  • CQRS using two NHibernate relational sores
  • CQRS using with relational store based on LINQ 2 SQL (not available as binary installation package, only in trunk)
  • Event Sourcing with CQRS

I really would like to hear you opinions on where the project should go now? Do you think it is finished and contains all the things it should contains? What needs to be done? What should be done first?

Installation is dead-simple when using default SQLite database, so don’t be afraid. If you have any problems, feel free to contact me via e-mail or twitter.

VN:F [1.9.22_1171]
Rating: 5.0/5 (1 vote cast)

Raportowanie a CQRS

Zdaję sobie sprawę, że tytuł jest ogromnym skrótem myślowym. Tak naprawdę chodzi mi o możliwość generowania raportów z rozwiązań wykorzystujących model domeny z CQRS. Oczywiście, posłużę się przykładem DDDSample. Na wstępnie jednak muszę się przyznać, że nie jestem ekspertem od business intelligence, więc jeśli popełniłem jakieś karygodne wykroczenia, proszę o wyrozumiałość i zgłoszenie poprawek w komentarzach — będę wdzięczny za wszelkie uwagi.

Problem wygląda następująco: nasz system transakcyjny działa świetnie, jest wydajny, bezpieczny itp. Nadszedł jednak czas, aby wygenerować z niego jakiś raport potwierdzający, że system się sprawdza biznesowo. Jak to zrobić, mając po stronie komend silnie znormalizowaną bazę zoptymalizowaną dla operacji update/insert, a po stronie zapytań — tabele odzwierciedlające formatki UI? Są dwie możliwości:

  1. Zmodyfikować bazę strony zapytań, aby stała się prawdziwą “bazą raportową”. Dzięki temu będzie mogła służyć i do generowania raportów i do wyświetlania danych na formatki. Niestety konsekwencją tego jest znaczne zwiększenie skomplikowania kodu dostępu do danych dla formularzy i list. Dlaczego? Zaraz zobaczymy.
  2. Dodać kolejną (3!) bazę danych zoptymalizowaną pod kątem raportów. Minusem jest, jak zwykle, zwiększony wysiłek ze strony administratorów. Plus (również jak zwykle): lepszy podział odpowiedzialności i możliwość optymalizacji.

Spróbujmy więc zrealizować to drugie rozwiązanie. Na początek potrzebujemy struktury bazodanowej, która nadawałaby się do generowania raportów. Oczywiście, w rzeczywistej sytuacji zapytalibyśmy naszego klienta, jakich raportów potrzebuje. Niestety nie mam takiej możliwości pisząc te notkę. Przygotowałem więc schemat, który wydaje mi się użyteczny:

Pozwala on na analizę towarów pod kątem zmian rzeczywistej trasy w stosunku do tej zarejestrowanej i ich wpływu na dostarczenie towaru. Z drugiej strony umożliwia także analizę samych tras: którędy prowadziła, czy wynikiem było złe skierowanie towaru, czy została porzucona (zmieniona), czy też w wyniku jej realizacji towar został dostarczony.

Na pierwszy rzut oka widać, że transformacja tak przechowywanych danych do formatu niezbędnego do wyświetlenie na formatkach byłoby bardzo trudna. Utwierdza mnie to w przekonaniu, że (tym razem) słusznie wybrałem wariant drugi (osobne bazy).

Mając już strukturę danych, zastanówmy się, czego potrzebujemy, aby ją zasilić? Z pomocą przychodzi nam naturalna właściwość tego rodzaj systemów CQRS. Są one naturalnie przystosowane do scenariuszy real-time business intelligence, ponieważ posiadają wbudowany mechanizm wypychania danych z bazy transakcyjnej w czasie rzeczywistym (służący do zasilania bazy dla zapytań). Możemy się więc w niego bezwstydnie wpiąć. Potrzebujemy jedynie czterech obiektów obsługi komunikatów dla zdarzeń:

  • zarejestrowano towar (utworzenie obiektu w CargoFacts i RouteFacts)
  • przypisano trasę (aktualizacja RouteFacts)
  • zmieniono lokalizację docelową (utworzenie obiektu w RouteFacts, modyfikacja reprezentującego poprzednią trasę)
  • zarejestrowano zdarzenie obsługi (aktualizacja rzeczywistego miejsca załadunku towaru i miejsca dostarczenia towaru, aktualizacja pola “misdirected” itp.)

Implementacje możemy wykonać (znów) na dwa sposoby: albo bezpośrednio przygotowując odpowiednie komendy SQL, albo mapując przedstawiony model na obiekty. Co kto woli.

PS. Zamierzam spróbować zaimplementować przedstawione rozwiązanie. Jak tylko mi się uda, podzielę się z Wami wynikami eksperymentu.

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

DDDSample documentation update

I have just published some new documentation pages on DDDSample.Net CodePlex site. You can now read about Domain-Driven Design elements in context of class diagrams, compare CQRS approach to the classic one and read on how Event Sourcing influences the model.

VN:F [1.9.22_1171]
Rating: 5.0/5 (1 vote cast)

O usługach

Zostałem niedawno zapytany, dlaczego w projekcie DDDSample.NET projekt “Application” nazywa się właśnie tak, a nie “Domain Services”. Zwróciło to moją uwagę na całkiem spory problem nazewnictwa związanego z DDD oraz ogólnie z architekturami. Jednym ze źródeł problemu zdaje się być niesamowicie przeładowane znaczeniowo słowo “usługa”. Ale po kolei…

Wspomniany projekt “Application” zawiera fasadę Modelu Domeny udostępniającą operacje biznesowe realizowane za pomocą tegoż modelu. Te operacje to coś w rodzaju transaction script-ów operujących na obiektach domeny. Nazwę zaczerpnąłem oczywiście wprost z Java-owego oryginału, którego dokumentacja tak opisuje ten element architektury:

The application layer is responsible for driving the workflow of the application, matching the use cases at hand. These operatios are interface-independent and can be both synchronous or message-driven. This layer is well suited for spanning transactions, high-level logging and security.

The application layer is thin in terms of domain logic – it merely coordinates the domain layer objects to perform the actual work.

Przyznam szczerze, że nazwa “Application” nie jest najszczęśliwsza na świecie, bo tak na dobrą sprawę, nie mówi nic o przeznaczeniu tej warstwy. Można ją znaleźć także w innych przykładach, np. w architekturze cebulowej Jeffreya Palermo. Różnica polega jednak na tym, że u Palermo nazwa brzmi “Application Services”, co niesie już ze sobą jakieś znaczenie — mamy do czynienia z usługami.

No właśnie. Dlaczego pisałem na wstępie, że winne jest słowo “usługa”? Ponieważ tak naprawdę ja najchętniej z “Application Services” zostawiłbym “Services” jako nazwę mojej warstwy. Zauważcie, że pasuje ona o wiele lepiej pasuje do przytoczonego opisu. Niestety usługi występują już w tylu kontekstach w naszej terminologii, że wprowadzenie kolejnych “usług” byłoby niewskazane.

Być może lepiej byłoby w ogóle zrezygnować z terminologii wywodzącej się z “Application Services”? Można się odwołać np. do tego, że warstwa ta implementuje przypadki użycia i nazwać ją “Use Cases”. Albo, podchodząc do problemu od strony technicznej, zauważyć że jest to implementacja wzorca fasady — “Model Facade”. A jak Wy nazywacie projekty takiego rodzaju w swoich architekturach?

Druga część pytania dotyczy domain services — usług modelu domeny. Wydaje się, że jest jeszcze wiele wątpliwości związanych z usługami w Domain Driven Design. Moje rozumienie tego termin jest następujące.

Usługi modelu domeny pozwalają wyrazić operacje, które nie mają naturalnie przypisanego obiektu wykonującego je lub są realizowane przez obiekty zewnętrzne w stosunku do modelu. Na przykład IPricingService to usługa zwracająca ceny produktów na podstawie danych uzyskanych z innego systemu za pośrednictwem webserwisu. Na poziomie modelu reprezentowana jest przez interfejs, aby nie uzależniać go od szczegółów implementacyjnych.

Osoba, która zadała mi pytanie rozumiała usługi domenowe jako sposób na wykonanie pewnych bardziej skomplikowanych operacji biznesowych poprzez orkiestrację wywołań na obiektach modelu, czyli… dokładnie to, co u mnie kryje znajduje się w warstwie “Application”. Podobne opinie znalazłem też na kilku znanych blogach, np. tu. Cóż, nie zgadzam się z takim podejściem. Nie widzę sensu, aby definiować takie byty. Co więcej, usługi domenowe w takim znaczeniu miałyby bardzo niebezpieczną tendencję to wysysania logiki biznesowej z obiektów modelu.

Podsumowując, w dużym skrócie i uproszczeniu:

  • Następnym razem napewno nazwę swoją warstwę “Application” inaczej. Skłaniam się ku “Use Cases”.
  • Usługi domenowe mogą reprezentować albo operacje nie posiadające wykonawcy (algorytmy), albo być abstrakcją dla synchronicznych usług implementowanych na zewnątrz. Oba przypadki powinny być bardzo rzadkie.

The application layer is responsible for driving the workflow of the application, matching the use cases at hand. These operatios are interface-independent and can be both synchronous or message-driven. This layer is well suited for spanning transactions, high-level logging and security.

The application layer is thin in terms of domain logic – it merely coordinates the domain layer objects to perform the actual work

VN:F [1.9.22_1171]
Rating: 3.5/5 (4 votes cast)

Event sourcing in DDDSample: reviewing Mark Nijhof’s solution

As CQRS version of DDDSample is getting mature, I am switching my development efforts to event sourcing support. For those of you who don’t know that yet, event sourcing is a pattern which encourages persisting not snapshots of data in particular moments in time, but rather events which describe how these data changes. Then, data snapshots (not only the latest, but also historic ones) can be reconstructed by applying these events starting from the ‘beginning of time’. More about defining event sourcing and CQRS can be found here.

I’ve started by looking at Marc Nijhof’s excellent series of posts (starting here) describing event sourcing. Mark has built a sample application based on what he had learnt about CQRS during Greg Young’s course.

Mark’s solution is fairly simple. In the core there is a domain assembly containing classes that model domain concepts like Account and Client. These inherit and use additional infrastructure assemblies which provide event sourcing features.

One thing that looks odd to me is usage of memento pattern to store snapshots of aggregates. I don’t understand why can’t they (the aggregates) be simply serialized as they are. Maybe there is a reason behind this, but I don’t see it, at least for now. I marked this area for further investigation.

Moving away from the core, there are several supporting assemblies which contain commands, command handlers, events and so on. Personally, I don’t see a point in separating some of them. There is an obvious reason why commands and command handlers are in separate assemblies, but the events? They are part of the domain model, at least for me.

After more careful analysis I noticed that there is no notion of messages in Marks sample solution. The events themselves are passed from command side to query side. That is probably the reason why the events are defined in separate assembly — if they are to be used in reporting, it would be nice not to have to reference whole domain model assembly, only the events.

Going further, Mark is using a custom O/RMish solution to implement query/reporting side. I am not a big fan of custom solutions and I probably would use an off-the-shelve one, even if it is slightly more complex then necessary. I am planing to use NHibernate, as in the non-event-sourcing CQRS version.

Anyway, Mark did great job of describing event sourcing concepts to the public. I probably wouldn’t be able to start writing my own implementation in DDDSample without first reading his code. Thanks a lot!

VN:F [1.9.22_1171]
Rating: 3.7/5 (3 votes cast)