CQS i CQRS

Obowiązek kontra ewentualność

Piotr Wandycz
Dla juniorów

Gdyby na studiach ktoś powiedział mi o CQS, zaoszczędziłbym około dwóch lat z życia. Oczywiście największym problemem na początku jest, aby kod w ogóle chciał działać. Optymalizacją można zająć się później (ta, jasne). Jednak ucząc się niektórych praktyk na starcie, możemy małym kosztem otrzymać bardzo duże efekty. Przykładowo: urządzenia elektryczne działają zdecydowanie lepiej po podłączeniu ich do prądu. Dobitnie się o tym przekonałem w zeszłym tygodniu, montując dysk i zapominając o jednym z dwóch wymaganych kabli…

CQS – Command Query Separation

Dawno, dawno temu żył sobie we Francji Bertrand Meyer. Historycy IT do dzisiaj sprzeczają się, czy był to rok 1986, czy 1988, ale ów pan sformułował – a w zasadzie ogłosił wtedy – bardzo ważne prawo:

Pytanie nie powinno zmieniać odpowiedzi

Jak rozumieć tą abstrakcyjną wypowiedź? Szczerze to nie wiem, ale po poszperaniu w Internecie dotarłem do definicji prostszej, którą mój umysł był w stanie pojąć.

Każda metoda powinna być w jednej z dwóch grup:

  • Query – coś zwraca, ale nie zmienia stanu aplikacji
  • Command – zmienia stan aplikacji i nic nie zwraca

Odczyty są bezpieczne i stanowią większą część naszej aplikacji. Są one przeważnie proste do napisania oraz łatwo jest je optymalizować. Możemy tutaj skorzystać z pamięci podręcznej (cache), a także reprezentować je na różne sposoby. Z reguły ich nazwa zaczyna się od Get, przykładowo: jeśli mam metodę GetReader, mogę ją wywołać sto razy i wiem, że nic się nie zepsuje.

Komendy zawsze powinny być typu void i nie powinny nic zwracać. Dla zapisu priorytetami są bezpieczeństwo i spójność danych. Reprezentowany jest on na jeden sposób i nie ma tu zastosowania pamięć podręczna. Możemy tu stosować bardziej skomplikowane wzorce, np. transakcje. Jeśli czytelnik i jego adres byłyby zapisywane w osobnych miejscach to albo zapiszą się oba, albo jak coś pójdzie nie tak – nic się nie zapisze.

A co jeśli mamy komendę, która musi coś zwrócić? Prawdopodobnie nie musi, choć jest to dla nas bardzo wygodne. Jeśli złamiesz tę zasadę raz, złamiesz ją później po raz kolejny i kolejny. Nawet gdy będzie to jedynie zwrócenie Id nowo utworzonego obiektu. Potem dorzucisz tylko nazwę, przecież Id i nazwa to podstawa. A jak już zwraca dwa pola, to czemu nie trzy? Klasy zaczną puchnąć i coraz trudniej będzie wprowadzać zmiany w kodzie. Zamiast małych metod, zaczniemy tworzyć odpowiedzialne za więcej niż jedną rzecz. Każdy z nas to robił i widział.

CQRS – Command Query Responsibility Segregation

O ile CQS odbywa się na poziomie projektowania pojedynczej klasy, to CQRS idzie nieco dalej i robi osobne ścieżki w warstwie infrastruktury aplikacji. Autorstwo, bądź rozpowszechnienie tej koncepcji, przypisuje się dwóm panom, a są to: Greg Young i Udi Dahan. Spopularyzowali ową ideę na początku obecnego stulecia.

CQS pomaga pisać kod łatwiejszy w utrzymaniu. Przedstawione powyżej rozwinięcia definicji odczytów i komend miały za zadanie ukazać Ci jak bardzo różnią się od siebie te dwa elementy. Skoro mają mało części wspólnych, to robiąc podział na poziomie infrastruktury – jesteśmy w stanie poprawić wydajność. Te kroki trzeba przechodzić po kolei, nie nauczysz się wszystkich dobrych praktyk poprzez jeden projekt. Najpierw zrób tak, aby działało. Później popraw łatwość utrzymywania, a na końcu wydajność.

Nie ma jednej drogi do zaimplementowania CQRS. Na pewno w podstawowej wersji nie wymaga on dwóch baz ani Event Sourcingu. O tym jak ja podszedłem do tego tematu, będę Cię informował w kolejnych wpisach. CQRS nie jest architekturą i nie nazwałbym też go wzorcem projektowym. Istnieją za to wzorce ułatwiające jego implementację, o których także niedługo będę pisał.

Zagrożenia

Mało jest w życiu rzeczy jednoznacznie dobrych. Nie inaczej jest w przypadku CQRS. To prawda, że pomaga nam pisać zoptymalizowany kod, używający różnych modeli do odczytu oraz zapisu, dzięki czemu łatwiej go później rozszerzać. Implikuje to wolniejsze dostarczanie funkcjonalności na początku naszej pracy, chociaż później jest szansa, że ten koszt się zwróci. Należy zadać sobie pytanie: “Czy możemy sobie na to pozwolić?”. Osobiście stosowałbym CQS w miejscach, gdzie mamy stuprocentowy CRUD, a CQRS w reszcie systemu. Przy startowaniu projektu mamy dużo czasu, a później zaczyna go brakować i to CQRS może nas wtedy uratować.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *