GoSuda

Hvorfor Go valgte eksplicit fejlreturnering og panic-recover frem for try-catch-undtagelseskastning

By Rabbit Princess views ...

Go understøtter med vilje ikke try-catch, og tilbyder kun sprogkonstruktionerne panic og recover. Dette har fået de talrige udviklere, der er vant til fejlhåndtering med try-catch, til at klage. Hvorfor er try-catch så ikke blevet inkluderet? Det skyldes, at try-catch har flere problemer.

try-catch-finally

Try-catch-konstruktionen (try-catch) er en sprogkonstruktion til håndtering af fejlsituationer og undtagelsessituationer, der kan opstå under programkørsel (runtime). Derudover angiver finally-konstruktionen den kode, der skal udføres ubetinget, uanset om der er opstået en undtagelse eller ej.

Fejlhåndtering og ansvar

I 1980'erne og 1990'erne var fejlhåndtering meget enkel. Fejlmeddelelserne var begrænset til "Disketten er fuld", "Ingen diskette i drevet" og "Ingen skriverettigheder til disketten", og udvikleren på den tid kastede, når der opstod en fejl, fejlen (throw) til det sted, hvor fejlen skulle håndteres, og håndterede den dér på en fælles måde. I denne situation fungerede try-catch-konstruktionen effektivt.

Med tiden ændrede situationen sig dog. Forretningslogikken blev kompleks, der opstod databaser og transaktioner, og mange API-kald over netværket krævede, at der blev fortolket talrige anmodningsmeddelelser. Med fremkomsten af samtidighedsprogrammering blev det endda nødvendigt at håndtere fejl i andre tråde end hovedtråden.

Fejl blev til sidst for komplekse til at kunne håndteres ét sted, og det blev umuligt for ét enkelt sted at tage ansvaret for alle fejl. Her opstår et alvorligt problem med try-catch.

Try-catch og ansvarsoverførsel

Kort sagt er try-catch en metode, hvor den del af koden, der udløser fejlen, overlader ansvaret (efterbehandlingen) for fejlen til en anden. Den part, der overlades ansvaret, kan være catch-konstruktionen, den overordnede metode, den overordnedes overordnede metode, og så videre op ad kæden. Med andre ord, i en verden hvor fejlhåndtering bliver flere og mere kompleks, er den løsning, try-catch har valgt, netop tankegangen "nogen vil nok klare det". Se på 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 koden ovenfor er, at det ikke er klart, hvem der har ansvar for at håndtere printStackTrace, og at det heller ikke er muligt at vide, i hvilken kode fejlen opstod. Når der er mere logik i try-sætningen, bliver problemet endnu værre. Paradoksalt nok, jo mere udviklingen blev kompleks, desto mere blev udviklerne afhængige af try-catch-konstruktionen, der overfører ansvaret. De holdt op med at tænke over fejlhåndtering, ansvarsfølelsen svækkedes, og til sidst mistede de forståelsen for fejl- og undtagelseshåndteringens egentlige væsen. Hvordan løste golang så dette problem?

panic, recover

En af Go's styrker er, at sproget har flere mekanismer, der hjælper med at gøre udviklere til gode udviklere i stedet for at lade dem falde ind i dårlige vaner. panic og recover er et eksempel på dette.

Panic og recover ligner ved første øjekast ikke meget forskelligt fra try-catch, men de adskiller sig ved, at ansvaret ikke skubbes udad, når et problem opstår. I Go skal en panic, når den opstår, håndteres der, hvor den opstod, i stedet for at værdien sendes udad. Dette giver udvikleren ansvaret for fejlhåndteringen og tilskynder til at overveje grundigere, hvor, af hvem og hvordan fejlen skal håndteres. Det svarer til at give brugeren selvbestemmelse, samtidig med at der gives plads til eftertanke.

Ordet panic er også valgt meget godt. I modsætning til try-recover lægger panic-recover allerede ved selve ordvalget et pres på udvikleren om kun at bruge det i åbenlyse fejlsituationer og ikke i almindelige undtagelsessituationer. Naturligt nok undgår udvikleren at misbruge recover og bruger det kun dér, hvor det er nødvendigt. Dette hjælper i høj grad med at skrive kortfattet kode i Go.