Codziennością każdego programisty jest praca z kodem źródłowym. Ważne, aby zadbać o czysty kod. Dlaczego? Odpowiedź na to pytanie znajduje się w tym artykule.
Kod źródłowy jest zapisem woli programisty, która ma być zrealizowana przez procesor. W przypadku języków imperatywnych będzie to lista czynności do wykonania, a w przeciwieństwie do języków deklaratywnych jest to zbiór warunków jakie rozwiązanie ma spełniać1.
Procesor nie czyta kodu źródłowego. Procesor otrzymuje polecenia na podstawie przetworzonego kodu źródłowego najczęściej w formie kodu maszynowego lub kodu pośredniego (bytecode). Programem, który czyta Twój kod źródłowy jest analizator składniowy (parser). Jednak parser jest bezwzględny – bezpardonowo wytnie misternie przygotowane wcięcia, literackie nazwy funkcji oraz komentarze pisane wierszem z kodu i wyciśnie to co jest dla niego ważne – tokeny służące dalszej analizie.
W przypadku długoterminowych projektów kod źródłowy jest częściej czytani niż pisany. Czytanie kodu następuje w sytuacji rozszerzania funkcjonalności oraz naprawy potencjalnych błędów. Zatem kto potrzebuje kod źródłowy? Są to dwie grupy:
- Ty sam,
- Twoi koledzy z zespołu.
Za każdym razem osoba analizująca kod musi zrozumieć i poprawnie zinterpretować działanie kodu oraz przewidzieć sekwencję realizowanych instrukcji (code execution path). Nie są odosobnione przypadki trudności w interpretacji i analizie danego fragmentu kodu przez jego autora już po upływie kilku tygodni2.
Zatem odpowiemy na pytanie jak osiągnąć czysty kod – jak należy kodować, aby kod był czytelny, zrozumiały oraz łatwy do pracy nad nim?
Jak mieć czysty kod?
Wraz z rozwojem dziedziny inżynierii oprogramowania społeczność programistów opracowała szereg zasad oraz dobrych praktyk dotyczących wytwarzania oprogramowania. Przytoczmy kilka z nich.
Formatowanie kodu
W poprzednim artykule zostało przedstawione dlaczego formatowanie kodu jest ważne oraz dlaczego automatyczne formatowanie kodu jest jeszcze ważniejsze. Podsumowując: automatyczne formatowanie kodu poprawia jego czytelność i spójność oraz zmniejsza koszt jego rozwoju.
Keep It Simple Stupid
Reguła wskazuje, że proponowane rozwiązania powinny być możliwie proste i łatwe w zrozumieniu.
Don’t Repeat Yourself
Reguła określona jest w dwojaki sposób. W odniesieniu do kodu zaleca, aby powtarzające się fragmenty kodu wydzielić do funkcji. W drugim przypadku wskazuje, iż powtarzające się czynności programisty powinny być zautomatyzowane na przykład w postaci skryptów i narzędzi automatyzujących. Prostym przykładem są narzędzia formatujące kod źródłowy.
SOLID
Zbiór zasad, które zaproponował Robert C. Martin. Zasady określają w jaki sposób powinien być zorganizowany kod pisany w duchu paradygmatu programowania obiektowego. Są to następujące zasady:
- każda klasa powinna posiadać tylko jedną odpowiedzialność,
- każdy element systemu powinien być otwarty na rozszerzenia, ale zamknięty na modyfikacje,
- funkcje używające adresów3 do obiektów typów bazowych muszą być w stanie również używać wskazań do obiektów typów dziedziczących,
- podział ogólnych na wiele wyspecjalizowanych interfejsów,
- zależność pomiędzy modułami wysokopoziomowymi, a niskopoziomowymi powinna być realizowana poprzez abstrakcje.
Prawo Demeter
W skrócie prawo Demeter określa, że w metodzie można odwoływać się bezpośrednio jedynie do metod obiektów wykorzystywanych w tej metodzie. Celem tego prawa jest ograniczenie zależności. Drugą, mniej oczywistą zaletą tego podejścia jest ułatwienie procesu debuggowania kodu. Dla zobrazowania posłużmy się dwoma fragmentami kodu:
object.call_a().call_b().call_c()
result_a = object.call_a()
result_b = result_a.call_b()
result_b.call_c()
W przypadku wykonywania kodu w trybie krokowym (stepping) w pierwszym przypadku aby wejść do wnętrza metody call_c() należy w pierwszej kolejności wejść do wnętrza metody call_a() a następnie do metody call_b() oraz z tych metod wyjść. W drugim przypadku metoda call_c() jest bezpośrednio dostępna4.
Komentarze
Komentarze w niektórych środowiskach są tematem kontrowersyjnym. Niektórzy uważają, iż komentowanie kodu świadczy o tym, że kod nie jest wystarczająco KISS. Niektórzy podnoszą, że komentarze, na skutek zmian w kodzie, szybko stają się nieaktualne, a przez to mylące. Jest w tym dużo racji, niemniej lepiej mieć komentarz niż go nie mieć5 (pomijając ekstremalne przypadki, gdy linijek komentarza jest więcej niż właściwego kodu), bo nawet przestarzały komentarz świadczy o zmianach w działaniu kodu (taką informację również można wywnioskować poprzez analizę historii zmian w repozytorium). Komentarze nie powinny streszczać działania kodu, a opisywać realizowaną logikę biznesową w uogólniony sposób.
Jest tutaj jeden istotny wyjątek – testy jednostkowe. W tym przypadku komentarz opisujący test powinien zawierać opis scenariusza testowego wraz z przyjętymi założeniami oraz oczekiwanymi rezultatami (czyli niejako powtórzenie tego, co jest zawarte w kodzie testu). Sam test jednostkowy może ulec zmianie, jednak scenariusz testowy powinien być niezmienny, a zapisany komentarz wskazuje co dany test powinien weryfikować. Drugim ważnym do komentowania miejscem są przypadki brzegowe (najczęściej instrukcje warunkowe wyjścia z pętli lub funkcji). Taki komentarz powinien wprost odwoływać się do logiki biznesowej i wyjaśniać, dlaczego sekwencja kodu kończy swoje działanie.
PEP-20
Propozycja ulepszeń języka Python zawiera pythonic way oraz rekomendacje jak pisać dobry i czysty kod. Zasady w głównej mierze wskazują, że kod powinien być pisany dla ludzi, a nie dla maszyn.
Lektura obowiązkowa
Większość z przytoczonych powyżej zasad i dobrych praktyk poruszanych jest również w książce wspomnianego wcześniej autora Roberta C. Martina. Książka Czysty kod. Podręcznik dobrego programisty jest lekturą obowiązkową dla programistów, którzy chcą, aby życie było łatwiejsze a ich kod źródłowy doceniony.
Twój zespół potrzebuje wsparcia we wdrożeniu dobrych praktyk lub potrzebujesz zespół, który posprząta Twój kod?
- więcej o paradygmatach programowania można znaleźć tutaj ↩︎
- również osobiste doświadczenie autora wpisu ↩︎
- w szczególności wskaźników lub referencji ↩︎
- można również ustawić pułapkę (breakpoint) wewnątrz pożądanej metody, ale to jest dodatkowy wysiłek, który trzeba ponieść ↩︎
- niektórzy wskazują, że nieaktualny kod powoduje zamęt i dodatkowy koszt, więc lepiej takiego nie mieć ↩︎
Leave a Reply