GoSuda

Hvorfor har Go ikke Try-Catch?

By Rabbit Princess
views ...

Go understøtter bevidst ikke try-catch, men kun panic-recover syntaks. Dette har ført til mange udvikleres utilfredshed, da de er vant til fejlhåndtering ved hjælp af try-catch. Så hvorfor er try-catch ikke inkluderet? Det skyldes, at try-catch har flere problemer.

try-catch-finally

Try-catch-sætningen er en konstruktion til håndtering af fejl- og undtagelsessituationer, der kan opstå under programudførelse (runtime). Derudover anvendes finally-sætningen til kode, der ubetinget skal udføres, uanset om der opstår en undtagelse.

Fejlhåndtering og ansvar

I 80'erne og 90'erne var fejlhåndtering meget simpel. Fejlmeddelelser som 'diskette fuld', 'ingen diskette i drevet' eller 'ingen skriverettigheder til diskette' var alt, og udviklere i denne periode kastede fejl til et centralt fejlhåndteringspunkt for at behandle dem samlet. I sådanne situationer fungerede try-catch-sætningen effektivt.

Men med tiden ændrede situationen sig. Forretningslogikken blev mere kompleks, databaser og transaktioner opstod, og det blev nødvendigt at fortolke utallige request-beskeder ved at kalde mange API'er over netværket. Desuden opstod behovet for at håndtere fejl i andre tråde end main på grund af fremkomsten af concurrency programming.

Fejl blev for komplekse til at håndtere ét sted, og det blev umuligt for ét enkelt sted at bære det fulde ansvar for alle fejl. Her opstår et alvorligt problem med try-catch.

Ansvarsfraskrivelse i try-catch

Try-catch er, kort sagt, en metode, hvor den enhed, der udløser en fejl, uddelegerer ansvaret (efterbehandlingen) for fejlen til en anden. Denne delegation kan være til en catch-sætning, til dens forældremetode, eller til en forfader af forælderen af forælderen... Med andre ord, i en verden hvor fejlhåndtering bliver mere omfattende og kompleks, er den metode, try-catch vælger, "nogen vil nok tage sig af det". Se koden nedenfor.

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}

Problemet med ovenstående kode er, at det ikke er klart, hvem der håndterer printStackTrace, og det er heller ikke muligt at identificere, hvor fejlen opstod i koden. Problemet bliver endnu værre, jo mere logik der tilføjes inden i try-udsagnet. Paradoksalt nok blev udviklere, jo mere kompleks udviklingen blev, afhængige af try-catch-konstruktionen, der uddelegerer ansvar. De holdt op med at tænke over fejlhåndtering, deres ansvarsfølelse aftog, og til sidst glemte de essensen af fejl- og undtagelseshåndtering. Så hvordan løste Golang dette problem?

panic, recover

En af fordelene ved Go er, at det har flere systemer designet til at vejlede udviklere mod god praksis i stedet for at føre dem på afveje. Panic-recover kan nævnes som et eksempel. ​ Ved første øjekast kan panic og recover virke ens try-catch, men de adskiller sig ved, at de ikke uddelegerer ansvaret udadtil, når et problem opstår. Når en panic opstår i Go, skal problemet løses på det sted, hvor panikken opstod, snarere end at videresende værdien udadtil. Dette tildeler udvikleren ansvaret for fejlhåndtering og tilskynder dem til at overveje mere indgående, hvor, hvem og hvordan fejlen skal håndteres. Det giver brugeren autonomi, samtidig med at der levnes plads til overvejelse.

Desuden kan valget af ordet "panic" siges at være yderst fremragende; i modsætning til try-recover, pålægger panic-recover udvikleren et pres blot ved ordvalget, at det kun bør anvendes i klare fejlsituationer og ikke undtagelsessituationer. Naturligvis misbruger udvikleren ikke recover, men bruger det kun, hvor det er nødvendigt. Dette bidrager væsentligt til at skrive kortfattet kode i Go.