Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

1. diel - Najčastejšie chyby programátorov - Vieš pomenovať premenné?

Vitajte pri prvom tutoriále kurzu Best practices pre návrh softvéru, v ktorom sa budeme zaoberať najčastejšími chybami programátorov a dobrými praktikami pri vývoji softvéru. Vybrané lekcie sú obsiahnuté v tunajších kurzoch programovania, a tak je možné, že ste sa s niektorými už stretli. Keďže sa jedná o zásadné chyby, s ktorými sa v praxi stretávame veľmi často, rozhodli sme sa na túto tému vytvoriť samostatný kurz.

Slovo senior programátora

David Čápka - Best practices pre návrh softvéru

Materiál pre dnešnú lekciu 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 dnes budeme baviť. Záleží nám na tom, aby ste boli naozaj dobrí, preto týchto lekcií nájdete naprieč našimi kurzami ešte niekoľko.

Ako správne pomenovávať premenné?

Hovorí sa, že 10% času niečo programujeme a 90% času pre to vymýšľame názov;-) Ide samozrejme o nadsádzku, ale vtip naráža na nutnosť stráviť určitý čas nad vymýšľaním názvov premenných. To aby každý 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 vypis, text2;
    int[5] pole;
    int foo, bar, x, vypocet;

    \---

    ✓ Správně

    String nazev, jmeno;
    int[5] odpovedi;
    int i, j, bonus, celkovyBonus;

    \--- \---

  • ✗ Špatně

    string vypis, text2;
    int[] pole = new int[5];
    int foo, bar, x, vypocet;

    \---

    ✓ Správně

    string nazev, jmeno;
    int[] odpovedi = new int[5];
    int i, j, bonus, celkovyBonus;

    \--- \---

  • ✗ Špatně

    std::string vypis, text2;
    int pole[5];
    int foo, bar, x, vypocet;

    \---

    ✓ Správně

    std::string nazev, jmeno;
    int odpovedi[5];
    int i, j, bonus, celkovyBonus;

    \--- \---

  • ✗ Špatně

    vypis = ""
    text2 = ""
    pole = [0, 0, 0, 0, 0]
    foo = 0
    bar = 0
    x = 0
    vypocet = 0

    \---

    ✓ Správně

    nazev = ""
    jmeno = ""
    odpovedi = [0, 0, 0, 0, 0]
    i = 0
    j = 0
    bonus = 0
    celkovy_bonus = 0

    \--- \---

  • ✗ Špatně

    var vypis: String = ""
    var text2: String = ""
    var pole = [0, 0, 0, 0, 0]
    var foo: Int = 0
    var bar: Int = 0
    var x: Int = 0
    var vypocet: Int = 0

    \---

    ✓ Správně

    var nazev: String = ""
    var jmeno: String = ""
    var odpovedi = [0, 0, 0, 0, 0]
    var i: Int = 0
    var j: Int = 0
    var bonus: Int = 0
    var celkovyBonus: Int = 0

    \--- \---

  • ✗ Špatně

    $vypis = "";
    $text2 = "";
    $pole = array(0, 0, 0, 0, 0);
    $foo = 0;
    $bar = 0;
    $x = 0;
    $vypocet = 0;

    \---

    ✓ Správně

    $nazev = "";
    $jmeno = "";
    $odpovedi = array(0, 0, 0, 0, 0);
    $i = 0;
    $j = 0;
    $bonus = 0;
    $celkovyBonus = 0;

    \--- \---

  • ✗ Špatně

    let vypis = "";
    let text2 = "";
    let pole = [0, 0, 0, 0, 0];
    let foo = 0;
    let bar = 0;
    let x = 0;
    let vypocet = 0;

    \---

    ✓ Správně

    let nazev = "";
    let jmeno = "";
    let odpovedi = [0, 0, 0, 0, 0];
    let i = 0;
    let j = 0;
    let bonus = 0;
    let celkovyBonus = 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ť premennú pole má asi rovnakú vypovedaciu hodnotu, ako by sme ju pomenovali promenna.

Častá chyba je, že chceme napr. uložiť výsledok nejakého výpočtu a premennú pomenujeme vypocet. 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 celkovyBonus / celkovy_bonus. Podobne je v prvom kóde pomenovaná premenná vypis, 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 kód vľavo je program na kvízy?

Tiež nikdy nepomenovávame premenné pomocna alebo pom apod.

Pozor na "Czechglish" a diakritiku

V zdrojovom kóde je na našej úrovni začiatočníkov jedno, akým jazykom budeme pomenovávať premenné (pokiaľ teda nepošleme Angličanovi kód v slovenčine).

Premenné v jednom projekte pomenovávame jedným jazykom a pokiaľ česky, tak bez diakritiky!

Opäť si ukážme príklady:

  • ✗ Špatně

    String zpráva = "Čau!";
    int count;

    \---

    ✓ Správně

    String zprava = "Čau!";
    int pocet;

    Alebo:

    String message = "Čau!";
    int count;
    \--- \---
  • ✗ Špatně

    string zpráva = "Čau!";
    int count;

    \---

    ✓ Správně

    string zprava = "Čau!";
    int pocet;

    Alebo:

    string message = "Čau!";
    int count;
    \--- \---
  • ✗ Špatně

    std::string zpráva = "Čau!";
    int count;

    \---

    ✓ Správně

    std::string zprava = "Čau!";
    int pocet;

    Alebo:

    std::string message = "Čau!";
    int count;
    \--- \---
  • ✗ Špatně

    zpráva = "Čau!"
    count = 0

    \---

    ✓ Správně

    zprava = "Čau!"
    pocet = 0

    Alebo:

    message = "Čau!"
    count = 0
    \--- \---
  • ✗ Špatně

    var zpráva = "Čau!"
    var count = 0

    \---

    ✓ Správně

    var zprava = "Čau!"
    var pocet = 0

    Alebo:

    var message = "Čau!"
    var count = 0
    \--- \---
  • ✗ Špatně

    $zpráva = "Čau!";
    $count = 0;

    \---

    ✓ Správně

    $zprava = "Čau!";
    $pocet = 0;

    Alebo:

    $message = "Čau!";
    $count = 0;
    \--- \---
  • ✗ Špatně

    let zpráva = "Čau!";
    let count = 0;

    \---

    ✓ Správně

    let zprava = "Čau!";
    let pocet = 0;

    Alebo:

    let message = "Čau!";
    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ú textSPozdravemHelloWorld, ale stačí nám tam len pozdrav, pokiaľ tam iný 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, tá je v Jave tzv. camelCase (slovensky ťavie notácie, kedy každé ďalšie slovo má veľké písmeno a názov potom vyzerá ako hrby). V iných jazykoch sa môže používať napr. podtržítko ako snake_case a ďalšie notácie.
  • Vyhneme sa pokiaľ možno číslovaniu premenných a už vôbec nepíšeme čísla slovami, nie pozdrav2 ani pozdravDve. "Dve" totiž nič nehovorí o tom, čo pozdrav obsahuje.
.<>
camelCase - Best practices pre návrh softvéru snake_case - Best practices pre návrh softvéru

Ukážme si to na príkladoch:

  • ✗ Špatně

    String zprava1;
    String zpravaDve;

    Tu nie je jasné čo je uložené:

    String prijato; // text, bajty, sprava, objednavka, ...?
    String odeslano;

    A tu je názov nečitateľný:

    String prijatazprava;
    String odeslanazprava;

    \---

    ✓ Správně

    String prijataZprava;
    String odeslanaZprava;
    \--- \---
  • ✗ Špatně

    string zprava1;
    string zpravaDve;

    Tu nie je jasné čo je uložené:

    string prijato; // text, bajty, sprava, objednavka, ...?
    string odeslano;

    A tu je názov nečitateľný:

    string prijatazprava;
    string odeslanazprava;

    \---

    ✓ Správně

    string prijataZprava;
    string odeslanaZprava;
    \--- \---
  • ✗ Špatně

    std::string zprava1;
    std::string zpravaDve;

    Tu nie je jasné čo je uložené:

    std::string prijato; // text, bajty, sprava, objednavka, ...?
    std::string odeslano;

    A tu je názov nečitateľný:

    std::string prijatazprava;
    std::string odeslanazprava;

    \---

    ✓ Správně

    std::string prijataZprava;
    std::string odeslanaZprava;
    \--- \---
  • ✗ Špatně

    zprava1 = ""
    zpravaDve = ""

    Tu nie je jasné čo je uložené:

    prijato = "" # text, bajty, sprava, objednavka, ...?
    odeslano = ""

    A tu je názov nečitateľný:

    prijatazprava = ""
    odeslanazprava = ""

    \---

    ✓ Správně

    prijataZprava = ""
    odeslanaZprava = ""
    \--- \---
  • ✗ Špatně

    var zprava1: String = ""
    var zpravaDve: String = ""

    Tu nie je jasné čo je uložené:

    var prijato: String = "" // text, bajty, sprava, objednavka, ...?
    var odeslano: String = ""

    A tu je názov nečitateľný:

    var prijatazprava: String = ""
    var odeslanazprava: String = ""

    \---

    ✓ Správně

    var prijataZprava: String = ""
    var odeslanaZprava: String = ""
    \--- \---
  • ✗ Špatně

    $zprava1 = "";
    $zpravaDve = "";

    Tu nie je jasné čo je uložené:

    $prijato = ""; // text, bajty, sprava, objednavka, ...?
    $odeslano = "";

    A tu je názov nečitateľný:

    $prijatazprava = "";
    $odeslanazprava = "";

    \---

    ✓ Správně

    $prijataZprava = "";
    $odeslanaZprava = "";
    \--- \---
  • ✗ Špatně

    let zprava1 = "";
    let zpravaDve = "";

    Tu nie je jasné čo je uložené:

    let prijato = ""; // text, bajty, sprava, objednavka, ...?
    let odeslano = "";

    A tu je názov nečitateľný:

    let prijatazprava = "";
    let odeslanazprava = "";

    \---

    ✓ Správně

    let prijataZprava = "";
    let odeslanaZprava = "";
    \--- \---
Nepoužívame skratky

Túto podkapitolu začnime citáciou:

Všetci si lámali hlavu, k čomu je ten stĺpec DATNAR. Až sa raz zistilo, že je to praj dátum narodenia.
Táto zlá praktika je vlastne opakom viacslovných názvov premenných. Nevymýšľame nezmyselné skratky, napríklad z názvu pz nikto nespozná, že myslíme prijataZprava. 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 zp;
    int pz;

    ✓ Správně

    String zprava;
    int pocetZprav;

    \--- \---

  • ✗ Špatně

    string zp;
    int pz;

    ✓ Správně

    string zprava;
    int pocetZprav;

    \--- \---

  • ✗ Špatně

    std::string zp;
    int pz;

    ✓ Správně

    std::string zprava;
    int pocetZprav;

    \--- \---

  • ✗ Špatně

    zp = ""
    pz = 0

    ✓ Správně

    zprava = ""
    pocetZprav = 0

    \--- \---

  • ✗ Špatně

    var zp: String = ""
    var pz: Int = 0

    ✓ Správně

    var zprava: String = ""
    var pocetZprav: Int = 0

    \--- \---

  • ✗ Špatně

    $zp = "";
    $pz = 0;

    ✓ Správně

    $zprava = "";
    $pocetZprav = 0;

    \--- \---

  • ✗ Špatně

    let zp = "";
    let pz = 0;

    ✓ Správně

    let zprava = "";
    let pocetZprav = 0;

    \--- \---

V budúcej lekcii, Najčastejšie chyby programátorov - Podmienky a cykly , si ukážeme najčastejšie chyby začiatočníkov, napríklad ohľadom pomenovania kolekcií, boolean výrazov a DRY.


 

Všetky články v sekcii
Best practices pre návrh softvéru
Preskočiť článok
(neodporúčame)
Najčastejšie chyby programátorov - Podmienky a cykly
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
1 hlasov
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity