Menu Zamknij

Sprawdź, jak Dobre Nazwy Mogą ułatwić ci Życie!

Komunikacja z maszynami jeszcze nigdy nie była tak łatwa, jak dziś. Nowoczesne języki programowania i wiele innych zdobyczy techniki znacznie to ułatwiły. Niestety o komunikację międzyludzką nadal musimy zadbać sami. Więc nawet jeżeli super dogadujesz się ze swoim JVM-em, ale nikt nie rozumie twojego kodu, to nie jest za dobrze.

Ludzie czytają twój kod i chcą go zrozumieć. Im szybciej i lepiej to zrobią, tym łatwiej dokonają w nim niezbędnych zmian. Zaoszczędzą czas na zbędną analizę i unikną błędów wynikających z nieporozumień.

To, co zdecydowanie ułatwia pracę programisty to dobre, wyjaśniające wszystko nazwy. Nie żartuję! — Wyobraź sobie tylko kod, w którym wszystko opisane jest jedną literą. To byłaby jakaś istna patologia!

Możemy więc uznać, że nazwy są istotne i powinny być jak najlepsze. To coś, co najbardziej pomaga innym zrozumieć to, co się dzieje w twoim kodzie. Jeżeli nie ma w nim wystarczająco dobrych nazw, to już chyba tylko debugger może nas wtedy uratować.

// Co tu się dzieje? Sam autor już tego nie pamięta :)
S {
   private final R r;
   private final P p;
   void a(final C c){
      c.v();
      r.s(c);
      p.p(c.e());
   }
}

Opowiadaj Proste Historie

Pierwszym krokiem do lepszej komunikacji jest dobre wyczucie abstrakcji. Zbyt długie i szczegółowe nazwy mogą wprowadzać tylko chaos informacyjny. Natomiast te zbyt ogólne, mogą po prostu nam nic nie mówić.

No i nie powiem! — Balansowanie między ogółem a szczegółem jest pewną sztuką, ale czasem wystarczy wrzucić kilka pomysłów, by poczuć, co będzie w danym miejscu pasować idealnie. W końcu nabierzemy w tym wprawy i będzie już tylko łatwo, lekko i przyjemnie.

Dobre nazwy zwiększają czytelność kodu
Wtedy nawet małpa powinna zrozumieć twój kod 🙂

Problemy z dobraniem abstrakcji chyba najczęściej pojawiają się przy metodach. Nazwa takiej metody na pewno nie powinna być szczegółowym opisem jej kodu. Jeżeli w twoich nazwach pojawiają się łączniki, takie jak And lub Or, to wiedz, że coś się dzieje. 😈 Szatan się tobą interesuje!

To, co ułatwi nam tu sprawę to przyjęcie perspektywy klienta. Klient nie mówi szczegółowo, co ma być zrobione — Klient o swoich potrzebach opowiada zazwyczaj w kilku słowach. Robi to w sposób ogólny, ponieważ nie ma szczegółowej wiedzy w tej dziedzinie.

Gdy jedziesz swoim samochodem na przegląd. Nie musisz mówić diagnoście, co po kolei ma sprawdzać, przypominać się o pieczątce w dowodzie i prosić o wpis do systemu. Mówisz tylko tyle, że potrzebujesz zrobić przegląd i to już wystarczy. Tak samo powinno wyglądać to w kodzie. Nazwy metod powinny mieć ogólną nazwę dopasowaną do klasy, która jej używa.

Gdy nazwy mają już odpowiednią abstrakcję, to bardzo łatwo ułożyć z nich prostą, zwięzłą historię, którą każdy bez problemu zrozumie. Taki właśnie powinien być twój kod —  Lekki i prosty, jak bajka, którą opowiadasz dzieciom przed snem.

Takie historie nie opisują zbędnych szczegółów. Te odwracałyby jedynie naszą uwagę od głównej fabuły. Więc, tak długo, jak główny wątek fabularny twojej historii ma jakiś sens, szczegóły możesz spokojnie hermetyzować. Jeżeli kogoś będą interesowały detale, to wejdzie do metody i sobie o nich na spokojnie przeczyta. To jednak będzie już trochę inna historia.

// Przykład zwięzłej prostej historii :)
wilk.spotyka(czerwonyKapturek);
wilk.idzieDo(babcia);
wilk.zjada(babcia);
wilka.zjada(czerwonyKapturek);
myśliwy.zabija(wilk);
myśliwy.opróżniaBrzuch(wilk);
if(czyWszyscyŻyją(czerwonyKapturek, babcia){
   żyjaDługoISczęśliwie(czerwonyKapturek, babcia, myśliwy);
   return;
}
throw new BajkaNieKończySięDobrze(czerwonyKapturek,babcia);

Gdy logikę biznesową zaprogramujesz w tak przystępnej formie, uwierz mi wszyscy będą Ci za to wdzięczni.

Nie pisz o sprawach oczywistych

Teraz czas na trochę inną historię. Wyobraź sobie, że wraz z kolegami co tydzień łoicie wódę w pobliskim barze. Gdy spotkasz jednego z nich i pyta cię — Czy idziesz na weekend do baru? Nie będziesz go przecież pytać — Po co masz tam iść? Wiesz, że znów szykuje się ostre picie i jeszcze ostrzejszy kac na drugi dzień. Chociaż to drugie o dziwo wszystkich zaskakuje.

To, że robicie to dość systematycznie, nie czyni cię jeszcze alkoholikiem, ale dodaje całej tej sytuacji pewnego kontekstu. Dzięki temu nieprecyzyjne pytanie twojego kolegi jest dla ciebie w pełni zrozumiałe. Ty już dobrze wiesz, co się będzie działo.

Nie pisz w kodzie rzeczy oczywistych
Teraz już nikt nie ma wątpliwości 🙂

Przechodząc jednym susem od kieliszka do klawiatury, chcę powiedzieć tylko, że takie podejście pomaga, również tworzyć dobre nazwy w programowaniu. Myśląc o nich, zwróć zawsze uwagę na otoczenie, w którym przebywają. Nadaje ono kontekstu, dzięki któremu możemy myśleć o niektórych sprawach trochę na skróty. To upraszcza trochę nazwy i znacznie poprawia czytelność.

Problem z pisaniem takich oczywistych rzeczy, bardzo dobrze widać, gdy nazwa klasy powtarza się w nazwie jej pola. W kodzie robi się nam wtedy takie oto „masło maślane”.

@Getter
class User{
  private final String userLogin;
  //...
}
// Gdzieś w kodzie
user.getUserLogin();
user.resetUserPassword(); 

Nie musisz identyfikować w nazwie przynależności do obiektu. To wiadomo już z kontekstu. Przecież widzisz, w jakiej klasie jest pole i na jakim obiekcie wywołujesz metodę.

@Getter
class User{
  private final String login;
  //...
}
// Gdzieś w kodzie
user.getLogin();
user.resetPassword();

Niestety, nic tak nie zaburza nam kontekstu, jak brak jednoznaczności. Gdy podobne nazwy pojawiają się niedaleko siebie, łatwo jest się pogubić. Lepiej rozmontować taką pułapkę za nim ktoś w nią wpadnie.

W takiej sytuacji musimy doprecyzować, o co właściwie nam chodzi. Nie możemy tu dopuścić do pomyłek i nadinterpretacji. To trochę tak jakby twoja, żona miała siostrę bliźniaczkę. Taka sytuacja jest zwyczajnie niebezpieczna!

// Lepiej nie zostawiać, ktoś może użyć nie tam gdzie trzeba.
user.getAddress();
user.getShippingAddress();

// Tu już wiadomo co do czego przeznaczone.
user.getResidenceAddress();
user.getInvoiceAddress(); 
user.getShippingAddress();

Jeżeli obiekt lub jakaś wartość opuszcza swój dotychczasowy kontekst, warto wtedy doprecyzować to w nazwie. Szczególnie, wtedy gdy tracimy z oczu jego oryginalne pochodzenie.

final String name = user.getName();
//..10 liniek i 5 if-ów dalej
sendWelcomeEmail(name); // tu już nie będziesz wiedział co to jest //vs

final String userName = user.getName();
//..10 liniek i 5 if-ów dalej
sendWelcomeEmail(userName); // Tu już można się domyśleć 

Czasami w nazwie zmiennej zamiast pochodzenia, można też wskazać jej przeznaczenie. Ja bym jednak robił to tylko wtedy gdy, źródło pochodzenia nie jest jednoznaczne. Nie powie nam to za dużo o samej zmiennej, jednak nadaje trochę kontekstu w miejscu jej użycia.

// Nie wiemy kto tak naprawdę dostanie SMS, ale wiemy na jaki numer.
final PhoneNumber recipientPhone = resolveRecipientPhone()
//...
sendSms(recipientPhone, message);

// Gdy znamy źródło lepiej utrzymać je w nazwie.
final PhoneNumber userPhone= user.getPhone()
//...
sendSms(userPhone, message); // Tu już wiemy, do kogo.

Po co się domyślać? Nazwij to!

Czasem, zdarzają się miejsca, w których brakuje nam kontekstu lub opisujemy dość skomplikowany koncept. Są to te momenty, w których naprawdę lepiej użyć dłuższej formy. Co prawda nazwa może być długa i ciężko się będzie ją czytać, ale przynajmniej szczerze odda swoje prawdziwe intencje. Będzie to dużo lepsze niż krótka ładna nazwa, która zupełnie nic nam nie mówi lub taka co wręcz zakłamuje rzeczywistość.

Nazywaj w kodzie rzeczy
class TaskScheduler {
   private static final int TEN_HOURS = 10 * 60;
   //...
   // Nie znamy przeznaczenia tej wartości.
   final int period = TEN_HOURS;

   //vs
   // Tu opierając się o kontekst wiemy już wszystko.
   final int initialDelayInMinutes = TEN_HOURS; 
   //...
}

Druga sprawa to warunki logiczne. Czasem są one tak skompilowane, że ciężko nam rozszyfrować co właściwie sprawdzają. Widzimy tak dużo szczegółów, że w sumie to nic już nie widzimy. Warto taki warunek ubrać w metodę i nazwać ją w jakiś sprytny sposób. Często nadaje takiej metodzie formę prostego pytania, na które można odpowiedzieć true lub false.

if(24.99 > body.getWeight() / body.getHeight() > 18,5 ){
   eatSweets();
}

// vs

if(body.isCorrectBmi()){
   eatSweets();
}

Teraz czas na istny klasyk. To „magiczne” wartości! Pozbawione nazwy argumenty metod lub konstruktorów. Tu recepta jest prosta. Umieszczaj je w stałych. Stałe mają nazwy! Te zaś mogą więcej powiedzieć o samych wartościach.

Bywa, że są to wartości bardzo techniczne, wymuszone przez inne serwisy. Często mogą to też być przykładowe dane w testach. Takie stałe dodają również kontekstu do metod, które z nich korzystają.

TaskExcecutor excetor = new TaskExceutor(5);
executor.execute(refreshConnectionTask, 300000);

//vs

private static final int FIVE_MINUTES_DELAY = 5;
private static final int THREAD_POOL_SIZE = 5;
//...
TaskExcecutor excetor = new TaskExceutor(THREAD_POOL_SIZE);
executor.execute(refreshConnectionTask, FIVE_MINUTES_DELAY);

Iluzja, Kłamstwo i Chaos

W programowaniu prawda jest istotna. Im nazwa jest bliższa prawdy, tym lepiej dla nas. Kłamliwe nazwy, zwodzą nas i oszukują. Powodują niejasności i budują fałszywy obraz rzeczywistości. Po prostu istny chaos.

Fałszywe nazwy programowaniu
Gdy nazwałeś coś w taki sposób, żeby tylko pasowało do reszty kodu.

Łatwo o, to gdy nadal utrzymujemy stare nazwy, mimo że przeznaczenie nazwanych tak rzeczy drastycznie się już zmieniło. W procesie ciągłego dostosowywania do nowych wymagań biznesowych łatwo stracić szerokie spojrzenie. Często nawet nie chcemy zauważać, jak nasz kod powoli odkleja się od rzeczywistości. Cieszymy się, że coś tam nam działa, mimo że coraz mniej z tego wszystkiego rozumiemy.

Takie przekłamania pojawiają się również w nowych systemach. Wystarczy, że nie zrozumieliśmy do końca intencji biznesu przy projektowaniu nowej funkcjonalności. Zazwyczaj dlatego, że za mało interesuje nas sama domena, a czasem dlatego, że biznes mało nam o niej mówi.

Warto więc wiedzieć o domenie jak najwięcej i odzwierciedlić ją w kodzie najlepiej jak się tylko da. Pozostawienie fałszywego obrazu domeny, w tym mylących nazw, będzie tylko pogłębiać problemy w przyszłości.

Z tego wychodzi, że dobre nazwy w programowaniu wynikają również z dobrego rozpoznania domeny. Im nasze postrzeganie domeny będzie bardziej spójne z tym, jak patrzy na nią biznes, tym lepsze i elastyczniejsze rozwiązania uda nam się zaimplementować. Dzięki temu przyszłość nie będzie nas już tak zaskakiwać. Dlatego warto rozmawiać z biznesem i korygować nasz kod na bieżąco.

Tak więc jeszcze raz, ale krótko! — Dobre zrozumienie domeny, pozwala tworzyć dobre nazwy, a dobre nazwy ułatwiają zrozumienie domeny. Warto zadbać o jedno i drugie, bo wtedy efektem ubocznym będą dobrze zaprojektowane rozwiązania.

To może teraz jakiś… Refactor?

Powiedzmy to sobie szczerze! Zmiana nazwy zazwyczaj nie jest trudna. Jest też w miarę bezpieczna. Podobnie jest z wyodrębnieniem kawałka kodu do metody i nazwaniem go.

Nie utrzymuj kodu, który komplikuje tylko twoją pracę. Zadbaj o dobre nazwy w programowaniu, a samo programowanie stanie się przyjemniejsze.

Dziękuje, za Twój czas. Mam nadzieję, że wyciągnąłeś z tego wpisu coś dla siebie. Miłego główkowania przy nazwach. Poniżej jeszcze mała dawka inspiracji 😂

Programowanie przy pomocy emoji
Może to jest przyszłość dobrej komunikacji w programowaniu 😉
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.