Zapytaj swojego kolegę, programistę czy komentarze w kodzie to dobry pomysł. Jak myślisz, jaka zazwyczaj pojawia się odpowiedź?
- Absolutnie!
- Nie.
- Chyba Cię po(..)„
Bez zastanowienia komentujemy także komentarze podczas Code Review – zostawiając pozostawione emocji, krótkie i bez krzty wyjaśnienia wrzutki: „usuń ten pieprzony komentarz!”. 💥
Mam wrażenie, że sporo zmieniło się po szaleńczym hajpie na książkę „Clean Code” Uncle Boba (zresztą świetną, którą wpisałbym w obowiązkowy kanon lektur programisty). To w niej znajdziemy rozprawkę na kilkanaście stron odnośnie komentarzy – (nie)stety stawiając je w obliczu zła najgorszego – patrząc na ilość warunków, które wpływają na ich negatywny odbiór.
„Zapamiętujemy czego robić nie można, zapominając o tym, co robić MOŻNA lub WYPADA.”
Coś tu cuchnie…
Wracając jednak do tytułowego cytatu. Tak – komentarze mogą kłamać, bo modyfikując logikę biznesową, często pod presją czasu zapominamy o tym co otacza nasz najważniejszy kod. Mając oddech Project Managera na plecach, zależy nam na wykazaniu się i dostarczeniu zmiany jak najszybciej.
Zmiana została wprowadzona – mamy mały „sukces”… I porażkę zarazem.
Niestety ale komentarz opiewający zmodyfikowany fragment kodu, nie odpowiada aktualnej implementacji. Gorzej, może nie wpływać na rezultat kompilacji, wynik uruchomionych testów czy narzędzi SCA. Przecież działa. Wprowadziliśmy zmianę, degradując przy tym kod.
Jednak nasze obyczaje zaczęły sięgać także drugiego dna. Można powiedzieć, że przyjęliśmy zasadę:
„Kto komentuje, ten smród w kodzie snuje. 💩”
Nadużywanie komentarzy jest złe. Tutaj się zgadzamy. Jest wiele momentów gdy komentarz jest zbędny. Natomiast nie wykorzystywanie jego potencjału – także może nie być najlepszym pomysłem.
Istnieją tylko dwa rodzaje komentarzy
Dzielę komentarze pojawiające się w kodzie na dwa typy – tak czysto zero-jedynkowo. Nie ze względu na zastosowanie, ale ze względu na wartość jaką niosą swoją treścią.
Nie wnoszące wartości ⛔️
To te, które wprowadzają szum. Zbędny balast, bez którego kod będzie bardziej czytelny. To tych przykładów możemy wygenerować najwięcej. Tłumacząc podtytuł, nie wnoszące wartości komentarze to takie które:
- opisują za co odpowiada metoda, jednocześnie rozmijając się z prawdą zawartą w implementacji 😈,
- tłumaczą podstawowe operacje (poniżej fragment mojego starego kodu),
- objaśniają zawiłość rozwiązania zamiast konkretnie odnieść użytkownika, że wykorzystaliśmy algorytm A*,
- informują, że zmienna
$firstName
zawiera imię, - „wycinają funkcjonalność” poprzez zakomentowanie kodu,
- pełnią rolę historii zmian.
Długo by wymieniać. Sam dawno temu, zostawiłem w kodzie sporo podobnych smaczków myśląc, że wniosą one pożyteczną wartość do projektu:
// Load link by hash
$link = ORM::factory('link', $this->request->param('hash'));
// Throw exception if link not exists
if (!$link->loaded()) {
throw new Exception('Link not exists!');
}
// Increment redirections and update DB
$link->redirections += 1;
$link->save();
// Redirect to url
$this->request->redirect($link->url, 301);
Dziś wywołują jedynie uśmiech na twarzy, przypominając mi, że od razu nie było się orłem 🙂
Wartościowe, uzupełniające kod ✔️
Tych dobrych komentarzy, wartych uwagi programisty jest zdecydowanie mniej. Jednak w tym tkwi ich potencjał.
1. Wyjaśniające decyzję, kontekst
Zostawiając komentarz dlaczego w naszym przypadku zastosowaliśmy algorytm A*. Szczególnie gdy wyjaśnienie nie jest zawarte bezpośrednio w kodzie, ale umieszczony został link – do dokumentacji, strony internetowej.
Czasem musimy walczyć z frameworkami oraz konkretnymi wersjami przeglądarek:
// Fix IE Caching Issue: http://stackoverflow.com/a/19771501
if (!$httpProvider.defaults.headers.get) {
$httpProvider.defaults.headers.get = {};
}
Wiadomo przynajmniej skąd to dziwadło znalazło się w kodzie.
2. @TODO
Oznaczenie fragmentów kodu do których musimy wrócić w przyszłości (z różnych względów). Szczególnie gdy mamy do czynienia z Feature Flags, prosty zabieg ułatwi nam odnalezienie wszystkich użytych Feature Flags w kodzie projektu. Tym bardziej, że IDE bardzo sprawnie radzi sobie z wyszukiwaniem tego typu komentarzy. Można posługiwać się szablonem: // @TODO FF:[TICKET ID / FEATURE FLAG ID]
czyli: // @TODO FF:AUDITOR-276
.
Zazwyczaj są to komentarze o określonej długości życia – znikają wraz z usprawnieniem kodu / usunięciem Feature Flag.
3. Komentarze na potrzeby publicznego API
Czyli komentarze na podstawie których możemy wygenerować dokumentację – fajnym przykładem jest API dla SDK AWS. Wykorzystywanie IDE ułatwia także wykorzystywanie API biblioteki, podpowiadając nam niezbędną składnię.
Tutaj czai się jednak to o czym wspomniałem na początku. Łatwo zmienić implementację, pozostawiając niezmienioną formę komentarza – przynajmniej tą opisową, bo z typami oraz nazwami parametrów metody, narzędzia SCA sobie nieźle radzą. Tak więc nawet dobry komentarz, może przybrać formę komentarza niechcianego w naszym kodzie 🙁
Nie bój się dobrych komentarzy w kodzie
Chciałbym zwrócić uwagę, że minimalizowanie szumu w kodzie, nie wiąże się bezpośrednio z usunięciem wszystkiego co jest komentarzem. Jak widać, w gąszczu złych komentarzy, znajdziemy także ich formę, która przynosi wartość – jest ich jak na lekarstwo ale jednak. W gruncie rzeczy, gdyby komentarze były bezużyteczne – dawno zniknęłyby z naszych języków programowania. Ah… zagalopowałem się, goto
wprowadzono do języka PHP dopiero w wersji PHP 5.3 wydanej w 2009 roku 👌
Mówi się, że testy jednostkowe są dokumentacją dla programisty. Dobre komentarze – mogą ją nieco uzupełniać, dając trochę więcej kontekstu na podjęte decyzje.