1. diel - Najčastejšie chyby programátorov - Vieš pomenovať premenné?
Vitajte pri prvom tutoriále kurzu Best practices pre návrh softvéru! Naučíme sa predchádzať častým chybám a navrhovať svoje aplikácie tak, aby sa po čase nestali neprehľadné a bolo ich možné ľahko rozširovať. V praxi sú aplikácie často veľmi rozsiahle a tieto znalosti potom úplne kľúčové na odvedenie dobrej práce. Práve umenie programovať správne robí z juniorov mediorov a seniorov a posúva vás na platovej škále dopredu.
Keďže si zakladáme na kvalite našich absolventov, nevyhnutné minimum z tohto kurzu je v podobe niekoľko lekcií už obsiahnutých priamo v tunajších kurzoch programovania. Je teda možné, že ste sa s niektorými, najmä prvými časťami kurzu, už stretli. Ak áno, získate tu samozrejme ďalšiu porciu informácií, ktoré naštartujú vašu programátorskú kariéru a zabránia veľa problémom, ktoré by ste inak mohli urobiť.
Slovo senior programátora
Materiál pre tento kurz som zostavil na základe 20-ročných skúseností s programovaním. Ako šéfredaktorovi a lektorovi mi rukami prešli stovky, možno tisíce zdrojových kódov vytvorených komunitou. Nebolo ťažké si všimnúť, že väčšina z nich, hoci funguje, obsahuje zbytočné chyby, ktoré sa navyše stále dookola opakujú. Chyby napodiv často robili ako nováčikovia, tak skúsenejší programátori a aj ja som ich robil, keď som začínal.
Došiel som k tomu, že základným a mylným predpokladom je:
✗ Program je správne, ak funguje.
Programy a domy
Pokiaľ staviame dom, že sa nám páči a nefúka do neho neznamená, že je správne. Dom totiž musí mať premyslenú architektúru a pokiaľ nemá základy, o pár rokov sa nám začne zosúvať.
Programovanie je často prirovnávané k stavebníctvu práve z ohľadu na architektúru, tu však tú softvérovú. Vysvetlime si prečo.
Ľudský mozog dokáže naraz pracovať len s určitým obmedzeným množstvom informácií. Zjednodušene môžeme povedať, že pokiaľ je program neprehľadne napísaný, od určitej chvíle by musel programátor udržať v hlave viac vecí, než človek vôbec dokáže. Pridávanie ďalších funkcií do takého programu potom vždy spôsobí, že v aplikácii vznikne chyba. V praxi to dopadá tak, že hobby projekt autora "prestane baviť" alebo komerčný projekt skrachuje, pretože je "už veľmi zložitý".
Uveďme si ešte iný príklad – Keď bude naša domácnosť usporiadaná tak, že bude kladivo v lekárničke, ktorá bude umiestnená v pivnici, asi ťažko v nej budeme schopní efektívne fungovať. Hoci tento príklad znie absurdne, jeho alternatívy v podobe programov vznikajú denne.
Kedy je program správne?
To je ľahké. Program je správne, ak:
- funguje,
- dodržiava dobré praktiky a
- je otestovaný.
Všimnite si, že funkcionalita z pohľadu užívateľa programu predstavuje len 1/3 kritérií kvality programu. Podobne ako funkčnosť domu z pohľadu bývajúceho predstavuje asi iba zlomok jeho reálnej kvality z hľadiska staviariny.
Práve o porušovaní dobrých praktík a kvalite kódu sa budeme v tomto kurze baviť. Záleží nám na tom, aby ste boli naozaj dobrí a dokázali si poradiť aj s väčšími aplikáciami, v ktorých každá chyba napučí do nepríjemných rozmerov.
Ako správne pomenovávať premenné?
V dnešnej lekcii sa budeme zaoberať premennými. Hovorí sa, že 10 % času niečo programujeme a 90 % času pre to vymýšľame názov Ide samozrejme o zveličenie, ale vtip naráža na nutnosť stráviť určitý čas nad vymýšľaním názvov premenných. To aby každý vo vývojovom tíme vrátane nás vracajúcich sa po pár mesiacoch k vlastnému kódu, pochopil, na čo ona premenná slúži. Všeobecne sa dá spoľahnúť na jednoduché pravidlo:
Premenné vždy pomenovávame podľa toho, čo obsahujú, nie podľa toho, na čo v programe slúžia.
Porovnajme nasledujúce 2 kódy:
-
✗ Špatně
String output, text2; int[] arr; int foo, bar, x, calculation;
✓ Správně
String title, name; int[] answers; int i, j, bonus, totalBonus;
-
✗ Špatně
string output, text2; int[] arr; int foo, bar, x, calculation;
✓ Správně
string title, name; int[] answers; int i, j, bonus, totalBonus;
-
✗ Špatně
string output, text2; int arr[5]; int foo, bar, x, calculation;
✓ Správně
string title, name; int answers[5]; int i, j, bonus, totalBonus;
-
✗ Špatně
output = "" text2 = "" arr = [] foo = 0 bar = 0 x = 0 calculation = 0
✓ Správně
title = "" name = "" answers = [] i = 0 j = 0 bonus = 0 total_bonus = 0
-
✗ Špatně
var output = "" var text2 = "" var arr = [Int]() var foo = 0 var bar = 0 var x = 0 var calculation = 0
✓ Správně
var title = "" var name = "" var answers = [Int]() var i = 0 var j = 0 var bonus = 0 var totalBonus = 0
-
✗ Špatně
$output = ""; $text2 = ""; $arr = []; $foo = 0; $bar = 0; $x = 0; $calculation = 0;
✓ Správně
$title = ""; $name = ""; $answers = []; $i = 0; $j = 0; $bonus = 0; $totalBonus = 0;
-
✗ Špatně
let output = ""; let text2 = ""; let arr = []; let foo = 0; let bar = 0; let x = 0; let calculation = 0;
✓ Správně
let title = ""; let name = ""; let answers = []; let i = 0; let j = 0; let bonus = 0; let totalBonus = 0;
Oba kódy vytvárajú premenné pre jednoduchý konzolový kvíz. Pri prvom
príklade nie je vôbec jasné, čo niektoré premenné obsahujú, napr.
pomenovať pole arr
má asi rovnakú vypovedaciu hodnotu, ako by
sme ho pomenovali variable
.
Častá chyba je, že chceme napr. uložiť výsledok
nejakého výpočtu a premennú pomenujeme
calculation
. Výpočet s premennou však vôbec nesúvisí, to je
nejaká akcia (dej), premenná obsahuje vždy
hodnotu (výsledok deja). Tou je tu v prípade kvízu
totalBonus
(alebo total_bonus
, oddeľovanie slov
záleží na konvenciách daného programovacieho jazyka, viď. ďalej). Podobne
je v prvom kóde premenná pomenovaná output
, pretože ju niekde
vypisujeme. Z druhého kódu ale reálne vidíme, že obsahuje názov
kvízu.
Ruku na srdce - kto z vás by pochopil, že prvý kód je program na kvízy?
Tiež nikdy nepomenovávame pomocné premenné
temporary
alebo temp
.
Pozor na mixovanie jazykov a diakritiku
Na úrovni začiatočníkov je prehľadnejšie premenné pomenovávať po slovensky. V praxi sa však stretnete takmer vždy s anglicky písaným kódom, preto aj naše pokročilejšie kurzy obsahujú identifikátory pomenované anglicky.
Premenné v jednom projekte pomenovávame jedným jazykom, ideálne anglicky. Ak ich pomenujeme po slovensky, tak bez diakritiky!
Opäť si ukážme príklady:
-
✗ Špatně
String správa = "Hi!"; int count;
✓ Správně
String message = "Hi!"; int count;
-
✗ Špatně
string správa = "Hi!"; int count;
✓ Správně
string message = "Hi!"; int count;
-
✗ Špatně
string správa = "Hi!"; int count;
✓ Správně
string message = "Hi!"; int count;
-
✗ Špatně
správa = "Hi!" count = 0
✓ Správně
message = "Hi!" count = 0
-
✗ Špatně
var správa = "Hi!" var count = 0
✓ Správně
var message = "Hi!" var count = 0
-
✗ Špatně
$správa = "Hi!"; $count = 0;
✓ Správně
$message = "Hi!"; $count = 0;
-
✗ Špatně
let správa = "Hi!"; let count = 0;
✓ Správně
let message = "Hi!"; let count = 0;
V identifikátoroch (napr. v názvoch premenných) nikdy nepoužívame háčiky a čiarky. V hodnotách v nich uložených je to už samozrejme v poriadku.
Napriek tomu, že moderné jazyky podporujú kódovanie UTF-8 aj v identifikátoroch, možno veľmi ľahko na háčik alebo čiarku zabudnúť a používame potom inú premennú ! Navyše, súbor so zdrojovým kódom môže spracovávať aplikácia, ktorá ho nepodporuje, a typicky sa to aj časom stane (napr. je občas problém zobraziť diakritiku v prílohe mailovým klientom a pod.).
Viacslovné premenné
Dnešné aplikácie sú čoraz zložitejšie. Často sa stane, že by jedno
slovo nestačilo na opis toho, čo je v premennej uložené. Potom je výhodné
použiť viac slov. Krátke identifikátory z 80. rokov tak v súčasných
business aplikáciách striedajú aj pomerne dlhé názvy ako
userObjectOutputStreamFactory
a podobne.
Takto dlhý názov má však zmysel iba v zložitej
aplikácii, kde je niekoľko podobných premenných a preto musíme pridať
ďalšie slovo. Nebudeme teda v Hello world aplikácii vytvárať premennú
textWithGreetingHelloWorld
, ale stačí nám tam len
greeting
, pokiaľ tam iný pozdrav nie je
Oddelenie slov
Kvôli čitateľnosti slova v takom názve premennej musíme nejako oddeliť:
- Viac slov oddeľujeme podľa konvencie daného programovacieho jazyka. V
Jave/C#/JS je to tzv.
camelCase
(slovensky ťavia notácie, kedy každé ďalšie slovo má veľké písmeno a názov potom vyzerá ako hrby). V jazykoch ako je Python/C sa používa podčiarknutie akosnake_case
(pre triedy sa v Pythone používaPascalCase
, viď ďalej v kurze). - Vyhneme sa, pokiaľ možno, číslovaniu premenných a už vôbec nepíšeme
čísla slovami, nie
greet2
anigreetTwo
.Two
totiž nič nehovorí o tom, čo pozdrav obsahuje.
Ukážme si to na príkladoch:
-
✗ Špatně
String message; String messageTwo;
Tu nie je jasné, čo je uložené:
String received; // text, bytes, message, order, ...? String sent;
A tu je názov nečitateľný:
String receivedmessage; String sentmessage;
✓ Správně
String receivedMessage; String sentMessage;
-
✗ Špatně
string message; string messageTwo;
Tu nie je jasné, čo je uložené:
string received; // text, bytes, message, order, ...? string sent;
A tu je názov nečitateľný:
string receivedmessage; string sentmessage;
✓ Správně
string receivedMessage; string sentMessage;
-
✗ Špatně
string message; string messageTwo;
Tu nie je jasné, čo je uložené:
string received; // text, bytes, message, order, ...? string sent;
A tu je názov nečitateľný:
string receivedmessage; string sentmessage;
✓ Správně
string receivedMessage; string sentMessage;
-
✗ Špatně
message = "" messageTwo = ""
Tu nie je jasné, čo je uložené:
received = "" # text, bytes, message, order, ...? sent = ""
A tu je názov nečitateľný:
receivedmessage = "" sentmessage = ""
✓ Správně
received_message = "" sent_message = ""
-
✗ Špatně
var message = "" var messageTwo = ""
Tu nie je jasné, čo je uložené:
var received = "" // text, bytes, message, order, ...? var sent = ""
A tu je názov nečitateľný:
var receivedmessage = "" var sentmessage = ""
✓ Správně
var receivedMessage = "" var sentMessage = ""
-
✗ Špatně
$message = ""; $messageTwo = "";
Tu nie je jasné, čo je uložené:
$received = ""; // text, bytes, message, order, ...? $sent = "";
A tu je názov nečitateľný:
$receivedmessage = ""; $sentmessage = "";
✓ Správně
$receivedMessage = ""; $sentMessage = "";
-
✗ Špatně
let message = ""; let messageTwo = "";
Tu nie je jasné, čo je uložené:
let received = ""; // text, bytes, message, order, ...? let sent = "";
A tu je názov nečitateľný:
let receivedmessage = ""; let sentmessage = "";
✓ Správně
let receivedMessage = ""; let sentMessage = "";
Nepoužívame skratky
Túto podkapitolu začnime citáciou:
Všetci si lámali hlavu, k čomu je ten stĺpec
DATBIR
. Až sa raz zistilo, že je to vraj dátum narodenia (date
of birth).
Táto zlá praktika je vlastne opakom viacslovných názvov premenných.
Nevymýšľame nezmyselné skratky, napríklad z názvu rm
nikto
nespozná, že myslíme receivedMessage
. Pomôcka môže byť:
Pokiaľ sa na kód pozrie niekto iný ako my, mal by presne vedieť, čo v ktorej premennej je.
-
✗ Špatně
String mess; int mc;
✓ Správně
String message; int messageCount;
-
✗ Špatně
string mess; int mc;
✓ Správně
string message; int messageCount;
-
✗ Špatně
string mess; int mc;
✓ Správně
string message; int messageCount;
-
✗ Špatně
mess = "" mc = 0
✓ Správně
message = "" message_count = 0
-
✗ Špatně
var mess = "" var mc = 0
✓ Správně
var message = "" var messageCount = 0
-
✗ Špatně
$mess = ""; $mc = 0;
✓ Správně
$message = ""; $messageCount = 0;
-
✗ Špatně
let mess = ""; let mc = 0;
✓ Správně
let message = ""; let messageCount = 0;
V budúcej lekcii, Najčastejšie chyby programátorov - Vieš pomenovať objekty?, si ukážeme najčastejšie chyby začiatočníkov, napríklad ohľadom pomenovania tried, metód a atribútov.