GoSuda

Miért nincs Try-Catch a Go-ban?

By Rabbit Princess
views ...

A Go szándékosan nem támogatja a try-catch szerkezetet, kizárólag a panic-recover mechanizmust. Ez sok fejlesztő nemtetszését váltja ki, akik hozzászoktak a try-catch alapú hibakezeléshez. Miért nem építették be akkor a try-catch-et? Azért, mert a try-catch számos problémát rejt magában.

try-catch-finally

A try-catch szerkezet a program futása során (runtime) felmerülő hibák és kivételek kezelésére szolgáló nyelvi elem. A finally blokk pedig olyan kódot tartalmaz, amely kivétel felmerülésétől függetlenül minden esetben végrehajtódik.

Hibakezelés és felelősség

Az 1980-as és 1990-es években a hibakezelés rendkívül egyszerű volt. A hibaüzenetek kizárólag a következőket jelentették: 'Floppy lemez megtelt', 'Nincs floppy lemez a meghajtóban', 'Nincs írási jogosultság a floppy lemezre'. Ebben az időszakban a fejlesztők a hibákat a hibakezelési pontig továbbították (throw), és ott egységesen kezelték. Ilyen körülmények között a try-catch szerkezet hatékonyan működött.

Az idő múlásával azonban a helyzet megváltozott. Az üzleti logika komplexebbé vált, megjelentek az adatbázisok és a tranzakciók, számtalan API hívást kellett értelmezni a hálózaton keresztül, és a konkurens programozás megjelenésével a hibákat már nem a fő szálon, hanem más szálakon kellett kezelni.

A hibák olyannyira komplexszé váltak, hogy már nem kezelhetők egyetlen helyen, és senki sem vállalhatja a teljes felelősséget minden hibáért. Itt merül fel egy súlyos probléma a try-catch mechanizmussal kapcsolatban.

A try-catch felelősségáthárítása

A try-catch, egy szóval, egy olyan módszer, amellyel a hibát okozó entitás a hibakezelés (utófeldolgozás) felelősségét valaki másra hárítja. Ez a valaki lehet a catch blokk, a szülő metódus, vagy akár a szülő szülőjének szülőjének szülője. Más szóval, egy olyan világban, ahol a hibakezelés egyre gyakoribbá és komplexebbé válik, a try-catch által választott megközelítés az, hogy "valaki majd megteszi". Nézzük meg az alábbi kódot.

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}

A fenti kód problémája az, hogy nem világos, ki kezeli a printStackTrace-et, és azt sem lehet tudni, melyik kódrészletben történt a hiba. Minél több logika kerül a try utasításba, annál borzasztóbbá válik a probléma. Azonban paradox módon, minél komplexebbé vált a fejlesztés, annál inkább függővé váltak a fejlesztők a felelősséget áthárító try-catch szerkezettől, nem gondolkodtak a hibakezelésen, a felelősségérzetük is elhalványult, és végül elfelejtették a hibák és kivételek kezelésének lényegét. Hogyan oldotta meg ezt a problémát a Golang?

panic, recover

A Go egyik előnye, hogy számos olyan rendszerrel rendelkezik, amely a fejlesztőket jó irányba tereli, ahelyett, hogy rossz útra vinné őket. A panic-recover mechanizmus is ennek példája. ​ A panic és a recover első pillantásra nem tűnik sokban különbözőnek a try-catch-től, azonban abban különbözik, hogy probléma esetén nem hárítja át a felelősséget. Amikor Go-ban panic történik, ahelyett, hogy az értéket továbbítaná, a panic helyén kell megoldani a problémát. Ez a megközelítés felelősséget ró a fejlesztőre a hibakezeléssel kapcsolatban, arra ösztönözve őket, hogy alaposabban gondolják át, hol, ki és hogyan kezelje az adott hibát. Ezáltal autonómiát biztosít a felhasználóknak, ugyanakkor teret enged a gondolkodásnak.

Emellett a "panic" szó kiválasztása is rendkívül találó, mivel a try-recover-rel ellentétben a panic-recover már önmagában is nyomást gyakorol a fejlesztőre, hogy csak nyilvánvaló hibahelyzetekben használja, és ne kivételes esetekben. Természetesen a fejlesztő nem él vissza a recover használatával, és csak ott alkalmazza, ahol szükséges. Ez nagyban hozzájárul a Go tömör kódjának megírásához.