Każdy taki akronim wygląda sexy. Mmm SOLID. Dobrze wiedzieć, że istnieje coś takiego. A gdyby tak wiedzieć co każda z literek oznacza, a gdyby tak rozumieć jeszcze. Z miejsca 15k koleżko. Zaufaj mi.
Znasz to uczucie, gdy chcesz coś zmienić w swoim systemie. Jakie uczucia mogą towarzyszyć takiemu zadaniu. Często trwoga. Jeszcze nie otworzyłeś IDE, ale już wiesz, że lepiej odwołać wieczorne plany. Wiadomo, nikt z nas ich pewnie nie ma, ale tak się mówi. Zaczynasz rzeźbić pierwszą linijkę. Testy na czerwono. Żartuję, nie mamy przecież testów. Ale klasa w pakiecie obok się też pali na jaskrawo. Wtf. Zmieniłem encję, a świeci się klasa controllera. Bierzesz za telefon i odwołujesz jutrzejsze wieczorne spotkanie, choć mogłeś to zrobić od razu, bo wszystko to było do przewidzenia. Jak zrobić by żyło się lepiej.
Single Responsibility
A gdyby tak nie musieć się więcej martwić. Po co nam tyle katalogów, modułów, klas, modyfikatorów dostępu i Bóg wie co jeszcze. Umieścimy całą aplikację w jednym miejscu. Nie będzie się świecić pakiet obok. Na przykład w punkcie startowym programu. Niech to będzie main. Będziemy tam mieć kod, który steruje regułami biznesowymi, pobiera dane, przetwarza, wyświetla, zapisuje i wyszukuje. Co tylko dusza zapragnie. Napisane, działa jak marzenie. Tą aplikacją jest wspominana już gdzieniegdzie aplikacja do obliczania podatku dochodowego przez księgową.
Pojedyncza odpowiedzialność polega na grupowaniu w module takich funkcji / aspektów naszej aplikacji, które będą się zmieniać z tego samego powodu. Będziemy więc rozdzielać te funkcje aplikacji, które zmieniają się z różnych powodów. Ot cała definicja.
Umieszczając wszystko w jednym miejscu zdecydowanie nie stosujemy się do S. Jakby to wówczas rzutowało na naszą pracę. Sprawdźmy więc i wróćmy do naszej aplikacji.
Co księgowa robi:
- Klika przycisk pobierz dane dla klienta Joe Doe
- Klika przycisk oblicz podatek dochodowy klienta Joe Doe
- Księgowa patrzy na ekran i widzi. Dane. Dużo danych.
Proste rzeczy. Księgowa pobiera dane niezbędne do obliczenia podatku, sprawdza czy wszystko jest ok i klika przycisk obliczający podatek. Po chwili na ekranie, w kolorowej tabelce dostaje zwrotkę z aplikacji odnośnie podatku dochodowego Joe Doe. Voila. Duża ta tabelka. Piętnaście kolumn. Skomplikowany ten System.out.println. Księgowa korzysta z czterech kolumn. Księgowa ma dość. Chwyta za telefon. Programisto informatyku zmieniaj, bo zawiśniesz. Cztery. Cztery kolumny i nazwy kolumn po polsku. Angielski nie.
Programista otwiera maina. 5200 linii. Szuka System.out.println, zmienia nazwy na polskie, wyrzuca niepotrzebne kolumny. Deploy. Jest. W domu zasypiając programista zastanawia się, czy nic na pewno nie popsuł robiąc tę prostą zmianę.
Mamy zatem tu dwa powody dlaczego wprowadzenie pojedynczej odpowiedzialności mogłoby przynieść korzyść. Korzyścią tą jest mianowicie możliwość czytania kodu, odnajdywania się w nim i łatwość wprowadzania zmian. A jaki był powód zmiany dotyczącej czterech kolumn i polskich nazw? Powodem było to, że główny użytkownik aplikacji, czyli księgowa, jest smutna i zdenerwowana. Księgowa miała już dość nadmiernej ilości danych. Źle jej się pracowało. Nikt częściej niż księgowa nie patrzy na frontend tej aplikacji.
Jesteśmy więc świadomi tego, że w naszej aplikacji znajduje się coś takiego jak frontend. Wiemy też, że jest on istotny dla jakiejś grupy ludzi (tu: tylko księgowa). Ta część systemu będzie się zmieniać dlatego, że tej grupie ludzi będzie na tym zależało. Powodem do zmiany będą ich interesy. Powinniśmy zatem izolować tę część systemu i trzymać ją razem. Ni mniej, ni więcej.
Innym razem, przychodzi do nas przełożona księgowej. Ona nie używa na co dzień tej aplikacji. Jest organem nadzorczym. Sprawdza w raportach czy wszystkie podatki wyliczone są poprawnie. Okazało się pewnego dnia, że w logice obliczania podatku jest błąd. Ring ring. Fix it my friend.
Sytuacja jest podobna. Mamy grupę szczególnie zainteresowanych poprawnym działaniem algorytmu wyliczania podatków. Tu tę grupę będzie stanowił przełożona księgowej i np.: manager i ważni przełożeni. Ich wola oraz ich interesy będą stanowiły powód do zmiany w logice biznesowej naszej aplikacji.
Co najważniejsze, zmiany wprowadzane na wniosek księgowej, czyli zmiany we frontendzie nie będą wpływały na kod aplikacji, który jest ważny dla managera i przełożonej księgowej. I na odwrót. Wprowadzając zmiany w logice biznesowej nie musimy się martwić, że spartolimy coś we frontendzie.
Co się dzieje, gdy księgowa klika przycisk pobierz dane klienta Joe Doe. Z pewnością nastąpi próba dobicia się do bazy danych i wyciągnięcie danych. Po obliczeniu podatku dochodowego, chcielibyśmy zapisać wynik również do bazy danych. Czyli tym samym zidentyfikowaliśmy pewną odpowiedzialność. Odpowiedzialność wykonania operacji na bazie danych. Pod spodem, odpowiedzialność ta będzie składać się z dwóch metod: findByName oraz save. Pojedyncza odpowiedzialność nie ma nic wspólnego zatem z liczbą metod. Nie jest tak jak można by intuicyjnie stwierdzić, że klasa, która posiada więcej niż jedną metodę nie spełnia warunków pojedynczej odpowiedzialności. O nie nie nie, hej hej hej hejka! Odpowiedzialność za operacje na bazie danych będzie należała pewnie do jakiegoś technicznego smutnego gościa. Na przykład takiego jak my.
Podsumowanie
Jeśli księgowa będzie chciała dodać kolejne dwie kolumny, albo dodać nową tabelkę, to chcemy, aby zmiana widoku nie propagowała się na inne moduły, które nie mają nic wspólnego z wyświetlaniem danych. Nie chcemy, aby zmiana widoku powodowała, że muszę otwierać np.: plik z klasą, gdzie mam zaszyte obliczanie podatku dochodowego. Logika biznesowa jest tym, na czym nasza firma zarabia. Realizuje najistotniejsze zadania, za które ktoś płaci. Nie ma potrzeby zaglądać i dłubać tam bez potrzeby. Pojedyncza odpowiedzialność pomaga nam uniknąć właśnie takich smutnych sytuacji.
Metodą, która pomoże nam sprawdzić, czy pojedyncza odpowiedzialność jest obecna w naszej klasie, jest wysoka kohezja. Ale o tym innym razem. Zarzucam tylko temat.