/ janturon.cz / Od kodéra k analytikovi / Čistý kód

Čistý kód

Zásady psaní čistého kódu jsou základem jakéhokoliv programování. Syntaxe jazyka to nevyžaduje, ale chápání člověka ano.

Pojmenování   Komentování   Funkce  Odsazování

Pojmenování

Pojmenování každé třídy, funkce, proměnné (dále identifikátor) musí být takové, aby byl pro cizího člověka na první pohled jasný účel.

Zde je účel proměnných d, m, y jasný z kontextu pojmenování funkce setDate:

void setDate(int d, int m, int y);

Zde není účel proměnné jasný:

int d; int day; int issueDay;

Zde kontextuálně ano:

class Invoice { int issueDay; ... }

Název by neměl být příliš dlouhý: ne každý a všude má k dispozici vývojové prostředí s automatickým doplňováním kódu. Navíc je kód pak nečitelný a roztahaný:

ContainerOrderFocusTraversalPolicy myContainerOrderFocusTraversalPolicy = new ContainerOrderFocusTraversalPolicy(); myContainerOrderFocusTraversalPolicy.setImplicitDownCycleTraversal(); 1

Správné pojmenování se sestává ze dvou krátkých slov:

  1. co proměnná/funkce/třída dělá
  2. k čemu se vztahuje

Obojí musí být nezaměnitelné s ničím jiným v kontextu, ve kterém se vyskytuje. Vymyšlení takového správného jména je někdy obtížné (kodéři v ukázkových příkladech často volí jména foo a bar), ale vyplatí se: kód čteme častěji než zapisujeme a při každém čtení dobré jméno ušetří mnoho času a předchází chybám. Pokud nelze vymyslet dobré jméno, téměř jistě jsme se někde dopustili chyby v návrhu. (Toto kritérium lze zobecnit na všechny lidské činnosti: pokud něco nedokážeme stručně a jednoduše vysvětlit, znamená to, že tomu nerozumíme.)

V celém kódu je nutno dodržovat stejnou typografickou konvenci. Dnes převažují:

  1. podtržítková (starší kód): issue_day
  2. velbloudí: issueDay - spolu s pravidlem, kde má a nemá být na začátku velké písmeno: v Javě se velké na začátku píše pouze v názvech tříd, v C# u všech veřejných členů

V objektových jazycích zcela převládla velbloudí konvence, je vhodné zvyknout si na ni.

Konvence nemíchat: pokud přebíráme kód, držíme se původní konvence. Např. Win32Api používá tzv. maďarskou konvenci, což je velbloudí s prefixem typu na začátku jména (např. lpszTitle - long pointer to a string zero-terminated - nízkoúrovňové C pracující s několika vzájemně nekompatibilními formáty řetězců a čísel: ve Win32Api bychom neměli používat jinou konvenci.

Někteří kodéři používají podtržítko před názvy neveřejných členů (např. z důvodu snadné orientace při kontextuální nápovědě). Používáme-li jejich kód, respektujeme to a neupomínáme je, že podtržítko je nadbytečná informace.

2

Protože příkazy jsou v angličtině, je přehledné vše včetně komentářů psát anglicky, obzvlášť v mezinárodním týmu. Neplatí (velmi vyjímečně), pokud je v týmu důležitý člověk angličtinu neovládající.

for(int dny in mesic) { } // špatně for(int days in month) { } // správně

V žádném případě by se v jednom jménu neměly jazyky míchat: je to jen ukázka ledabylosti a neznalosti autora.

int tydenArray[] = {1,2,3,4,5,6,7}; // špatně int weekArray[] = {1,2,3,4,5,6,7}; // správně int tydenPole[] = {...}; // budiž, nezná-li kolega AJ

Komentování

Komentáře by neměly popisovat, co kód dělá: k tomu slouží dobré pojmenování (viz výše). Pokud jsou časté, kodér si na ně vypěstuje slepotu a nahlédne do nich jen tehdy, pokud si s kódem neví rady (což by u dobrého kódu nemělo nastat). Vhodná použití:

  • tam, kde se provádí něco neintuitivního
  • TODO - komentář popisující, co je třeba dodělat v další fázi vývoje
  • jako oddělovač logických částí umístěných v jednom souboru
// --- public ------------------------------------ 3

Zakomentování kódu (comment out) je možné použít pouze ve fázi odstraňování chyby. Žádný zakomentovaný kód nemá nárok na existenci déle než den. Po této lhůtě je možné jej bez přemýšlení smazat: zakomentovaný kód se totiž nevyvíjí a už po první změně systému je zastaralý a nepoužitelný.

Když už komentář píšeme, měli bychom být si s ním dát záležet jako při psaní diplomové práce: stručnost, srozumitelnost, výstižnost, gramatická a stylistická správnost a užitečnost jsou nutné vlastnosti každého komentáře. Každý komentář bychom si měli několikrát přečíst a popřemýšlet, není-li ho možné napsat lépe: bude to číst jiný člověk (nebo my sami s odstupem času) s jinými myšlenkovými pochody - komentář musí pomoci, jinak je zbytečný.

Funkce

function toggleButton(button) { var toggle = function() { button.innerHTML = button.innerHTML=="On"? "Off" : "On"; } if(button.addEventListener) button.addEventListener("click",toggle); else if(button.attachEvent) button.attachEvent("onclick",toggle); }

Výšeuvedená funkce (Javascript) řeší více úrovní abstrakce: obsluhu kliknutí a rozpoznávání prohlížeče v jazyce Javascript. Nižší je vhodné oddělit do samostatné funkce, což také zvýší znovupoužitelnost kódu:

4
function addEvent(target,event,handler) { if(target.addEventListener) target.addEventListener(event,handler); else if(target.attachEvent) target.attachEvent("on"+event,handler); } function toggleButton(button) { var toggle = function() { button.innerHTML = button.innerHTML=="On"? "Off" : "On"; } addEvent(button,"click",toggle); }

I funkce toggle je kandidát na zobecnění:

function toggle(control,yes,no) { return function() { control = control==yes? no : yes; } } function toggleButton(button) { var handler = toggle(button.innerHTML,"On","Off"); addEvent(button,"click",handler); }

Pokud se však v kódu nikde jinde toggle nepoužívá, dopustili bychom se antivzoru unáhlené zobecnění.

5

Každá funkce by měla dělat pouze jednu věc. Pokud je dobře pojmenovaná a s jednou úrovní abstrakce, měla by mít méně než deset řádků. Rozhodně by se měla vejít na jednu obrazovku (25 řádků). Dodržením tohoto pravidla by si funkce měla vystačit s nejvýše třemi argumenty. Pokud musíme používat nápovědu, abychom se ujistili v pořadí argumentů, znamená to, že těch argumentů je příliš mnoho.

Odsazování

Úroveň zanoření se nejčastěji odsazuje dvěma mezerami. Tabelátor není vhodné používat, protože někdo může použít editor, který nahradí tabelátor mezerou, což rozhodí celý kód (jsou vyjímky, např. soubor makefile - tam je tabelátor vyžadován).

Logický úsek kódu (např. provedení cyklu, ukončení podmínky, ukončení práce s nějakým objektem) je vhodné oddělit vertikální mezerou (jedním prázdným řádkem). Metody je pak vhodné oddělovat dvěma prázdnými řádky.

Existují dva uznávané způsoby odsazování složených závorek. První způsob je úspornější: ukončovací závorka jako jediný znak na řádku a prázdný řádek dostatečně opticky rozlišuje konec funkce, ukončovací závorka se vztahuje k nejbližšímu identifikátoru se stejným odsazením.

6
function A() { ... } function B() { ... }

Zastáncům druhého extravertnějšího způsobu zápisu se líbí složené závorky pod sebou natolik, že jsou ochotni úspornost oželet.

function A() { ... } function B() { ... } 7

Způsob odsazování je věcí dohody v týmu, v kódu by se ale měl používat pouze jeden. Vyjímečně je možné toto pravidlo porušit, pokud to vede ke zpřehlednění kódu - viz např. funkci toggleButton výše.

Jeden příkaz by se měl vejít na jednu řádku (80-120 znaků). Není vhodné provádět spojování příkazů (např. pomocí vnořování) tam, kde by toto pravidlo bylo porušeno:

// přehledněji var toggle = function() { button.innerHTML = button.innerHTML=="On"? "Off" : "On"; } addEvent(button,"click",toggle); // nepřehledněji addEvent(button,"click",function() { button.innerHTML = button.innerHTML=="On"? "Off" : "On"; } ); 8