GoSuda

Waarom Go kiest voor expliciete foutretournering en panic-recover in plaats van try-catch-uitzonderingen

By Rabbit Princess views ...

Go ondersteunt bewust geen try-catch, maar alleen de panic-recover-syntaxis. Dit heeft geleid tot veel frustratie onder de talrijke ontwikkelaars die gewend zijn aan foutafhandeling met try-catch. Waarom wordt try-catch dan niet opgenomen? Dat komt doordat try-catch verschillende problemen kent.

try-catch-finally

Het try-catch (trycatch) statement is een constructie om fout- en uitzonderingssituaties af te handelen die tijdens de uitvoering van een programma (runtime) kunnen optreden. Het finally-statement bevat code die ongeacht of er een uitzondering is opgetreden altijd moet worden uitgevoerd.

Foutafhandeling en verantwoordelijkheid

In de jaren tachtig en negentig was foutafhandeling zeer eenvoudig. De foutmeldingen waren beperkt tot 'floppy disk vol', 'geen floppy disk in station' en 'geen schrijfrechten voor floppy disk', en ontwikkelaars die een fout tegenkwamen, gooiden die fout door (throw) naar het punt waar fouten werden afgehandeld, zodat dit centraal kon gebeuren. In zo'n situatie werkte het try-catch-statement efficiënt.

Na verloop van tijd veranderde de situatie echter. Bedrijfslogica werd complex, er kwamen databases en transacties, er moesten via het netwerk talloze API's worden aangeroepen en talloze requestberichten worden geïnterpreteerd, en door de opkomst van concurrent programmeren moesten fouten zelfs in threads buiten de hoofdthread worden afgehandeld.

Fouten werden zo complex dat ze niet langer op één plek konden worden afgehandeld, en één enkele plek kon niet langer verantwoordelijk zijn voor alle fouten. Hier ontstond een ernstig probleem met try-catch.

Het afschuiven van verantwoordelijkheid bij try-catch

Kort gezegd is try-catch een methode waarbij de partij die de fout veroorzaakt, de verantwoordelijkheid voor het gevolg (het opruimen) doorschuift naar iemand anders. Die andere partij kan het catch-statement zijn, de bovenliggende methode, of de bovenliggende van de bovenliggende van de bovenliggende van de bovenliggende... iemand anders. Met andere woorden: in een wereld waarin foutafhandeling steeds meer en complexer wordt, was de keuze van try-catch simpelweg 'iemand zal het wel oplossen'. Bekijk de onderstaande code.

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}

Het probleem met deze code is dat het niet duidelijk is wie verantwoordelijk is voor de verwerking van printStackTrace, en dat niet kan worden achterhaald in welke code de fout is opgetreden. Naarmate er in het try-statement meer logica komt, wordt het probleem nog ernstiger. Paradoxaal genoeg raakten ontwikkelaars, naarmate de ontwikkeling complexer werd, verslaafd aan try-catch-constructies die verantwoordelijkheid afschoven. Ze dachten niet meer na over foutafhandeling, hun verantwoordelijkheidsbesef verflauwde, en uiteindelijk vergaten zij het wezen van fout- en uitzonderingsafhandeling. Hoe heeft Golang dit probleem dan opgelost?

Panic en recover

Een van de voordelen van Go is dat het over verschillende systemen beschikt die ontwikkelaars niet op een verkeerd pad brengen, maar juist tot goede ontwikkelaars maken. Panic-recover is hier een voorbeeld van.

Panic en recover lijken op het eerste gezicht niet te verschillen van try-catch, maar ze verschillen doordat de verantwoordelijkheid niet naar buiten wordt doorgeschoven wanneer er een probleem optreedt. In Go moet een panic op de plek waar deze optreedt worden opgelost, in plaats van de waarde naar buiten door te geven. Dit legt de verantwoordelijkheid voor foutafhandeling bij de ontwikkelaar, die zo dieper moet nadenken over waar, door wie en hoe de fout moet worden afgehandeld. Het geeft de gebruiker autonomie en laat tegelijkertijd ruimte voor overweging.

Ook de keuze van de term panic is zeer doeltreffend. In tegenstelling tot try-recover dwingt panic-recover de ontwikkelaar, al door het woord alleen, om het alleen te gebruiken in duidelijke foutsituaties en niet in uitzonderingssituaties. Vanzelf gebruikt de ontwikkelaar recover dan niet overmatig, maar alleen waar het nodig is. Dit draagt sterk bij aan het schrijven van beknopte code in Go.