DTO vs CQS
Dzisiejsza notka jest wolnym tłumaczeniem jednej z poprzednich, którą opublikowałem in English. Ilość informacji na ten temat w polskim internecie jest tak znikoma, iż wydaje mi się, że każda notka jest ważna.
Pomijając historię, jak udało mi się dość do moich wniosków, chciałbym zaprezentować rzetelne porównanie podejść DTO oraz CQS w kontekście udostępniania informacji na potrzeby interfejsu użytkownika.
DTO
Wzorzec DTO polega na zdefiniowaniu, dla każdego obiektu Modelu Domeny, obiektu Data Transfer, który
posiada wszystkie dane obiektu Modelu, ale
nie posiada zachowania. Jest to kontener na dane, który może być przekazywany między warstwami.
[Edit]
Jak słusznie zauważył , powyższa definicja to jedna z form wzorca DTO. Inna, zupełnie legalną, formą jest jeden (lub dwa: input oraz output) obiekt DTO dla każdej operacji udostępnianej przez fasadę modelu. Poniższe rozważanie
nie dotyczy obiektów DTO przeznaczonych do przenoszenia argumentów wejściowych operacji, a jedynie tych, które służą do
transportu wyników zapytań.
[/Edit]
DTO są zwykle tworzone za pomocą wzorca
DTO assembler, czyli specjalizowanej klasy, która przepisuje dane z obiektu Modelu do obiektu DT.
Assembler może być zastąpiony tzw. object/object mapperem (np.
AutoMapper) analogicznie, jak ręcznie napisany DAL może być zastąpiony O/RM-em.
Poniższy rysunek przedstawia schemat interakcji z modelem domeny, eksponowanym za pośrednictwem aplikacji WWW, składający się z dwóch faz: pobranie danych na GUI (pierwsze żądanie) oraz wykonanie operacji biznesowej (drugie żądanie). Wyraźnie widoczne są trzy fazy transformacji danych.

Legenda:
- Strzałka z pustym grotem - przepływ sterowania
- Strzałka z pełnym grotem - przepływ danych
- Bloczek niebieski - transformacja danych
- Bloczek źółty/pomatańczowy - relacyjna baza danych
- MD / MDZ / MDK - model domeny / model domeny dla zapytań / model domeny dla komend
CQS
Na temat definiowania CQS w kontekście architektury
pisał sporo Greg Young, więc nie będę odkrywał koła na nowo. W naszym kontekście istotą CQS jest wydzielenie dwóch modeli: modelu dla komend oraz modelu dla zapytań. Model dla komend realizuje logikę biznesową. Jest, z grubsza, taki sam, jak ogólny model w wypadku użycia DTO. Obiekty modelu dla komend nie muszą jednak eksponować publicznie swoich danych.
Model dla zapytań zawiera klasy reprezentujące obiekty domeny w kontekście zapytań. Są to, podobnie jak w wypadku DTO, klasy pozbawione zachowania. Różnica polega na tym, że obiekty tych klas nie są one budowane na podstawie obiektów modelu dla komend, ale bezpośrednio na podstawie bazy danych (np. w wykorzystaniem biblioteki OR\M).
Poniższy rysunek przedstawia analogiczny (do tego z DTO) schemat interakcji. Tym razem widoczne są tylko dwie transformacje. Trzecia, ukryta, wykonywana jest na etapie synchronizacji danych.
Porównanie
Oba podejścia wymagają utrzymywania dwóch równoległych zestawów klas opisujących obiekty domeny. Oba również wymagają stworzenia logiki tworzącej obiekty DTO lub obiekty modelu dla zapytań. Ilość kodu wymagana do realizacji obu rozwiązań jest więc porównywalna.
Na tym podobieństwa się kończą. Wszelkie inne kwestie przemawiają na korzyść CQS:
- CQS lepiej przygotowuje aplikację do skalowania, ponieważ umożliwia przeźroczyste dla kodu rozdzielenie baz danych stojących za modelami i realizację replikacji z bazy transakcyjnej (model dla komend) do bazy raportowej (model dla zapytań)
- CQS (przy założeniu rozdzielenia baz) pozwala zoptymalizować obie bazy pod kątem operacji na nich wykonywanych (insert/update vs select)
- CQS daje większą swobodę w tworzeniu GUI, ponieważ obiekty modelu dla zapytań mogą znacznie różnić się od obiektów modelu dla komend.
- CQS skutkuje o wiele czystszym modelem logiki biznesowej, ponieważ klasy modelu dla komend nie są "zaśmiecone" kodem spełniającym wymagania warstwy prezentacji
Podsumowując,
CSQ kosztuje tyle samo, a daje znacznie większe możliwości.
Dlaczego miałbym więc wracać do DTO?