Lekce 1 - Debugging: Úvod a terminologie
Dříve nebo později se každý, kdo se zabývá programováním, setká s termínem debugging. Ale co to vlastně je? Původ pojmu debugging, doslova z angličtiny "odhmyzení", se dnes připisuje Grace Hopperové. V roce 1940, kdy pracovala s počítačem Mark II, totiž její spolupracovníci objevili uvízlou můru ve stroji, který díky tomu nefungoval správně. Proces "opravy" pojmenovali jako debugging, čili odstraňování hmyzu. Dnes tento termín označuje proces odstraňování chyb v našich programech, konkrétně tento kurz bude jednat o debuggování v JavaScriptu.
Pro koho je debuggování?
Debuggování patří k základním znalostem každého dobrého
programátora. Stejně jako se nikdo neobejde bez cyklu for
,
while
či if
, tak by každý měl znát alespoň
základy debuggování. Cílem každého programátora je psát především
správné programy. Programátor her sice může napsat kód tak, že mu hra
běží při 240 FPS, může-li ale hráč prostřelit zeď přes celou mapu,
nikoho hra nebude nijak zvláštně zajímat.
Mobilní aplikace může vypadat také úplně super. Pokud ale spadne při zobrazení nějakých speciálních znaků, což se už několikrát stalo např. s aplikací iMessage, to bude určitě sekundární záležitost. Zkrátka nezáleží na tom, v jakém prostředí vyvíjíme. Jsme vývojáři a musíme umět debuggovat svůj kód.
O co jde?
My, jakožto lidé, nejsme perfektní. Nikdo nepíše perfektní kód, proto se v něm často najdou chyby. Je tím pádem důležité vědět, jak tyto chyby řešit. To je vlastně podstata tohoto kurzu. Obecně rozlišujeme mezi dvěma typy chyb:
- syntaktické a
- logické.
Syntaktické chyby
Formát programového jazyka se nazývá syntax, tj. pravidla, kterými JavaScript (mluvíme o abstraktním konceptu jazyka) rozhoduje, co náš kód znamená. Třeba:
console.log("ahoj");
Text console
znamená "Objekt s názvem console
",
.log
znamená "Člen objektu console
s názvem
log
" (v tomto případu funkce), ("ahoj")
znamená
"Zavolej funkci log objektu console s parametry "ahoj"
". Středník
;
na konci označuje konec řádku.
Výsledkem porušení těchto pravidel znamená, že náš program je
nefunkční a vyhodí se SyntaxError
výjimka. Příklady
syntaktických chyb jsou například:
- nevybalancované závorky,
- chybějící středník,
- překlep v názvu funkce či proměnné atd.
JavaScript tím, že je dynamicky typovaný, nám dovoluje psát kód, který na první pohled dává syntaktický smysl, ale dojde k erroru až po nějaké době běžení programu a to často jen za nějakých podmínek.
Nedávno jsem napsal mé první Discord boty v JavaScriptu (Node.js + discord.js). Jeden z nich umožňoval
skupince lidí provádět anonymní hlasování. Bot měl takovou funkci, která
dovolovala uživateli zadat do chatu $$majority
(anglicky
většina) a jestli tedy většina byla dosažena, pak by byly
zobrazeny výsledky. Byl v tom ale jeden háček, a to sice v tomto úryvku:
//... } else { msg.channel.send("There is no majority!".catch(err => console.log(err))); } //...
Všimli jste si ho? Po druhých uvozovkách chybí závorka, která se mi
záhadným způsobem dostala na konec řádku. Tento kód je syntakticky
správný. Dojde-li ale k provedení tohoto kódu, vznikne tzv.
Uncaught TypeError
, jelikož objekt typu string
nemá
metodu catch()
. Místo toho, aby můj bot odeslal text
There is no majority!
a kdyby něco, tak error vypsal do konzole,
tak v té situaci program ihned spadl.
Naštěstí jsem chybu našel poměrně jednoduše a rychle. Tento typ erroru je způsoben tím, že proměnná může mít teoreticky jakýkoliv typ, to je v JavaScriptu asi nejběžnější. Existuje třeba TypeScript (vřele ho doporučuji), který má statické typování, ve kterém by se takové chyby triviálně našly. Jsou ale i jiné a zákeřnější chyby, protože nevypisují žádné errory, jen tiše selžou...
Logické chyby
Logické chyby jsou speciální tím, že na první pohled vůbec nejsou jasné a někdy si ani nejsme vědomi toho, že takové chyby v našich programech máme. Často se stane, že naše algoritmy fungují pro poměrně jednoduché vstupy, ale chyby v přemýšlení se ukážou až v komplexnějších situacích. Najít logické chyby je často těžké a mnohokrát se skrývají tam, kde bychom to nejméně čekali. Nicméně si co nejlépe vysvětlíme, jak tyto chyby řešit, ale také jak se jim vyhýbat. Lehčí kategorie logických chyb jsou přepisy, například:
function min(a, b) { return a > b ? a : b; }
V tomto případě autor zcela určitě mínil tohle:
function min(a, b) { return a < b ? a : b; }
Rozdíl, čistě textově, je jedno znaménko, ale logicky kód vydává opačné výsledky. Nebo, absolutní klasika:
for(let i = 0; i <= a.length; i++) { console.log(a[i]); }
Autor omylem napsal <=
místo <
. Konkrétně
v JavaScriptu bude např.: a[7]
(tedy element hned za koncem)
hodnoty undefined
. V jiných jazycích, jako např. C++, by toto mohlo mít katastrofální následky pro náš
program. Ale o hodně horší je řešit případ, kdy náš program prostě
není logicky správný. Potom totiž opravit chybu není vůbec triviální,
ale musíme najít nové řešení pro daný problém.
Debugging – Postupy & Pojem "bug"
Pojmem bug označujeme logické chyby. Stejně jako hmyz, tyto chyby jsou často poměrně malé, mohou ale mít rozsáhlý dopad na náš program. Chceme-li být dobří debuggeři, musíme mít správný postup. Tato lekce má být jenom úvod do tohoto tématu. V dalších lekci si projdeme, jak vlastně JavaScript funguje a jak s ním komunikovat přes konzoli. Poté si projdeme:
- JavaScript enginy
- Programy, které překládají a vykonávají náš kód. Naučíme se o základních funkcích, jaké enginy existují a v čem se liší.
- Konzoli
- Konzole je základní interface, přes který komunikujeme s enginem a prohlížečem.
- Obecné postupy debuggování
- Taktiky, jak identifikovat chybu, najít ji v kódu a jak ji opravit.
- Používání Chromu a Firefoxu
- V této lekci si projdeme, jak používat moderní prohlížeče a jejich funkce pro vývojáře.
- Testování
- Testování je jedna z věcí, které se často přehlídnou. Je ale hodně důležité! Testováním se snažíme chyby najít preventivně a ihned je opravit. Testování je lepší, než když se chyba projeví v aplikaci, která už někde běží a my pak musíme napravit náhlý problém.
Dale je třeba potřeba mít na mysli, že dobré porozumění jazyka je
dobré mít, ale není to nutností. Právě v JavaScriptu máme zajímavosti
jako undefined == null
vs. undefined === null
. Nechci
tím říct, že musíme nějak zrovna vynikat v JavaScriptu, abychom ho
zvládli debuggovat, ale abychom nepodcenili i poměrně důležitou roli,
kterou hraje zkušenost s jazykem.
Co budeme potřebovat
Abychom aplikovali praktiky z těchto tutoriálů, budeme potřebovat:
- naše normální programovací prostředí (IDE)
- moderní webový prohlížeč (Firefox, Opera nebo Chrome)
K otestování kódu můžeme použít i různé frameworky. Až se budeme bavit o testování, pár z nich si ukážeme. Abychom je ale používali, je samozřejmostí je nainstalovat.
V další lekci, Nástroje pro debugging a internetové prohlížeče, si popíšeme funkci JavaScriptu a řekneme si, jak využít nástroje v prohlížečích pro debugging.