Prečo Go nemá Try-Catch?
Go zámerne nepodporuje try-catch a podporuje iba syntax panic-recover. To vyvoláva nevôľu u mnohých vývojárov, ktorí sú zvyknutí na spracovanie chýb pomocou try-catch. Prečo teda Go neobsahuje try-catch? Je to preto, že try-catch má niekoľko problémov.
try-catch-finally
Konštrukcia try-catch je určená na spracovanie chybových a výnimočných situácií, ktoré môžu nastať počas vykonávania programu (runtime). Klauzula finally obsahuje kód, ktorý sa musí vykonať bez ohľadu na to, či nastala výnimka.
Spracovanie chýb a zodpovednosť
V 80. a 90. rokoch bolo spracovanie chýb veľmi jednoduché. Chybové správy boli obmedzené na „disketa je plná“, „v mechanike nie je disketa“ alebo „nemáte oprávnenie na zápis na disketu“, a vývojári v tom čase pri výskyte chyby túto chybu vyvolali (throw) až do bodu spracovania chýb, kde sa spracovala centralizovane. V takýchto situáciách fungovala konštrukcia try-catch efektívne.
Časom sa však situácia zmenila. Obchodná logika sa stala komplexnejšou, objavili sa databázy a transakcie, bolo potrebné interpretovať nespočetné množstvo požiadaviek po volaní mnohých API prostredníctvom siete, a dokonca aj s príchodom súbežného programovania bolo potrebné spracovávať chyby v iných vláknach, než je hlavné.
Chyby sa stali príliš komplexnými na to, aby sa dali spracovať na jednom mieste, a žiadne jedno miesto nemohlo prevziať zodpovednosť za všetky chyby. Tu vzniká vážny problém s try-catch.
Prenášanie zodpovednosti v try-catch
try-catch je, jednoducho povedané, spôsob, ako subjekt, ktorý vyvolal chybu, prenesie zodpovednosť (následné spracovanie) za výskyt chyby na niekoho iného. Týmto subjektom môže byť klauzula catch, jej rodičovská metóda, alebo rodič rodiča rodiča rodiča... Inými slovami, vo svete, kde sa spracovanie chýb stáva čoraz rozsiahlejším a komplexnejším, metóda, ktorú si try-catch zvolil, je jednoducho „niekto iný to spraví“. Pozrime sa na nasledujúci kód.
1try {
2 data = readFile("hello.txt");
3 structuredData = parseData(data);
4 insertDBStatus(structuredData[1]);
5 startHTTPServer(structuredData[2]);
6} catch (Exception e) {
7 e.printStackTrace();
8}
Problém s vyššie uvedeným kódom spočíva v tom, že nie je jasné, kto spracováva printStackTrace, a nie je možné zistiť, v ktorej časti kódu nastala chyba. Navyše, čím viac logiky sa pridá do príkazu try, tým horší je problém. Paradoxne však, čím komplexnejší sa vývoj stával, tým viac vývojári prepadali konštrukcii try-catch, ktorá prenáša zodpovednosť, prestali premýšľať o spracovaní chýb, ich zmysel pre zodpovednosť sa oslabil a nakoniec zabudli na podstatu spracovania chýb a výnimiek. Ako teda tento problém vyriešil Golang?
panic, recover
Jednou z výhod Go je, že obsahuje rôzne systémy navrhnuté tak, aby vývojárov neviedli zlým smerom, ale pomáhali im stať sa dobrými vývojármi. Príkladom je aj panic - recover.
Panic a recover sa na prvý pohľad môžu zdať podobné try-catch, avšak líšia sa v tom, že pri vzniku problému sa zodpovednosť nepresúva navonok. V Go, keď nastane panic, by sa namiesto prenášania hodnoty navonok mala situácia vyriešiť na mieste, kde panic nastal. To vývojárom ukladá zodpovednosť za spracovanie chýb, čo ich núti hlbšie premýšľať o tom, kde, kto a ako by sa mala daná chyba spracovať. Zabezpečuje sa tým autonómia používateľa a zároveň sa ponecháva priestor na uvažovanie.
Navyše, výber slova „panic“ je mimoriadne vynikajúci, pretože na rozdiel od try-recover, panic-recover už samotným slovom vyvíja na vývojárov tlak, aby ho používali iba v jednoznačných chybových situáciách, a nie vo výnimočných situáciách. Prirodzene, vývojári nezneužívajú recover a používajú ho len tam, kde je to potrebné. To výrazne prispieva k písaniu stručného kódu v Go.