Hvorfor har ikke Go Try-Catch?
go støtter bevisst ikke try-catch, men kun panic-recover syntaksen. Dette har ført til misnøye blant mange utviklere som er vant til feilhåndtering ved hjelp av try-catch. Hvorfor velger man da å utelate try-catch? Årsaken er at try-catch har flere problematiske aspekter.
try-catch-finally
Try-catch-strukturen er en syntaks for å håndtere feilsituasjoner og unntakssituasjoner som kan oppstå under programkjøring (runtime). I tillegg inneholder finally-blokken kode som ubetinget skal utføres, uavhengig av om et unntak oppstår eller ikke.
Feilhåndtering og ansvar
På 80- og 90-tallet var feilhåndteringen svært enkel. Feilmeldingene var begrenset til 'Floppy disk full', 'No floppy disk in drive', 'No write permission for floppy disk', og utviklere på den tiden håndterte feil ved å kaste (throw) feilen opp til et felles feilhåndteringspunkt for behandling. I slike situasjoner fungerte try-catch-strukturen effektivt.
Imidlertid har situasjonen endret seg over tid. Forretningslogikken er blitt mer kompleks, databaser og transaksjoner har oppstått, og det har blitt nødvendig å tolke utallige Request-meldinger ved å kalle et stort antall API-er over nettverket. I tillegg, med fremveksten av concurrency programming, måtte feil håndteres i andre tråder enn Main-tråden.
Feilene er blitt for komplekse til å håndteres på ett sted, og ingen enkelt enhet kan ta ansvar for alle feilene. Det er her et alvorlig problem med try-catch oppstår.
try-catch's ansvarsfraskrivelse
Kort sagt er try-catch en metode der enheten som utløste feilen skyver ansvaret (etterbehandlingen) for feilen over på noen andre. Denne mottakeren kan være catch-blokken, dens foreldremetode, eller forelderen til forelderen til forelderen til forelderen av... noen. Med andre ord, i en verden der feilhåndtering øker og blir mer komplisert, er metoden try-catch har valgt, ganske enkelt: "Noen andre vil fikse 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 koden ovenfor er at det verken er klart hvem som håndterer printStackTrace, eller hvilken kode som forårsaket feilen. Problemet blir enda verre jo mer logikk som legges til i try-setningen. Men paradoksalt nok, jo mer kompleks utviklingen ble, desto mer avhengige ble utviklerne av try-catch-strukturen som fraskrev seg ansvar. De sluttet å tenke på feilhåndtering, ansvarsfølelsen ble svekket, og til slutt glemte de essensen av feil- og unntakshåndtering. Hvordan har da golang løst dette problemet?
panic, recover
En av fordelene med go er trolig at det finnes flere systemer som er ment å lede utviklere bort fra dårlige vaner og hjelpe dem til å bli gode utviklere. panic - recover kan nevnes som et eksempel på dette. Panic og recover kan ved første øyekast se ut som try-catch, men de skiller seg ut ved at de ikke skyver ansvaret utover når et problem oppstår. Når en panic inntreffer i go, bør verdien løses på stedet der panikken oppsto, i stedet for å sendes utover. Dette tildeler ansvaret for feilhåndtering til utvikleren, og oppmuntrer dem til å tenke dypere over hvor, hvem og hvordan feilen skal håndteres. Det sikrer autonomi for brukeren samtidig som det gir rom for refleksjon.
Valget av ordet "panic" er også svært vellykket. I motsetning til try-recover, legger panic-recover et press på utvikleren, bare gjennom ordvalget, om at det kun skal brukes i klare feilsituasjoner, og ikke i unntakssituasjoner. Naturlig nok vil utviklere unngå å misbruke recover og kun bruke det der det er nødvendig. Dette bidrar sterkt til å skrive konsis kode i go.