Czym jest czysty kod?
Czysty kod to kod pisany nie tylko po to, aby się kompilował i działał, lecz także po to, aby inni programiści mogli zrozumieć jego intencję, a później bezpiecznie go modyfikować, rozszerzać i weryfikować. Nie jest to pojęcie zdefiniowane przez jeden ścisły międzynarodowy standard ani wynik. Jest to raczej praktyczny termin obejmujący cele jakościowe, takie jak czytelność, zrozumiałość, utrzymywalność, spójność i bezpieczeństwo zmian. google.github.io
Na początku łatwo uznać go po prostu za „ładnie wyglądający kod”. W praktyce jednak istotne momenty następują po pierwszym napisaniu kodu: podczas poprawiania funkcji, znajdowania błędu, dodawania wymagania lub przeglądania pracy współpracownika. Czysty kod polega bardziej na ograniczaniu czasu i prawdopodobieństwa pomyłek w takich sytuacjach. Dlatego kluczowe nie jest zapamiętywanie konkretnych technik składniowych, lecz rozważanie, czego czytelnik musi się dowiedzieć i na jakie miejsca wpłynie zmiana.
Co dokładnie oznacza czysty kod?
Oprogramowanie nie jest dokumentem, który zapisuje się raz i uznaje za ukończony. Do istniejącego kodu wraca się przy dodawaniu statusu zamówienia, zmianie reguły cenowej lub badaniu błędu. Czytelnikiem może być pierwotny programista, ale często jest nim inny członek zespołu albo Ty z przyszłości. Czysty kod oznacza stan, w którym taki czytelnik może stosunkowo szybko zrozumieć rolę kodu, jego dane wejściowe i wyjściowe, ważne warunki oraz prawdopodobne miejsca zmian.
„Czysty” nie oznacza tu wyłącznie oceny estetycznej. Na przykład nawet dobrze sformatowany kod jest ryzykowny w modyfikacji, jeśli jego nazwy są niejednoznaczne, kilka odpowiedzialności miesza się w jednej funkcji i nie ma sposobu na jego zweryfikowanie. Z drugiej strony kod może być lepszy z perspektywy utrzymania, jeśli jego rola jest jasna, pasuje do konwencji zespołu i ma testy potwierdzające zmiany, nawet jeśli nie wykorzystuje szczególnie charakterystycznego stylu. Przegląd kodu ocenia nie tylko styl, ale także projekt, poprawność funkcjonalną, złożoność, testowanie i dokumentację. google.github.io
Termin „czysty kod” stał się szeroko znany dzięki książce Roberta C. Martina Clean Code z 2008 roku. Zalecenia z tej książki są jednak osadzone w kontekście konkretnych języków i praktyk programowania obiektowego. Zamiast bez zmian stosować książkę lub znaną regułę do każdego języka i każdego rozmiaru programu, lepiej ocenić, czy rozwiązuje ona problem w obecnym kodzie i zespole. www.informit.com
Dlaczego kod, który działa, nie wystarcza?
Uzyskanie oczekiwanego wyniku dla obecnych danych wejściowych jest najbardziej podstawowym wymaganiem programu. Jednak nawet poprawna funkcjonalność jest trudna do zarządzania w długim okresie, jeśli łatwo psuje się przy kolejnej zmianie. Na przykład długa funkcja może zawierać obliczanie rabatu, kontrolę uprawnień, renderowanie widoku i zapis danych. Może działać teraz, lecz osoba próbująca zmienić wyłącznie politykę rabatową z większym prawdopodobieństwem wpłynie również na obsługę uprawnień lub kolejność zapisu.
Kod trudny do przeczytania to nie tylko kwestia dłuższego czytania. Bez pewności co do intencji programiści mogą kopiować podobną logikę, modyfikować szerszy obszar niż trzeba albo odtwarzać reguły, które już istnieją. Recenzenci również mają trudność z oceną wpływu zmiany. Utrzymywalność to właściwość polegająca na tym, że przyszłe zmiany nie są blokowane, a czysty kod koncentruje się na poprawie tej utrzymywalności.
Mimo to nikt nie jest w stanie z góry wyeliminować wszystkich kosztów przyszłych zmian. Gdy same wymagania są złożone lub systemy zewnętrzne narzucają silne ograniczenia, kod także będzie do pewnego stopnia złożony. Lepszym celem nie jest udawanie, że rzeczywistość jest prosta, ale odróżnianie złożoności możliwej do uniknięcia od złożoności nieuniknionej. Jeżeli złożoność jest konieczna, jej przyczyna powinna być widoczna w strukturze, nazwach, testach i dokumentacji.
Jak dobre nazwy ujawniają intencję kodu?
Nazwy są informacją, z którą czytelnicy spotykają się najczęściej podczas pierwszego rozumienia kodu. Ogólne nazwy, takie jak x, data, process i flag, mogą być znajome dla autora, ale nie mówią innym, co reprezentują. Nazwy takie jak expiredCouponCount, isEligibleForRefund i calculateShippingFee stosunkowo bezpośrednio komunikują natomiast cel wartości lub operacji. Znaczące nazwy są także sposobem na przeniesienie do samego kodu informacji, które w przeciwnym razie musiałyby zostać wyjaśnione w komentarzach. google.github.io
Dobre nazewnictwo jest kwestią konkretności, a nie długości. Powszechnie uzgodnione pojęcie w małym zakresie może mieć krótką nazwę, podczas gdy wartość używana w szerszym zakresie może wymagać większego kontekstu. Na przykład indeks pętli i może być zrozumiały w bardzo krótkiej pętli. Jeżeli jednak wartość zwracana przez funkcję lub pole obiektu nazywa się tylko result, trudno ustalić, czy oznacza sukces, kwotę czy wynik zapytania.
Pomocne jest również odróżnianie czasowników od rzeczowników. Czytanie przebiega zwykle naturalnie, gdy funkcje mają nazwy oparte na czasownikach, które ujawniają, co robią, a wartości i obiekty mają nazwy oparte na rzeczownikach, które ujawniają, czym są. sendReceipt() to działanie, a receiptEmail to dane. Wydłużenie nazwy nie usuwa jednak automatycznie niejednoznaczności. handleUserData jest dłuższe, ale nadal nie wiadomo, czym się zajmuje.
// Example with unclear intent
if (a) {
doIt(b);
}
// Example where the purpose of the condition and action is visible
if (isPaymentApproved) {
sendOrderConfirmation(order);
}
Nazwy w drugim przykładzie nadal należy dostosować do rzeczywistego kontekstu. Chodzi o to, aby czytelnicy mogli zrozumieć ważną decyzję bez konieczności szukania daleko definicji a i b. W porównaniu ze strukturą, w której komentarze powtarzają to, co już wyjaśniają nazwy, samowyjaśniające się nazwy i kompozycja kodu stwarzają mniejsze ryzyko, że wyjaśnienie zdezaktualizuje się po zmianie.
Jak bardzo należy dzielić funkcje i strukturę?
Gdy funkcja lub moduł robi zbyt wiele rzeczy, czytelnicy muszą jednocześnie trzymać w głowie kilka reguł. Jeżeli walidacja danych wejściowych, obliczenia, wywołania zewnętrzne, obsługa błędów i formatowanie wyniku są zmieszane w jednym bloku, zmiana jednej części może wymagać zrozumienia całego przepływu. Rozdzielenie powiązanych kroków na nazwane jednostki może ułatwić czytanie przepływu na wysokim poziomie.
Na przykład proces potwierdzania zamówienia można przedstawić krokami takimi jak validateOrder, calculateTotal, reserveInventory i createPayment, które wyrażają przepływ biznesowy. Celem rozdzielenia nie jest zwiększanie liczby funkcji, lecz ułatwienie odczytania odpowiedzialności i kolejności każdego kroku. Jeżeli wyodrębniona funkcja ma tylko jedną linię, a jej nazwa jest mniej zrozumiała niż pierwotne wyrażenie, trudno uznać, że ekstrakcja poprawia zrozumienie.
Nadmierne dzielenie tworzy odwrotny problem. Czytelnicy mogą musieć przechodzić między wieloma plikami i cienkimi funkcjami, aby zrozumieć jedno działanie. Abstrakcje, takie jak interfejsy lub typy, mają zaletę ukrywania szczegółów implementacyjnych, ale mogą również ukrywać potrzebny kontekst. Abstrakcję należy stosować wtedy, gdy daje wyraźną korzyść, a nie przyjmować założenie, że „więcej abstrakcji zawsze oznacza lepszy projekt”. google.github.io
Decyzję o podziale można więc oceniać za pomocą takich pytań:
- Czy ta część ma rolę, którą można wyjaśnić niezależnie?
- Czy jej nazwa wyjaśnia intencję lepiej niż przeczytanie wewnętrznego kodu?
- Czy ta sama reguła powtarza się w wielu miejscach, co daje powód, aby zebrać ją w jednym miejscu?
- Czy tworzy granicę, dzięki której przy zmianie trzeba badać tylko tę część?
- Czy po rozdzieleniu śledzenie wywołań sprawia, że cały przepływ staje się mniej jasny?
Te pytania nie dają odpowiedzi automatycznie. Kierują jednak uwagę na rzeczywisty koszt zrozumienia kodu przez czytelników, zamiast na powierzchowne reguły, takie jak „krótkie funkcje”.
Czy prostota oznacza mniej funkcji?
W czystym kodzie prostota nie oznacza rezygnacji z potrzebnej funkcjonalności. Jest bliższa unikaniu niepotrzebnych struktur, nieużywanych punktów rozszerzeń i trudnych do zrozumienia objazdów, których nie wymagają bieżące wymagania. Jeśli uogólniasz rozwiązanie wyłącznie na podstawie przypuszczeń dotyczących przyszłych potrzeb, obecni czytelnicy muszą zrozumieć przypadki, które jeszcze nie istnieją.
Na przykład zbudowanie z góry wielowarstwowego systemu wtyczek dla małej funkcji z tylko jedną metodą płatności może stworzyć możliwość przyszłej rozbudowy. Zwiększa jednak także liczbę bieżących ścieżek kodu, konfiguracji i kombinacji, które trzeba przetestować. Z drugiej strony, jeśli dodawanie metod płatności jest już potwierdzone, a ich reguły znacznie się różnią, utworzenie wspólnej granicy może ograniczyć przyszłe zmiany. Żaden z tych wyborów nie jest z góry zawsze lepszy.
Prostota nie oznacza również „najmniejszej liczby linii kodu”. Skondensowanie wielu warunków i przekształceń w jednej linii może wydawać się autorowi sprytne, ale osoba modyfikująca kod musi interpretować priorytety i wyjątki. Z kolei użycie odpowiednio nazwanych wartości pośrednich i rozdzielenie warunków może zwiększyć liczbę linii, a jednocześnie uprościć proces rozumowania. Wytyczne dotyczące przeglądu kodu podkreślają również, że przyszli programiści powinni móc kod czytać, rozumieć i modyfikować. google.github.io
W praktyce warto rozważać łącznie dwa rodzaje prostoty. Pierwszy to prostota samej implementacji: czy jest mało niepotrzebnych stanów, rozgałęzień, zależności i duplikacji. Drugi to prostota użycia i zmiany: czy wywołujący mogą łatwo używać rozwiązania poprawnie oraz czy jasne jest miejsce modyfikacji, gdy zmieniają się reguły. Wybór, który upraszcza użycie zewnętrzne, może być czasem lepszy, nawet jeśli wnętrze jest nieco bardziej złożone.
Dlaczego spójny styl jest potrzebny i dlaczego nie wystarcza?
Gdy wcięcia, łamanie linii, organizacja plików i konwencje nazewnictwa są różne, czytelnicy muszą za każdym razem interpretować format. Konsekwentne stosowanie stylu uzgodnionego przez zespół może zmniejszyć uwagę poświęcaną powierzchownym różnicom w kodzie. Narzędzia mechanicznie sprawdzające reguły, takie jak automatyczne formatery i lintery, mogą być szczególnie przydatne w tej powtarzalnej pracy.
Samo przestrzeganie stylu nie czyni jednak kodu czystym. Nawet jeśli każda nazwa stosuje tę samą konwencję, role nadal mogą być niejasne; nawet jeśli długości linii są poprawne, projekt może pozostać nadmiernie splątany. Ocena jakości kodu zakłada, że oprócz stylu należy uwzględniać projekt, funkcjonalność, złożoność, testowanie i dokumentację. google.github.io
Przy stosowaniu reguł stylu zazwyczaj praktyczne jest respektowanie istniejących konwencji zespołu. Wypróbowanie preferowanej notacji w jednym nowym pliku może wydawać się drobne, lecz może osłabić spójność całego projektu. Z drugiej strony istniejącą konwencję można omówić i zmienić, jeśli ulepszenie istotnie zwiększa jasność. Ważne nie jest rywalizowanie o to, która reguła jest bardziej elegancka, lecz to, czy zespół może konsekwentnie czytać i zmieniać kod.
Przegląd kodu wymaga także odróżniania drobnych różnic preferencji od problemów wpływających na utrzymywalność. Wymaganie perfekcji przy każdej zmianie może spowolnić samo ulepszanie. Jeżeli zmiana ogólnie poprawia utrzymywalność, czytelność i zrozumiałość, jej stopniowa akceptacja może być bardziej realistyczna. google.github.io
Jaki jest związek między testami a czystym kodem?
Testy są wykonywalnym sposobem weryfikacji zachowania obiecywanego przez kod. Obietnica oznacza tutaj obserwowalne zachowanie, takie jak „opłacane są tylko prawidłowe zamówienia”, „zamówienie, które zostało już anulowane, nie jest anulowane ponownie” lub „po spełnieniu warunków rabatu odliczana jest określona kwota”. Testy stanowią podstawę do sprawdzenia, czy po zmianie nie zepsuło się krytyczne zachowanie.
Jeśli czysty kod postrzega się wyłącznie jako kod dobrze wyglądający, testy mogą wydawać się od niego odrębne. Jednak przy definicji obejmującej bezpieczną modyfikację są one kluczowe. Podczas porządkowania struktury trzeba móc potwierdzić zachowanie zewnętrzne, a przy dodawaniu nowej reguły trzeba sprawdzić, czy stare reguły nie zostały przypadkowo naruszone. Kod możliwy do utrzymania powinien mieć testy weryfikujące podstawową logikę i obiecane zachowanie oraz pomagające zidentyfikować przyczynę awarii. google.github.io
Sama duża liczba testów nie gwarantuje jakości. Testy zbyt mocno powiązane z drobną wewnętrzną kolejnością mogą utrudniać nawet uzasadnione ulepszenia strukturalne. Z kolei testy pomijające ważne warunki brzegowe i reguły biznesowe mogą nie wnosić wystarczającego wkładu w bezpieczeństwo zmian, nawet jeśli jest ich wiele. Nazwy testów i struktura arrange-act-assert również powinny być pisane jasno, aby czytelnicy wiedzieli, co jest gwarantowane.
Na przykład jeśli logika oblicza okres kwalifikowalności do zwrotu, bardziej sensowne jest testowanie granic rzeczywistej reguły — takich jak sam dzień terminu, moment bezpośrednio po terminie i brakujące dane wejściowe — niż sprawdzanie wyłącznie zwykłych dat. To, które przypadki należy testować, zależy od wymagań produktu i ryzyka. Kluczowe jest, aby testy komunikowały nie tylko, że „kod istnieje”, ale „które zachowanie musi zostać zachowane”.
Kiedy komentarze i dokumentacja są potrzebne?
Komentarze nie są złe. Są szczególnie wartościowe, gdy przekazują kontekst, który trudno wyrazić w kodzie. Na przykład same nazwy mogą niewystarczająco przekazywać obejście nieprawidłowego zachowania usługi zewnętrznej, ograniczenia prawne lub umowne, wybór oparty na pomiarach wydajności albo powód tymczasowego kodu zgodności, który zostanie usunięty po określonej dacie. Informacja ta pomaga przyszłym opiekunom kodu zrozumieć, dlaczego nie powinni zastępować rozwiązania prostszym podejściem. google.github.io
Z kolei komentarze, które jedynie tłumaczą to, co kod już mówi, mogą z czasem rozjechać się z kodem. Komentarz „zwiększ licznik o 1” obok count = count + 1 nie dodaje żadnej nowej informacji. W takim przypadku lepsza nazwa lub bardziej bezpośrednia struktura mogą mieć pierwszeństwo. Im dłuższe są komentarze, tym bardziej warto sprawdzić, czy nie sygnalizują niejasnej intencji kodu.
Odpowiednie miejsce dla dokumentacji również może być różne. Lokalny powód wewnątrz funkcji może pasować do pobliskiego komentarza. Zasady użycia, metody konfiguracji i warunki zgodności współdzielone przez wiele modułów mogą być łatwiejsze do znalezienia w osobnej dokumentacji lub opisach interfejsów. Niezależnie od miejsca ważne jest zapewnienie czytelnikom kontekstu potrzebnego do podejmowania decyzji oraz aktualizowanie go razem ze zmianami w kodzie.
Czym różnią się czysty kod, refaktoryzacja i styl kodowania?
Te trzy terminy są często wymieniane razem, ale pełnią różne role. Czysty kod to stan jakościowy lub perspektywa nastawiona na kod łatwy do zrozumienia i zmiany. Refaktoryzacja to działanie polegające na ulepszaniu struktury wewnętrznej przy zachowaniu obserwowalnego z zewnątrz zachowania. Styl kodowania to konwencja sposobu wyrażania kodu, taka jak wcięcia, notacja nazewnictwa i odstępy.
| Kategoria | Kluczowe pytanie | Zakres |
|---|---|---|
| Czysty kod | Czy ten kod można zrozumieć i bezpiecznie zmienić? | Nazwy, struktura, złożoność, testy, dokumentacja, spójność |
| Refaktoryzacja | Jak można ulepszyć strukturę przy zachowaniu zachowania? | Działanie na rzecz ulepszenia struktury |
| Styl kodowania | W jakim formacie zespół wyraża kod? | Konwencje zapisu i formatowania |
Refaktoryzacja jest jednym ze sposobów tworzenia lub utrzymywania czystego kodu. Na przykład zduplikowane obliczenia ceny można zebrać w jednym miejscu, niejednoznaczne nazwy można zmienić, a warunki można uporządkować w łatwiejsze do zrozumienia jednostki. Jednak zmiany strukturalne wprowadzane bez potwierdzenia zachowania mogą być ryzykowne, dlatego testy i przegląd są ważne.
Styl zmniejsza tarcie we współpracy, ale nie rozwiązuje automatycznie problemów projektowych. Z drugiej strony jasny kod o działającej strukturze nie jest automatycznie zły tylko dlatego, że jego styl nieznacznie się różni. Zrozumienie tego rozróżnienia ogranicza błąd polegający na traktowaniu problemów formatowania i rzeczywistych zagrożeń dla utrzymania z jednakową wagą podczas przeglądów. google.github.io
Co powinno mieć priorytet, gdy istnieją ograniczenia wydajnościowe i bezpieczeństwa?
Nacisk czystego kodu na prostotę i jasność nie oznacza poświęcania wydajności, bezpieczeństwa, zgodności ani niezawodności operacyjnej. Na przykład pamięć podręczna wymagana dla wydajności, kroki walidacji wymagane dla bezpieczeństwa lub obsługa zgodności ze starym systemem zewnętrznym mogą zwiększać złożoność kodu. Jeżeli ta złożoność wynika z rzeczywistych wymagań i wyników pomiarów, może być bardziej odpowiednia niż alternatywa, która jedynie wygląda na prostszą.
W tej sytuacji ważne jest nieukrywanie złożoności. Ograniczenia, zachowanie, które musi być gwarantowane, oraz powody niestosowania konwencjonalnej implementacji można uwidocznić przez nazwy, strukturę, testy i konieczne komentarze. Do takich decyzji odnosi się zasada dawania pierwszeństwa faktom technicznym i danym przed osobistymi preferencjami. google.github.io
Na przykład jeśli łatwa do przeczytania implementacja nie spełnia wymagań dotyczących czasu odpowiedzi w rzeczywistym środowisku produkcyjnym, istnieje powód, aby wybrać bardziej złożoną implementację. Nie jest jednak pożądane komplikowanie całego kodu wyłącznie na podstawie założenia, że dzieje się to „dla wydajności”. Po zmierzeniu problemu i potwierdzeniu wymagań należy porównać zarówno koszty, jak i korzyści złożoności.
To samo dotyczy bezpieczeństwa. Kroki takie jak walidacja danych wejściowych, kontrola autoryzacji i obsługa błędów mogą wydłużyć przepływ kodu. Nie oznacza to, że można je pominąć, aby kod był krótszy. Dobra struktura umieszcza te konieczne kroki tam, gdzie łatwo je rozpoznać, i pomaga zapobiec arbitralnemu rozproszeniu wrażliwych reguł w całej bazie kodu.
Jakie są częste błędne przekonania o czystym kodzie?
Pierwsze błędne przekonanie brzmi: „krócej zawsze znaczy lepiej”. Krótkie funkcje i zwięzłe wyrażenia mogą pomagać, ale liczba linii nie jest kryterium. Nadmierne dzielenie i abstrahowanie mogą wydłużać ścieżki wywołań i ukrywać kontekst. Zamiast pytać, czy kod stał się krótszy, zapytaj, czy czytelnicy mogą łatwiej zrozumieć główny przepływ i jego powody. google.github.io
Drugie błędne przekonanie brzmi: „mniej komentarzy zawsze znaczy lepiej”. Idea wyrażania przez nazwy i strukturę treści, które kod może wyjaśnić sam, nie oznacza usuwania użytecznych informacji kontekstowych. W szczególności powody wyborów i zewnętrzne ograniczenia mogą wymagać pozostawienia w komentarzach lub dokumentacji. Dobre komentarze nie powtarzają kodu; dostarczają kontekstu trudnego do poznania na podstawie samego kodu. google.github.io
Trzecie błędne przekonanie brzmi: „kod jest dobry tylko wtedy, gdy przestrzega każdej reguły”. Zalecenia są narzędziami oceny, a nie kodeksem prawnym mającym zastosowanie w każdej sytuacji. Priorytety różnią się w zależności od cech języka, istniejących konwencji projektu, wymagań wydajnościowych i bezpieczeństwa oraz doświadczenia zespołu. Ważniejsze jest sprawdzenie, czy zastosowanie reguły rzeczywiście czyni kod jaśniejszym.
Czwarte błędne przekonanie brzmi: „projekt musi być perfekcyjny od początku”. Wymagania się zmieniają, a niektórych informacji nie można poznać na początku. Zamiast opóźniać zmiany w pogoni wyłącznie za perfekcją, bardziej realistyczne jest dalsze wprowadzanie małych ulepszeń, które ogólnie ułatwiają czytanie i utrzymanie bieżącego systemu. google.github.io
Jak w praktyce oceniać czysty kod?
Trudno ocenić go wyłącznie na podstawie bezwzględnej listy kontrolnej, ale przy zmianie można zadać sobie kilka pytań. Najpierw zastanów się, czy osoba widząca kod po raz pierwszy potrafi wyjaśnić jego główny cel. Następnie przy zmianie jednej reguły sprawdź, czy miejsce modyfikacji jest stosunkowo jasne, czy też trzeba zmieniać również niepowiązane obszary. Na koniec potwierdź, czy istnieją testy albo metody przeglądu pozwalające zweryfikować podstawowe zachowanie po zmianie.
Oto praktyczne pytania przydatne podczas pisania lub przeglądania funkcji:
- Czy można w przybliżeniu zrozumieć rolę wartości, funkcji lub modułu na podstawie samej nazwy?
- Czy jedna funkcja niepotrzebnie miesza różne reguły biznesowe albo operacje zewnętrzne?
- Czy ta sama ważna reguła jest kopiowana w wielu miejscach?
- Czy rozwiązanie naturalnie pasuje do konwencji zespołu dotyczących nazewnictwa, formatowania i organizacji plików?
- Czy w razie potrzeby zapisano powody wyborów lub ograniczenia, których kod nie może wyrazić?
- Czy istnieje sposób weryfikacji podstawowego zachowania i ryzykownych warunków brzegowych?
- Czy uproszczenie nie pominęło wymagań dotyczących wydajności, bezpieczeństwa lub zgodności?
- Czy abstrakcja lub rozdzielenie rzeczywiście zmniejszają koszt zrozumienia, czy tylko wydłużają ścieżkę, którą muszą przejść czytelnicy?
Nie musisz od razu odpowiadać na wszystkie te pytania. Próba rozwiązania każdego problemu projektowego w małej zmianie może zatrzymać przegląd. Praktyczne jest najpierw naprawianie problemów o dużym wpływie, a resztę kierować w lepszą stronę w kolejnych zmianach. Celem przeglądu kodu może być również ciągłe poprawianie utrzymywalności, czytelności i zrozumiałości systemu, a nie tworzenie perfekcyjnego kodu. google.github.io
Wnioski: czysty kod to jakość dla zmian, a nie stały format
Czysty kod nie oznacza wyłącznie listy reguł z konkretnej książki ani schludnego formatowania. To perspektywa jakościowa, która uwidacznia intencję kodu w nazwach i strukturze, ogranicza niepotrzebną złożoność, umożliwia spójne czytanie w zespole i pozwala weryfikować zachowanie po zmianach. Komentarze służą do przekazywania kontekstu, testy wspierają bezpieczeństwo zmian, a abstrakcje stosuje się wtedy, gdy rzeczywiście ułatwiają zrozumienie i zmianę.
Forma dobrego kodu może różnić się między projektami. Ważne nie jest to, czy wygląda krótko albo przestrzega znanej reguły, lecz czy kolejny programista może go poprawnie zrozumieć i zmienić przy obecnych wymaganiach i ograniczeniach. Ciągłe ulepszanie małych nazw, warunków, testów i struktur z tej perspektywy jest praktycznym punktem wyjścia dla czystego kodu. google.github.iogoogle.github.io