GoSuda

Hvorfor har Go ikke Try-Catch?

By Rabbit Princess
views ...

Go understøtter bevidst ikke try-catch, men kun panic-recover syntaksen. Dette har vakt harme hos mange udviklere, der er vant til at håndtere fejl med try-catch. Hvorfor implementerede man så ikke try-catch? Det skyldes, at try-catch har adskillige problematiske aspekter.

try-catch-finally

Try-catch-sætningen er en konstruktion til at håndtere fejl og undtagelsestilstande, der kan opstå under kørslen (runtime) af et program. Desuden angiver finally-sætningen kode, der ubetinget skal udføres, uanset om der opstår en undtagelse eller ej.

Fejlhåndtering og ansvar

I 80'erne og 90'erne var fejlhåndtering meget simpel. Fejlmeddelelserne var blot "Floppydisk fuld", "Ingen floppydisk i drevet", "Ingen skriverettigheder til floppydisk", og udviklerne på den tid kastede blot fejlen til fejlhåndteringsstedet for at behandle den på en fælles måde, hvis der opstod en fejl. I denne situation fungerede try-catch-sætningen effektivt.

Men som tiden gik, ændrede situationen sig. Forretningslogikken blev mere kompleks, databaser og transaktioner opstod, et utal af API'er blev kaldt via netværket, og et utal af request-beskeder skulle fortolkes, og selv med fremkomsten af concurrency-programmering skulle fejl håndteres i andre tråde end main-tråden.

Fejl er blevet så komplekse, at de ikke længere kan håndteres ét sted, og ingen kan længere tage ansvar for alle fejl ét sted. Her opstår der et alvorligt problem med try-catch.

Ansvarsfraskrivelse med try-catch

Try-catch er, kort sagt, en metode, hvor den part, der udløser fejlen, udskyder ansvaret (oprydningen) for fejlforekomsten til nogen anden. Dette kan være catch-sætningen, dens overordnede metode, dens forældres forældres forældres forælder... hvem som helst. Med andre ord, i en verden, hvor fejlhåndtering bliver mere udbredt og kompleks, er try-catch's tilgang simpelthen "nogen vil nok gøre det". Se koden nedenfor.

1try {
2    data = readFile("hello.txt"); //læsFil funktion
3    structuredData = parseData(data); //parseData funktion
4    insertDBStatus(structuredData[1]); //indsæt DB Status funktion
5    startHTTPServer(structuredData[2]); //start HTTPServer funktion
6} catch (Exception e) {
7    e.printStackTrace();
8}

Problemet med ovenstående kode er, at det er uklart, hvem der er ansvarlig for at håndtere printStackTrace, og det er umuligt at vide, hvilken kode der har forårsaget fejlen. Problemet bliver endnu værre, jo mere logik der er inde i try-sætningen. Men paradoksalt nok blev udviklerne, jo mere kompleks udviklingen blev, afhængige af try-catch-sætningen, som fralægger sig ansvaret, og de tænkte ikke over fejlhåndtering, ansvarsbevidstheden blev også svagere, og i sidste ende glemte de essensen af fejl- og undtagelseshåndtering. Så hvordan løste golang dette problem?

panic, recover

En af Go's forcer er, at der er adskillige systemer, der forhindrer udviklere i at falde i dårlige vaner og gør dem til gode udviklere. Panic - recover er et eksempel på dette.

Panic og recover ser ved første øjekast ikke ud til at være forskellige fra try-catch, men de er forskellige, fordi de ikke eksternaliserer ansvaret, når de forårsager problemer. Når der opstår en panic i Go, skal værdien løses på det sted, hvor panic opstod, i stedet for at returnere den eksternt. Dette giver udviklerne ansvaret for fejlhåndtering og tilskynder dem til at tænke mere grundigt over, hvor, hvem og hvordan fejlen skal håndteres. Det garanterer brugerne autonomi, men efterlader stadig plads til eftertanke.

Valget af ordet panic er også meget fremragende, i modsætning til try-recover lægger panic-recover alene gennem ordet pres på udvikleren for kun at bruge det i klare fejlsituationer og ikke i undtagelsessituationer. Naturligvis vil udvikleren ikke misbruge recover, men kun bruge det, hvor det er nødvendigt. Dette er en stor hjælp til at skrive kortfattet kode i Go.