Wzorzec Strategii 馃檹. Jak Czytelnie Pisa膰 Kod? 馃

Pisanie kodu nie jest rzecz膮 trudn膮. Pisanie kodu, kt贸ry b臋dzie dzia艂a膰 prawid艂owo i b臋dzie rozumiany przez innych jest trudniejsze. Natomiast kod, kt贸ry spe艂nia poprzednie w艂a艣ciwo艣ci a dodatkowo jest utrzymywalny i 艂atwo wymienialny jest ju偶 pewnego rodzaju sztuk膮 – sztuk膮 programowania.


Cze艣膰聽馃檪

Dzisiejszy artyku艂 b臋dzie po艣wi臋cony pisaniu dobrego kodu. Zdefiniujemy czym jest dobry kod i jak go pisa膰. W artykule, opr贸cz aspekt贸w technicznych porusz臋 r贸wnie偶 kwestie mentalne – w ko艅cu kod pisany jest przez ludzi. Nast臋pnie inni go czytaj膮, modyfikuj膮 lub usuwaj膮 i przepisuj膮 od nowa. I tak kr臋ci si臋 nasz programistyczny 艣wiat 馃檪

W dzisiejszym artykule:


Czym jest dobry kod?

Aby pisa膰 dobry kod nale偶y zdefiniowa膰 czym on w og贸le jest. Moim zdaniem dobry kod to taki, kt贸ry po pierwsze jest 艂atwy w zrozumieniu. Wiem, 偶e czasami rozwi膮zujemy problemy, kt贸re nie s膮 trywialne i faktycznie w tych przypadkach ci臋偶ko o pisanie kodu 艂atwego w zrozumieniu. Jednak w wi臋kszo艣ci przypadk贸w nasz kod jest sekwencj膮 procedur, kt贸ra w spos贸b mniej lub bardziej sp贸jny spe艂nia wymagania biznesowe.

Drug膮 metryk膮 dobrego kodu jest mo偶liwo艣膰 jego zmiany lub jego ca艂kowita wymiana bez obawy popsucia innych, teoretycznie niezale偶nych obszar贸w. 艁atwo to brzmi na papierze. W praktyce jest to zadanie bardzo trudne do osi膮gni臋cia. Dlaczego tak si臋 dzieje? Wydaje mi si臋, 偶e cz臋艣ciowo jest to pochodna tego jak anga偶ujemy si臋 w projekt. Z autopsji wiem, 偶e wyst臋puj膮 sytuacje gdy nam si臋 po prostu nie chce my艣le膰 i piszemy aby by艂o. Czy mo偶emy temu zaradzi膰? Chyba nie. Aczkolwiek z pewno艣ci膮 mo偶emy to za艂agodzi膰 wykorzystuj膮c wzorzec strategii.

Kolejnym problemem z metryk膮 zmiany lub ca艂kowitej wymiany jest jej mierzalno艣膰. Ot贸z to czy dany kod jest 艂atwy do zmiany (rozszerzenia) czy te偶 do ca艂kowitej wymiany wyjdzie dopiero przy faktycznej potrzebie. Czasami na tak膮 potrzeb臋 czekamy tydzie艅 a czasami 6 miesi臋cy. O ile w pierwszym przypadku zmian膮 mo偶e si臋 zaj膮膰 osoba, kt贸ra implementowa艂a pocz膮tkowe rozwi膮zanie o tyle w drugim przypadku bardzo cz臋sto b臋dzie to osoba nie zwi膮zana z pocz膮tkow膮 implementacj膮.

Jak widzisz pisanie dobrego kodu jest sztuk膮 zrozumienia. Kod kt贸ry piszemy b臋dzie czytany i zarz膮dzany przez innych. Najwi臋kszym wyzwaniem programisty jest aby napisa膰 kod, kt贸ry w jasny spos贸b przeka偶e intencje i b臋dzie u偶yty we w艂a艣ciwym kontek艣cie. Istniej膮 zasady i konwencje, kt贸re programi艣ci powinni zna膰 i stosowa膰. Pomagaj膮 one dw贸m zupe艂nie r贸偶nym osobom (programistom) na wzajemne zrozumienie bez wzgl臋du na narodowo艣膰 czy przekonania. Wydaje mi si臋, 偶e must-have ka偶dego programisty to przeczytanie lektur wujka Boba o czystym kodzie. Wi臋kszo艣膰 programist贸w na ca艂ym 艣wiecie przeczyta艂a te lektury (przynajmniej Czysty Kod) dzi臋ki czemu w naszym programistycznym 艣wiecie mamy wsp贸lne poj臋cie czym jest czysty kod i jak go tworzy膰.


Wzorzec Strategii a Dobry Kod

Strategia czyli jeden z wzorc贸w programowania obiektowego, kt贸rego raczej nie musz臋 i nie chc臋 szczeg贸艂owo przedstawia膰. Je偶eli kto艣 chce sobie przypomnie膰 jak ten wzorzec dzia艂a to odsy艂am m.in. do tego linka. W du偶ym skr贸cie jest to wzorzec behawioralny, kt贸ry pozwala na zdefiniowanie rodziny (zbior贸w) algorytm贸w, umieszczenie ka偶dego z nich w osobnej klasie i uczynienie ich obiektami wymiennymi.

Co strategia ma do dobrego kodu? Moim zdaniem kluczowe jest zdanie rodzina algorytm贸w. Mo偶e to by膰 algorytm do obliczania ceny produktu w zale偶no艣ci kt贸ry klient dokonuje zakupu lub obliczanie ceny pizzy w zale偶no艣ci od tego jakie sk艂adniki zosta艂y u偶yte i jaki rabat b臋dzie udzielony. Rodzin膮 algorytm贸w r贸wnie dobrze mo偶e by膰 wyb贸r implementacji do obliczania drogi, jak膮 mamy do pokonania w zale偶no艣ci czy jedziemy autem, rowerem czy pokonujemy tras臋 pieszo (przyk艂ad: google maps). Przyk艂ady u偶ycia mo偶na mno偶y膰.

Rozk艂adaj膮c definicj臋 rodzina algorytm贸w na 艂opatki to oka偶e si臋, 偶e algorytm jest to wykonanie logiki pewnej decyzji biznesowej. A co si臋 dzieje z decyzjami biznesowymi? Zmieniaj膮 si臋 馃檪 . Nie zawsze – dobrym przyk艂adem mog膮 by膰 jakie艣 regulacje prawne, kt贸re od X lat s膮 niezmienne i szansa na to 偶e ulegn膮 zmianie jest nik艂a. Jednak znaczna wi臋kszo艣膰 decyzji biznesowych ulega zmianom. S膮 doprecyzowywane, usuwane, dodawane, zamieniane na inne.

Dostrzegasz korelacj臋 pomi臋dzy wzorcem strategii a decyzjami biznesowymi? Ja tak. Wykorzystuj膮c strategie nasze oprogramowanie jest bardziej elastyczne. Je偶eli mia艂bym przytoczy膰 zasady SOLIDto kod, kt贸ry wytworzymy z automatu przyjmuje jedn膮 z zasad [1] a drug膮 [2] w momencie gdy pomy艣limy i nie upychamy wszystkiego do jednego worka:

  • Open-closed principle [1]
  • Single-responsibility principle [2]

Dzi臋ki temu nasz kod b臋dzie otwarty na rozszerzenie. B臋dziemy mogli dowolnie dodawa膰 nowe funkcjonalno艣ci przez dodanie nowego algorytmu i w jednym miejscu w kodzie definiowa膰 nowe rozszerzenie (wyb贸r strategii). Wyb贸r strategii mo偶e by膰 instrukcj膮 switch-case,聽prostym warunkiem if lub w bardziej hardcorowych przypadkach konfiguracj膮 wyekstraktowan膮 do zewn臋trznego pliku. Jednak moim zdaniem ostatnia opcja nie sprawdza si臋 w przypadku rozwi膮za艅 biznesowych, gdzie wiemy dok艂adnie kto jest naszym klientem (nie jest to oprogramowanie kierowane do wszystkich).


Jak zastosowa膰 to w praktyce?

To jest chyba najtrudniejsza cz臋艣膰 tego artyku艂u. Nie mog臋 da膰 Ci konkretnych wytycznych kiedy zastosowa膰 wzorzec strategii bo nie znam domeny w jakiej pracujesz. Nie wiem co jest elementem zmiennym i z czego biznes czerpie najwi臋ksz膮 warto艣膰. Co jest jeszcze trudniejsze – cz臋sto bywa tak, 偶e chocia偶 wiesz w jakiej domenie si臋 obracasz to nie jeste艣 w niej ekspertem i nie masz poj臋cia czy wymaganie, kt贸re w艂a艣nie implementujesz mo偶e by膰 zmieniane. I co masz zrobi膰?

Teraz napisz臋 kilka zda艅, z kt贸rymi cz臋艣膰 mo偶e si臋 nie zgodzi膰 (by膰 mo偶e sam za jaki艣 czas stwierdz臋, 偶e to jest bez sensu). Zak艂adaj膮c, 偶e nie mo偶esz wyci膮gn膮膰 wi臋cej informacji ze strony biznesu (po prostu nie mo偶esz dowiedzie膰 si臋 wi臋cej o domenie) musisz dzia艂a膰 na czuja i wsz臋dzie tam gdzie czujesz, 偶e kontekst mo偶e by膰 zmienialny stostuj wzorzec strategii.

Aby lepiej to zobrazowa膰 podam Ci przyk艂ad. Za艂贸偶my 偶e pracujesz dla sklepu, kt贸ry zajmuje si臋 produkcj膮 i dystrybucj膮 biurek. Do tej pory sklep dzia艂a艂 lokalnie i ca艂a sprzeda偶 opiera艂a si臋 o kontakt telefoniczny. Teraz przechodz膮 w sprzeda偶 online. Twoim zadaniem jest implementacja logiki prostego systemu p艂atno艣ci. Ma to by膰 dostarczone szybko (ka偶da stracona godzina to $). W celu uproszczenia za艂贸偶my, 偶e ca艂y system jest ju偶 zrobiony a Ty musisz zaimplementowa膰 ten jeden ma艂y feature.

Musisz zaimplementowa膰 p艂atno艣膰, kt贸ra mo偶e by膰 realizowana za pomoc膮 p艂atno艣ci bankowej lub blika. Kiedy u偶ytkownicy dokonuj膮 p艂atno艣ci przy pomocy blika, dodatkowo zyskuj膮 punkty lojalno艣ciowe (taka promocja). Kod do tego mo偶e wygl膮da膰 nast臋puj膮co:

Nie wchod藕my w mantry tego czy ten kod ma sens czy nie. Chodzi o fakt, 偶e teraz dochodzi kolejne rozszerzenie. Sklep dostaje feedback, 偶e wyb贸r p艂atno艣ci jest zbyt sk膮py i klienci chc膮 aby dodano szybkie przelewy oraz mo偶liwo艣膰 przelewu offline (co to za klienci?? 馃榾 ). Sterowany czasem mo偶esz i艣膰 w kierunku dodawania kolejnych if’贸w do metody makePayment(…).

B臋d臋 z Tob膮 szczery – nie mam z tym problemu do czasu kiedy logika metody makePayment(…) zaczyna si臋 rozrasta膰, tak jak w naszym wyimaginowanym przypadku. Kolejny problem to kiedy r贸偶ne osoby modyfikowa艂y ten kod i teraz 偶adna inna (nawet te, kt贸re ten kod pisa艂y) nie chce tego fragmentu rusza膰 bo nie do ko艅ca wie jak to dzia艂a i boi si臋 zepsu膰. By艂em w tym miejscu w kodzie produkcyjnym. Nadal si臋 z tym spotykam i my艣l臋, 偶e ka偶dy kto pisze software zna to uczucie. Wiesz, 偶e przyda艂oby si臋 zrefaktoryzowa膰 ten fragment kodu ale nie mo偶esz bo nie ma czasu i zasob贸w a 偶eby zrozumie膰 ca艂o艣膰 trzeba b臋dzie wej艣膰 g艂臋boko w logik臋.

Gdyby艣my zamiast tego od razu wyczuli mo偶liwo艣膰 zmian, zaoszcz臋dziliby艣my p贸藕niejszych b贸l贸w. Oczywi艣cie zdaj臋 sobie spraw臋, 偶e niesie to inne problemy, typu przekazywanie zale偶no艣ci do konkretnych strategii (co艣 czego nie uwzgl臋dni艂em w przyk艂adzie poni偶ej). Mo偶na to za艂atwi膰 w najprostszy spos贸b, czyli wstrzykuj膮c zale偶no艣膰 przez konstruktor. Jednak najwa偶niejsze pytanie kt贸re si臋 pojawia i na kt贸re nie umiem Ci odpowiedzie膰 – czy warto? Wed艂ug mnie w wielu przypadkach tak ale jednak nie zawsze.

Mo偶e si臋 zdarzy膰 tak, 偶e mia艂e艣 z艂e przeczucie i kod, kt贸ry uj膮艂e艣 w strategi臋 nie ma 偶adnych rozszerze艅. Sko艅czy艂e艣 z interfejsem i jego dwoma implementacjami kt贸re si臋 nie zmieniaj膮. Co艣 co m贸g艂by艣 uj膮膰 w jednej metodzie z dwoma if’ami i 15 liniami kodu jest hierarchi膮 klas. Pytanie – czy to jest a偶 tak z艂e? W najgorszym przypadku masz 2 dodatkowe klasy, ka偶da zawieraj膮ca po 5 linii logiki kodu. Nie jestem zwolennikiem takiego podej艣cia ale uwa偶am, 偶e b臋dzie to lepsze ni偶 metoda z zagnie偶d偶aj膮cymi si臋 if’ami, kt贸re z czasem mog膮 doj艣膰. Czy jest z艂oty 艣rodek? I tak i nie. Zale偶y z kim pracujesz. Ja osobi艣cie jestem zdania, 偶e powinni艣my zaczyna膰 jak najpro艣ciej – w tym przypadku od metody. A kiedy widzisz, 偶e to si臋 rozrasta robisz refaktor. Nie akceptujesz wym贸wek typu: to ma by膰 na ju偶!


Podsumowanie

Mam nadziej臋, 偶e ten artyku艂 u艣wiadomi nas troch臋 w dzia艂aniu. Nie piszmy kodu bez my艣lenia! Patrzmy, co mo偶e si臋 zdarzy膰 dalej. By膰 mo偶e kod, kt贸ry w艂a艣nie klepiesz za 3 miesi膮ce b臋dzie musia艂 by膰 wyrzucony do kosza a zamiast niego o wiele szybciej powstanie nowa implementacja? Tylko pytanie – czy Tw贸j kod jest gotowy na tak szybk膮 wymian臋? Czy kod, kt贸ry wcze艣niej naklepa艂e艣 nie zawiera zawi艂o艣ci i nieoczekiwanych wynik贸w?

Oczywiste jest, 偶e im d艂u偶ej jeste艣 na danym projekcie, tym wi臋ksz膮 wiedz臋 masz na temat tego co tworzysz. Mo偶e faktycznie b臋dzie tak, 偶e uznasz i偶 kod, kt贸ry pisa艂e艣 2 miesi膮ce temu trzeba przepisa膰 z nowo poznan膮 wiedz膮. Jak du偶y b臋dzie koszt przepisania? Czy b臋dzie to tylko kwestia napisania nowej logiki i jej odpowiednie wstrzykni臋cie? A mo偶e modyfikowanie 10 miejsc z doz膮 niepewno艣ci czy system b臋dzie dzia艂a膰 dalej tak samo? Sam odpowiedz na to pytanie i pami臋taj, 偶e kod kt贸ry dzi艣 tworzysz jutro mo偶e by膰 zarz膮dzany przez kogo艣 innego.

Na koniec pozwol臋 sobie utworzy膰 w艂asny cytat:

Kod jest jak bumerang, kiedy艣 do Ciebie wr贸ci.

Bartosz D膮bek

 

殴r贸d艂a:


Za tydzie艅

Mamy pierwszy tydzie艅 nowego miesi膮ca a to oznacza podsumowanie pa藕dziernika oraz plany na listopad.

5 1 vote
Article Rating
Subscribe
Powiadom o
guest
4 komentarzy
najnowszy
najstarszy oceniany
Inline Feedbacks
View all comments
艁ukasz
艁ukasz
20 dni temu

Dlaczego stosujesz „else if” je偶eli masz w warunku poprzednim „return”?

Krzysiek
Krzysiek
27 dni temu

jaki poleci艂by艣 spos贸b, 偶eby nie u偶ywa膰 IF’ow w miejscu choosePaymentStrategy ?