Dziś znów powrót do podstaw inżynierii oprogramowania. Przedstawianie podstawowej zasady może wydawać się śmieszne ale mimo wszystko programista dobrze jak wie, że taka zasada ma swoją nazwę i naprawdę powinno się tego przestrzegać. Za pewne wiele programistów nie zna nazw tych reguł ale i tak postępuje zgodnie z nimi. Post ma jednak uświadomić, że takie praktyki są dobrze udokumentowane i są na naprawdę dobrym zwyczajem a nie tylko intuicją doświadczonego programisty.
Wzorzec dotyczy konstrukcji metod – każda metoda powinna być “komendą (command)” lub “zapytaniem (query)” ale nigdy jednocześnie i komendą i zapytaniem. Pozostaje wyjaśnić czym się różnią te dwa twory? Komenda to polecenie zrobienia czegoś – np. zapisu danych do bazy danych. Zapytanie to zwrócenie danych. Innymi słowy, nie powinniśmy tworzyć metod, które zarówno wykonują jakaś logikę, zmieniając tym samym stan obiektu, bazy danych jak i które zwracają na końcu dane. Według CQS lepszym podejściem jest rozdzielenie tego na dwie metody.
Uważam, że zasada bardzo dobra ale czasami jest wręcz anty-wzorcem. Pierwszy przykład to programowanie współbieżne, gdzie należy unikać częstych lock’ow i z tego względu lepiej skorzystać z bardziej rozbudowanej ale jednej metody. Drugi przykład to warstwa usług, która eksponuje warstwę biznesową. Fasada sama z definicji gromadzi szeroką funkcjonalność w jednej metodzie. Tworząc usługę sieciową lepiej aby jedno zapytanie zrobiło tyle co trzeba zamiast wysyłać kilka pojedynczych zapytań – interfejs warstwy usług nie powinien być “chatty”. Operacja na stosie POP (zdjęcie obiektu) jest klasycznym przykładem łamiącym CQS ale mimo wszystko jest to dobre podejście.
CQS przede wszystkim daje przejrzyste API – wiadomo, które metody zmieniają stan obiektu i prawdopodobnie kilkakrotne ich wywołanie może spowodować jakieś efekty uboczne.
Ogolnie rozdzielenie fizyczne warstw, np. za pomoca servisow psuje nasze interfejsy I kladzie czesc wzorcow 🙂
Napisałeś “Uważam, że zasada bardzo dobra ale czasami jest wręcz anty-wzorcem. ” moim zdaniem coś takiego nie występuję. Zasady mówią o pewnych praktykach, które fajnie by było stosować, ale nie nakazują jej stosowania! Dlatego jeśli użyjesz zasady w sposób nie właściwym to błąd leży po stronie człowieka.
A co z zasada nazewnictwa zmiennych nakazanych w danym teamie? Tez mozna nie stosowac? Jesli np. prywatne pola maja byc poprzedzone _ to zawsze nalezy to stosowac dla prywatnych, niestatycznych, zmiennych pol…
Gdy spojrzeć na to szerzej to mamy dwa rodzaje funkcji dla klas: 1. klasa wykonawca/executor (tutaj command) oraz 2. klasa pojemnik danych/storage (tutaj query).
Przykład to StreamWriter (executor) oraz MemoryStream(storage).
Albo w MVC – Model to storage, a Controller – executor.
Ale często też są klasy które są zarówno wykonawcami jak i pojemnikami, np. klasa string.
MZ, rozdzielenie tego albo łączenie zależy od indywidualnego przypadku, wygody itp.
Pozdrawiam
@Piotr wydaj mi się, że zasada nazewnictwa zmiennych to bardziej pewne ustalenie projektowe, niż coś co dotyczy inżynierii oprogramowania, bardziej chodzi mi o SOLID itp..
No to inna zasada: unikanie magicznych liczb. Zawsze nalezy stosowac chyba ze liczba nie jest magiczna:)
Nie rozumiem ostatniego zdania. Do spójnika “i” wszystko się zgadza, ale dalszy ciąg jest zaprzeczeniem zasady CQS. Jeśli stosujemy tę zasadę, to nie ma szans na żadne skutki uboczne metod, bo skoro są to te, “które zmieniają stan obiektu”, to zmiana stanu jest ich zasadniczym celem, a nie skutkiem ubocznym (pomijając te wywołane błędną implementacją).
Podejrzana ta zasada moim zdaniem :>.
Załóżmy że mamy metodę Q (klasyfikowaną jako zapytanie) i C (klasyfikowaną jako komenda).
Teraz jeśli w metodzie M użyjemy metody C, to metoda M nie będzie już nigdy zapytaniem (bo zmieniła stan obiektu) – i odwrotnie: użycie metody Q wyklucza komendę.
A przecież musi istnieć taka metoda M że wywołuje (być może niebezpośrednio) jednocześnie metodę C i Q – na przykład Main która pośrednio woła każdą metodę w projekcie.
Qed.