Prečo Go nemá Try-Catch?
Go zámerne nepodporuje try-catch a podporuje iba syntax panic-recover. To vyvoláva nevôľu mnohých vývojárov, ktorí sú zvyknutí na spracovanie chýb pomocou try-catch. Prečo teda nepoužíva try-catch? Je to preto, že try-catch má niekoľko problémov.
try-catch-finally
Príkaz try-catch slúži na spracovanie chybových situácií a výnimočných situácií, ktoré môžu nastať počas behu programu (runtime). Okrem toho, príkaz finally zapisuje kód, ktorý sa musí bezpodmienečne vykonať bez ohľadu na to, či došlo k výnimke.
Spracovanie chýb a zodpovednosť
V 80. a 90. rokoch bolo spracovanie chýb veľmi jednoduché. Chybové hlásenia boli iba 'Disketa je plná', 'V jednotke nie je disketa', 'Disketa nemá povolenie na zápis' a vývojári v tej dobe, keď nastala chyba, ju hodili (throw) až na miesto spracovania chýb a spracovali ju spoločne. V tejto situácii fungoval príkaz try-catch efektívne.
Časom sa však situácia zmenila. Obchodná logika sa skomplikovala, vznikli databázy a transakcie, a prostredníctvom siete bolo potrebné interpretovať nespočetné množstvo požiadaviek z mnohých API, a dokonca s príchodom súbežného programovania bolo potrebné spracovať chyby v iných vláknach ako v hlavnom.
Chyby sa stali príliš komplexnými na to, aby sa dali spracovať na jednom mieste, a žiadne miesto nemohlo prevziať zodpovednosť za všetky chyby. Tu vzniká vážny problém s try-catch.
Prehadzovanie zodpovednosti try-catch
Try-catch, jednoducho povedané, je spôsob, ako subjekt, ktorý spôsobil chybu, prenesie zodpovednosť (za následky) za chybu na niekoho iného. Týmto subjektom môže byť príkaz catch, jeho nadradená metóda, alebo nadradená metóda jeho nadradenej metódy... Alebo ktokoľvek iný. Inými slovami, v svete, kde pribúda a komplikuje sa spracovanie chýb, je prístup try-catch 'niekto to urobí za mňa'. 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émom vyššie uvedeného kódu je, že nie je jasné, kto je subjektom, ktorý spracúva printStackTrace, ani nie je jasné, v ktorom kóde sa vyskytla chyba. Dokonca, čím viac logiky pribudne do príkazu try, tým horšie sa problém stáva. Paradoxne, čím viac sa vývoj stáva komplikovanejším, tým viac sú vývojári závislí na príkaze try-catch, ktorý prenáša zodpovednosť, nezaoberajú sa spracovaním chýb, ich zmysel pre zodpovednosť sa stáva menším a nakoniec zabudnú 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 má niekoľko systémov, ktoré zabraňujú vývojárom ísť zlou cestou a vytvárajú z nich dobrých vývojárov. Panic-recover je tiež príkladom toho. Panic a recover sa na prvý pohľad nezdajú odlišné od try-catch, ale líšia sa v tom, že pri vzniku problému neprenášajú zodpovednosť navonok. Keď v go nastane panic, hodnota sa nevracia navonok, ale musí sa vyriešiť na mieste, kde nastal panic. To dáva vývojárovi zodpovednosť za spracovanie chýb a vedie ho k tomu, aby sa hlbšie zamyslel nad tým, kde, kto a ako by sa mala daná chyba spracovať. Je to akoby sa užívateľom zaručila autonómia, ale zároveň im zostal priestor na premýšľanie.
Okrem toho, výber slova panic je tiež veľmi výnimočný. Na rozdiel od try-recover, panic-recover už samotným slovom vyvíja na vývojára tlak, aby sa používal len v zjavných chybových situáciách, a nie v výnimočných situáciách. Vývojári tak prirodzene nepoužívajú recover nadmerne a používajú ho len tam, kde je to potrebné. To veľmi pomáha pri písaní stručného kódu v go.