Menu Zamknij

Zasada Tell, Don’t Ask! Chcę wyników, a nie danych!

Zadaj pytanie, na które naprawdę chcesz uzyskać odpowiedź, zamiast pytać o informacje, które pomogą ci ją znaleźć”.

Nie traktuj obiektów jak tępe kontenery na dane. Każ im zrobić to, na czym się najlepiej znają. Nie wyręczaj ich. Nie pytaj o ich wiedzę. Żądaj od nich działania i wyników. Obiekty powinny być powoływane do życia właśnie po to, by dostarczać wyniki i realizować zadania. Nie po to, by opowiadać o swoim bogatym życiu wewnętrznym. Owszem! Dane są konieczne, ale ich oddziaływanie powinno być jak grawitacja, którą odczuwamy, mimo że jej nie widać, Tak samo dyskretnie dane obiektów powinny wpływać, na funkcjonowanie procesów.

Syndrom Nadmiernie Zaangażowanego Klienta

Opowiem Ci teraz historię pewnego klienta. Chciał on zbudować prostą stronę internetową. Firma, z którą współpracował, miała całkiem bogatą ofertę różnych usług i produktów. Zajmowała wieloma aspektami: organizowała domenę, załatwiała hosting, instalowała Wordpress’a, dostarczała certyfikat SSL.

Klient uznał, więc że kupi od nich domenę, certyfikat oraz hosting. I sam zbuduje sobie stronę. Szybko jednak okazało się, że nie ma wystarczającej wiedzy, by połączyć to wszystko i zbudować coś, co by mogłoby zadziałać. Dodatkowo prace nad stroną nie pozwoliły mu się dostatecznie skupić na jego prawdziwym biznesie. Wokół niego rósł tylko chaos, biznes zaczął podupadać, a strona nadal nie działała.

To przykład tego, co się dzieje, gdy klient pyta o pół produkty i próbuje z nich sam coś składać, zamiast jasno mówić, czego chce. Nasz klient mógł zebrać wszystkie swoje wymagania i wysłać je do firmy i oczekiwać od niej dostarczenia gotowej działającej strony.

Taki klient powinien mieć szeroką wizję. Musi patrzeć z wysokiej perspektywy. Nie może zajmować go proces wytwarzania wszystkich potrzebnych mu elementów. Niech to dostawca się specjalizuje. Bywa tak, że wymagania rosą i ktoś się musi dostosować. Wtedy albo dostawca spełni żądania klienta, albo klient zmienia dostawcę.

Zasada tell don't ask

Właśnie o tym mówi zasada tell, don’t ask, by twój klient, czyli twoja klasa wyższego poziomu, nie wyciągała pojedynczych danych, tylko nakazywała swoim współpracownikom wykonanie konkretnego zadania i dostarczenia wyników.

Projektuj z Pozycji Klienta

Gdy projektujesz system z pozycji obiektów niskiego poziomu i zawartych w nich surowych danych, to szybko wpadasz w pułapkę, która polega na dostosowywaniu się klienta, do usług oferowanych przez jego ograniczonych współpracowników. Tak się też zazwyczaj składa, że te obiekty z niższych poziomów, często nie oferują nic oprócz surowych danych.

Trudno wtedy złapać się na tym, że nagminnie prosisz obiekty o ich dane. To dlatego, że twoje myślenie jest już spaczone, przez ubogą ofertę obiektów podrzędnych.

Projektowanie, z góry na dół

Dużo łatwiej jest nie wpaść w tę pułapkę, gdy projektujesz swoje rozwiązania od góry do dołu. Rozpocznij ten proces od dobrego zapoznania się z oczekiwaniami swojego klienta, poprzez widok i tak dalej w dół, aż do surowych danych. Zasada tell don’t ask, będzie wtedy stosowana przez ciebie wręcz intuicyjnie.

Zaczynasz wtedy myśleć w kategorii, konkretnych działań oraz wyników, ponieważ nie ma jeszcze danych, które by to zaciemniały i sugerowały kiepskie rozwiązania. Wtedy nawet te dane dobierane są do realizowanych przez obiekt działań. I to w ten właśnie sposób powstają najlepsze obiekty, posiadające jakieś zachowania. To tu jest klucz do programowania prawdziwie obiektowego. Działając od drugiej strony, szybko pogrążasz się w proceduralną otchłań.

Unikaj Efektu Domina

Kiedy obiekty ujawniają swój wewnętrzny stan, kuszą swoje klienty do tego, aby korzystały z niego w sposób bezpośredni, czyli przez analizę danych. Często te dane przekazują też dalej, do swoich klas nadrzędnych. Gdy coś się w nich zmieni, wymaga to wtedy poprawek we wszystkich tych miejscach, gdzie były one wykorzystywane.

W przypadku komunikacji obiektów, za pomocą swoich zachowań, takie katastroficzne zdarzenie raczej nie będzie miało miejsca. Dużo trudniej będzie złamać kontrakt, oparty o zachowanie. W takim przypadku, powinno pomóc już samo skorygowanie implementacji, a prawdopodobieństwo wystąpienia falowania zmian, będzie wręcz znikome.

Przenieś Zazdrosne Metody

Zazdrość w programowaniu obiektowym to takie zjawisko, gdy jakaś metoda dużo bardziej interesuje się metodami i danymi z innej klasy, niż ze swojej własnej. W tym przypadku warto przenieść taką metodę, do klasy, która jest najsilniej z nią powiązana.

class Collaborator {
    private int x;
    private int y;
    private int z;
    //public getters and setters
    public int calculateSomething(ratio, count) {
       return ((z* ratio) + (x- y)) * count;
    }
}

class Client {
    private final Collaborator collaborator;
    private final Publisher publisher;
    private int ratio;
    private int count;
    public Client(Collaborator collaborator, Publisher publisher) {
        this.collaborator = collaborator;
        this.publisher = publisher;
        ratio = 10;
        count = 20;
    }
    //jelous method
    void doSomething() {
        int reslult = (collaborator.getZ()* ratio) + (collaborator.getX() - collaborator.getY()) * count;
        publisher.publishResult(result)
    }
    //non-jelous method
    void doSomethingBetter() {
        int result = collaborator.calculateSomething(ratio, count)
        publisher.publishResult(result)
    }
}

Zasada Tell, don’t ask łączy się trochę z prawem Demeter. Prawo to mówi, że klasa powinna ujawnić tak mało stanu, jak to tylko możliwe. Przestrzeganie tej prostej zasady powinno uchronić ciebie, przed robieniem kodu spaghetti.

Moglibyśmy przecież, zrobić system, w którym wszystkie klasy wchodzą ze sobą w interakcje. Być może nawet są takie systemy. Czujesz jednak chyba, że to nie jest dobry pomysł. Wtedy każda najmniejsza zmiana groziłaby potrzebą poprawiania w wielu różnych miejscach systemu, a znalezienie tych miejsc też nie byłoby łatwą sprawą.

Zasada tell don't ask

Sprytne Obiekty Są Bardziej Użyteczne

Operacje na danych powinny wykonywać te obiekty, które są ich bezpośrednimi właścicielami, a na zewnątrz niech oferują jedynie metody, które pozwolą je wywołać. Tak więc, zamiast sprawdzać getterami stan obiektu i na podstawie tego modyfikować go, dużo lepiej jest ubrać całą akcję w jakąś zgrabną metodę.

Dobrym przykładem, może być konwersja. Załóżmy, że posiadasz dwóch klientów i jeden z nich wykorzystuje temperaturę w Kelwinach, jeszcze inny w stopniach Fahrenheita. Załóżmy, że oba te klienty korzystają z obiektu typu Termometr. Można by wtedy zwracać klientom temperaturę w stopniach Celsjusza i kazać im samodzielnie przeliczać na Kelwiny lub stopnie Fahrenheita. Dużo lepiej jest jednak zrobić nasz termometr odrobinę sprytniejszym i dodać do niego funkcje. inFarenthite oraz inKelwin. Pomyśl, jak bardzo ułatwia to pracę klientom takich metod oraz jak upraszcza to ich kod.

OK, a teraz spróbujmy uprościć życie klientów jeszcze bardziej. Załóżmy, że jeden z tych klientów, potrzebuje wiedzieć, czy temperatura w danej chwili nie jest przypadkiem równa 0 stopni Fahrenheita, drugi klient potrzebuje reagować na przekroczenie temperatury 1000 Kelwinów.

W takim wypadku dodalibyśmy następujące funkcje isZeroFarenhite oraz registerAlert(temperature, callback). Teraz nasi klienci posiadają już sprytne narzędzie, które kompleksowo zajmuje się ich zadaniami związanymi z temperaturą.

To przykład wysokiej spójności i niskiego sprzężenie. Dobrze alokujemy odpowiedzialność, termometr odpowiada na wszystko, co jest związane z temperaturą, jednak nie przekracza swoich kompetencji, próbując np. samemu wysyłać e-maile do użytkownika o przekroczeniu temperatury i nie ustawia na ekranie ikonki z płatkiem śniegu, gdy temperatura jest równa zeru. Po prostu odciąża klientów w tych kwestiach, w których ma najwyższe kompetencje.

Zasada tell don't ask

Bądź Gotów Na Zmiany, Ale Nie Wyprzedzaj Faktów

Pamiętaj, projekt będzie się zmieniał. Pole będą przychodzić i odchodzić. Typy danych mogą się zmieniać. Nie możesz sobie pozwolić na to, by takie drobne zmiany wymagały przekopywania całego kodu. Niech operacje będą tam, gdzie są dane potrzebne do ich wykonania. Rób w klasach takie metody, których potrzebują klienci, w obiektach, które mają do tego najlepsze kompetencje. Nie rób rzeczy na zapas, bo te w przyszłości mogą tylko sugerować mało aktualne kiepskie rozwiązania. W miarę możliwości pozbywaj się geterów i setterów.

To już wszystko w tym wpisie. Teraz niech słowo kodem się stanie, na twoim ekranie 🙂 Powodzenia!

Please follow and like us:
Skuteczna refaktoryzacja w 10 krokach!

Odbierz Darmowy Poradnik o Refaktoryzacji!

Poznaj kilka prostych technik i wprowadź nową jakość w swoim projekcie.

Dzięki za dołączenie do mojej listy.

Coś poszło nie tak :( Spróbuj jeszcze raz.