Ono to ošetřování chyb v GO má svoji logiku (i když, přiznávám, jako Javista jsem tomu nepřišel na chuť
.
Funkce typicky vrací dvojici hodnot - výsledek a chybu (result, err). Takto jsou napsané interní funkce a většinou se tak píšou i všechny ostatní. Obojí člověk
musí do nějaké proměnné přiřadit (result, err := func() ). A když už něco do proměnné přiřadí,
musí ji v kódu použít (jinak chyba, hlídá to kompilátor). Existuje ale placeholder "_" kdy můžu explicitně říct, že chybu ignoruju (result, _ := func() ). Takto explicitně kompilátoru řeknu, že chybový výstup funkce mě nezajímá a nechci ho ošetřit vůbec. Další možnost je chybu ošetřít v kódu v místě vzniku nebo "poslat dál" v návratovém kódu funkce. Vždyť je to v jádru podobný mechanismus jako checked exceptions v javě (akorát s primitivnější konstrukcí).
Filozofie GO je, že chyba je jedna z možností, jak volání funkce může dopadnout. Je to
plnohodnotná (a očekávaná!) alternativa k tomu, že funkce vrátí výsledek. Nikoliv něco jako corner case. Něco co "SE nějak" pořeší (frameworkem atp.). Rovnocenná varianta, která si zaslouží stejnou pozornost jako to, že funkce vrátila nějaký výsledek.
Ono v GO se typicky píšou ty mikroslužby, nástroje na automatizaci, síťoví klienti... Různé chyby spojení atd. tu nejsou výjimka ale regulérní věc, která prostě nastává. (tečka.)
A teď proč jsem si jako Javista nezvykl. Samozřejmě runtime exception. Ty jsou hodně oblíbené. Ty totiž nepřikazují, že se musí chyba řešit (buď ošetřit, poslat dál nebo prostě ignorovat (sic)) v místě vzniku.Tahle vlastnost checked exceptions je pro spoustu lidí tak silné omezení že je odchytávají a obalují do runtime a "posílají dál". Na nejpoužívanějších frameworcích v javě je to vidět. Checked exceptions jsou tak nějak demodé, nechtěný člen jazyka, na který se hledá jak to obejít.
No jo, je to návykové. Mít možnost chybu nechat bublat stackem, "chytit" ji o mnoho kroků dál a neřešit při každém volání něčeho "co když.."
Ano, pohodlně se s tím žije. Ale někdy je těžké (narozdíl od toho explicitního ošetřování) říct, co se stane, když... třeba server, který volám neopdoví. Data nejde načíst. Vstup je špatný... Ono "SE" to vyřeší. Někdo tu výjimku ošetří, co na tom, že klient dostane divný návratový kód (nejlépe i se stack trace
, v databázi (a jiných distribuovaných úložištích) zůstane nekonzistentní binec.. I tohle jsme mockrát viděli. Takže jako všechno se to musí používat s rozmyslem. Což se často neděje a proto vzniká výše uvedené. Bohužel jazyk a konstrukce neošetřených výjimek k tomu vybízí. Nejsem žádný evangelista check exceptions nebo stylu ale GO/C, jen jsem chtěl zkusit přiblížit co je pod tím za záměr.
Ono vynucovaná "štábní kultura" v GO je něco, co hodně lidí pobuřuje/omezuje. Prosté přiřazení proměnné bez dalšího použití v kódu je chyba. Chyba kompilaci (ne varování IDE). Ano, chybový výstup funkce můžu "dát do podtžítka" (ignorovat) ale okamžitě je vidět jaké jsem prase (a kde může být zdroj chyby). Dobře, buďme objektivnější - okamžitě je vidět, kde jsem se explicitně a po zralé úvaze
rozhodl, že chybu ošetřím zrovna takhle.
Ještě jedna věc k tomu, že v GO je za trest psát větší projekt. Kubernetes je top repozitář na githubu. Nejoblíbenější open source produkt a veliký projekt v GO současně (trocha bulvárního jazyka neuškodí). Kdyby to bylo za trest, asi by to nebylo tak oblíbené.