Czy nadmierna inżynieria CQRS nie jest?

15

Wciąż pamiętam stare dobre czasy repozytoriów. Ale repozytoria z czasem stawały się brzydkie. Następnie CQRS znalazło się w głównym nurcie. Byli mili, byli powiewem świeżego powietrza. Ale ostatnio wielokrotnie zadawałem sobie pytanie, dlaczego nie zachowuję logiki w metodzie Action Controller (szczególnie w Web Api, gdzie akcja jest rodzajem programu obsługi poleceń / zapytań).

Wcześniej miałem na to wyraźną odpowiedź: robię to w celu testowania, ponieważ ciężko jest przetestować kontroler z tymi wszystkimi niemożliwymi do wyrzucenia singletonami i ogólnie brzydką infrastrukturą ASP.NET. Ale czasy się zmieniły, a klasy infrastruktury ASP.NET są obecnie znacznie bardziej przyjazne dla testów jednostkowych (szczególnie w ASP.NET Core).

Oto typowe wywołanie WebApi: dodano polecenie i klienci SignalR zostali o tym powiadomieni:

public void AddClient(string clientName)
{
    using (var dataContext = new DataContext())
    {
        var client = new Client() { Name = clientName };

        dataContext.Clients.Add(client);

        dataContext.SaveChanges();

        GlobalHost.ConnectionManager.GetHubContext<ClientsHub>().ClientWasAdded(client);
    }
}

Mogę z łatwością przeprowadzić test jednostkowy / wykpić to. Co więcej, dzięki OWIN mogę skonfigurować lokalne serwery WebApi i SignalR i wykonać test integracji (a przy okazji całkiem szybki).

Ostatnio odczuwałem coraz mniejszą motywację do tworzenia nieporęcznych programów obsługi poleceń / zapytań i zwykle utrzymuję kod w działaniach interfejsu API sieci Web. Robię wyjątek tylko wtedy, gdy logika się powtarza lub jest naprawdę skomplikowana i chcę ją odizolować. Ale nie jestem pewien, czy robię tutaj właściwą rzecz.

Jakie jest najbardziej rozsądne podejście do zarządzania logiką w typowej nowoczesnej aplikacji ASP.NET? Kiedy uzasadnione jest przeniesienie kodu do programów obsługi poleceń i zapytań? Czy są jakieś lepsze wzory?

Aktualizacja. Znalazłem ten artykuł o podejściu DDD-lite. Wygląda więc na to, że moje podejście do przenoszenia skomplikowanych części kodu do programów obsługi poleceń / zapytań można nazwać CQRS-lite.

SiberianGuy
źródło
1
Nie widzę, w jaki sposób CQRS sprawia, że ​​wszystko jest jeszcze bardziej testowalne / jest pomocne w singletonach / kontrolerach itp. Są w dużej mierze niezwiązane. Ponadto nadal tworzysz polecenie w przykładzie (licznik?), Co jest dziwne.
guillaume31
Jeśli zachowasz swój kod wraz z kodem infrastruktury (tj. Zdobędziesz adres IP klienta), trudno go przetestować. Jeśli wyodrębnisz logikę w zapytaniu / poleceniu, będzie to o wiele łatwiejsze. Próbka kodu była nieco myląca, więc zaktualizowałem ją.
SiberianGuy
1
Zapytania i polecenia nie mają logiki. To głupie DTO. Następnie masz swoje procedury obsługi poleceń / zapytań , ale są one dokładnie takie same jak usługi aplikacji, interaktory, usługi biznesowe, nazwij je ... w kontekście innym niż CQRS. Umieszczenie logiki zastosowania / przypadku w oddzielnym obiekcie niż w sterowniku nie jest kwestią specyficzną dla CQRS.
guillaume31
Ponadto kwestia zależności Singletona od wstrzykniętej zależności jest całkowicie ortogonalna w stosunku do CQRS. Możesz mieć Kontrolera wywołującego singleton CommandHandler, który wywołuje singleton Repozytorium ...
guillaume31
1
@ guillaume31, CQRS jest bardziej kłopotliwy niż wywołania usługi repozytorium / aplikacji. Zwykle potrzebują 2-3 klas (tj. Zapytania, modułu obsługi zapytań, zapytania), infrastruktury itp.
SiberianGuy

Odpowiedzi:

17

Czy CQRS jest stosunkowo skomplikowanym i kosztownym wzorcem? Tak.

Czy to nadmierna inżynieria? Absolutnie nie.

W oryginalnym artykule, w którym Martin Fowler mówi o CQRS , można zobaczyć wiele ostrzeżeń o nieużywaniu CQRS, jeśli nie ma to zastosowania:

Jak każdy wzór, CQRS jest przydatny w niektórych miejscach, ale w innych nie.

CQRS to znaczący skok mentalny dla wszystkich zainteresowanych, więc nie należy się nim zajmować, chyba że korzyść jest warta skoku .

Wprawdzie natknąłem się na udane zastosowania CQRS, ale jak dotąd większość spraw, na które natrafiłem, nie była tak dobra ...

Pomimo tych korzyści należy zachować ostrożność podczas korzystania z CQRS .

... dodanie CQRS do takiego systemu może znacznie zwiększyć złożoność .

Moje podkreślenie powyżej.

Jeśli twoja aplikacja używa CQRS do wszystkiego, to nie CQRS jest nadmiernie inżynieryjne, to twoja aplikacja. Jest to doskonały wzór do rozwiązania niektórych specyficznych problemów, zwłaszcza aplikacji o wysokiej wydajności / dużej objętości, w których współbieżność zapisu może być poważnym problemem.

I może to nie być cała aplikacja, ale tylko niewielka jej część.

Żywy przykład z mojej pracy: stosujemy CQRS w systemie wprowadzania zamówień, w którym nie możemy stracić żadnych zamówień, i mamy skoki, w których tysiące zamówień przychodzą w tym samym czasie z różnych źródeł, w określonych godzinach. CQRS pomógł nam utrzymać system przy życiu i szybko reagować, jednocześnie pozwalając nam dobrze skalować systemy zaplecza w celu szybszego przetwarzania tych zamówień w razie potrzeby (więcej serwerów zaplecza) i wolniej / taniej, gdy nie są potrzebne.

CQRS jest idealny dla problemu, w którym kilku aktorów współpracuje w tym samym zestawie danych lub pisze do tego samego zasobu.

Poza tym, rozłożenie wzoru wykonanego w celu rozwiązania jednego problemu na wszystkie twoje problemy po prostu stworzy ci więcej problemów.


Inne przydatne linki:

http://udidahan.com/2011/04/22/when-to-avoid-cqrs/

http://codebetter.com/gregyoung/2012/09/09/cqrs-is-not-an-architecture-2/

Machado
źródło
3
Zgadzam się na wszystko oprócz części „stosunkowo skomplikowanej i kosztownej”. CQRS po prostu oddziela odczyty od zapisów. Możesz to zrobić za pomocą taśmy izolacyjnej, zerowego oprogramowania pośredniego / skomplikowanego oprzyrządowania i utrzymywania tej samej bazy danych, co wcześniej.
guillaume31
@ guillaume31, to słuszna kwestia. Myślę, że całkiem zgadza się z pomysłem z pierwotnego pytania: „w Web Api, gdzie akcja jest rodzajem polecenia / zapytania sama w sobie”. Ale czy widziałeś kiedyś próbki CQRS (najlepiej github), które nie używają osobnych klas dla poleceń i zapytań? To właśnie znajduję, gdy próbuję zobaczyć, jak inne osoby implementują CQRS w .NET.
SiberianGuy
Tak, ale to nie jest nadinżynieria. Jest to podstawowa zasada wzorca - oddzielanie zapytań od zapisów, odczytywanie modelu od modelu domeny.
guillaume31
Podejście CQRS może być zabójcze w wielu kontekstach, ale to zupełnie inna historia. Nie jest to przesada z powodu wszystkich drobnych szczegółów technicznych, które błędnie przypisujesz CQRS w swoim Q, to przesada, ponieważ nie zawsze potrzebujesz tego, co przynosi CQRS.
guillaume31
Myślę, że punkt Fowlera jest ważny tylko do pewnego momentu. Widoki SQL są jednym typem CQRS i są z nami od wieków i nikt nie mówi, że są bardzo złożone. Ponieważ istnieje wiele odmian CQRS, tj. Prognozy pozyskiwania zdarzeń, które mogą być postrzegane jako złożone w niektórych obszarach, podczas gdy w innych mogą być trywialne.
Alexey Zimarev
3

CQRS nie zastępuje repozytoriów jeden do jednego, właśnie dlatego, że jest złożonym, kosztownym wzorcem, który jest użyteczny tylko w niektórych przypadkach.

Oto, co zasługuje Udi Dahan:

Większość osób korzystających z CQRS (i Event Sourcing) nie powinna tego zrobić.

[...]

Przykro mi powiedzieć, że większość przykładowych aplikacji, które zobaczysz online, które pokazują, że CQRS są niepoprawne architektonicznie. Byłbym również bardzo ostrożny wobec ram, które poprowadzą cię w kierunku modelu CQRS agregującego root w stylu encji.

( źródło )

Martin Fowler:

[...] powinieneś być bardzo ostrożny przy korzystaniu z CQRS . Wiele systemów informatycznych dobrze pasuje do pojęcia bazy informacji, która jest aktualizowana w taki sam sposób, w jaki jest czytana, dodanie CQRS do takiego systemu może znacznie zwiększyć złożoność.

( źródło )

Wreszcie Greg Young:

CQRS można nazwać wzorem architektonicznym.

[...]

Jest to bardzo ważne, aby zrozumieć, że większość wzorów architektonicznych nie jest dobra do zastosowania wszędzie. Jeśli widzisz wzory architektoniczne w wytycznych architektonicznych, prawdopodobnie masz problem

[...]

Największą porażką, jaką widzę u osób korzystających z pozyskiwania zdarzeń, jest to, że próbują tego używać wszędzie.

( źródło )

Sklivvz
źródło