GoSuda

Miksi Go:ssa ei ole Try-Catchia?

By Rabbit Princess
views ...

Go ei tarkoituksellisesti tue try-catch-rakennetta, vaan ainoastaan panic-recover-syntaksia. Tämä on herättänyt tyytymättömyyttä monissa kehittäjissä, jotka ovat tottuneet virheenkäsittelyyn try-catch-rakenteella. Miksi try-catch-rakennetta ei siis ole sisällytetty? Syynä on se, että try-catch-rakenteeseen liittyy useita ongelmia.

try-catch-finally

Try-catch-rakenne on ohjelmointikielinen rakenne, jonka tarkoituksena on käsitellä ohjelman suorituksen (ajon aikana) mahdollisesti ilmeneviä virhe- ja poikkeustilanteita. Lisäksi finally-lohkoon kirjoitetaan koodi, joka on suoritettava riippumatta siitä, onko poikkeusta tapahtunut vai ei.

Virheenkäsittely ja vastuu

1980- ja 1990-luvuilla virheenkäsittely oli hyvin yksinkertaista. Virheilmoitukset olivat tyypillisesti "levyke täynnä", "ei levykettä asemassa" tai "ei kirjoitusoikeutta levykkeelle", ja tuon ajan kehittäjät heittivät virheen käsittelypisteeseen, jotta se voitaisiin käsitellä yhteisesti. Tällaisessa tilanteessa try-catch-rakenne toimi tehokkaasti.

Ajan myötä tilanne kuitenkin muuttui. Liiketoimintalogiikka monimutkaistui, tietokannat ja transaktiot syntyivät, ja lukuisten API-kutsujen kautta verkon yli täytyi tulkita lukuisia pyyntöviestejä. Lisäksi samanaikaisen ohjelmoinnin myötä virheitä täytyi käsitellä muissa säikeissä kuin pääsäikeessä.

Virheistä tuli niin monimutkaisia, ettei niitä voinut enää käsitellä yhdessä paikassa, eikä kukaan voinut ottaa vastuuta kaikista virheistä. Tässä try-catch-rakenteeseen syntyy vakava ongelma.

try-catch-rakenteen vastuunsiirto

Try-catch-rakenne on lyhyesti sanottuna tapa, jolla virheen aiheuttaja siirtää vastuun virheen käsittelystä (jälkikäsittelystä) jollekin toiselle. Tämä kohde voi olla catch-lohko, oma ylätason metodi tai oma ylätason ylätason ylätason ylätason... joku. Toisin sanoen, maailmassa, jossa virheenkäsittely lisääntyy ja monimutkaistuu, try-catch-rakenteen valitsema tapa on "joku hoitanee sen". Tarkastellaan seuraavaa koodia.

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}

Yllä olevan koodin ongelmana on, että ei ole selvää, mikä taho käsittelee printStackTrace-kutsua, eikä myöskään voida tietää, missä koodin osassa virhe tapahtui. Ongelma pahenee entisestään, mitä enemmän logiikkaa try-lauseen sisään syntyy. Ironista kyllä, mitä monimutkaisemmaksi kehitys muuttui, sitä riippuvaisemmiksi kehittäjät tulivat vastuuta siirtävästä try-catch-rakenteesta. He eivät pohtineet virheenkäsittelyä, heidän vastuuntuntonsa heikkeni, ja lopulta he unohtivat virheiden ja poikkeusten käsittelyn perusperiaatteet. Miten Go sitten ratkaisi tämän ongelman?

panic, recover

Yksi Gon eduista on, että siinä on useita järjestelmiä, jotka ohjaavat kehittäjiä hyviin käytäntöihin sen sijaan, että he ajautuisivat huonoille teille. Panic-recover on yksi tällainen esimerkki. ​ Panic ja recover saattavat ensi silmäyksellä vaikuttaa samankaltaisilta kuin try-catch, mutta ne eroavat siinä, että ne eivät siirrä vastuuta ongelman aiheuttamasta tilanteesta ulkopuoliselle. Kun Go:ssa tapahtuu panic, se on ratkaistava siinä paikassa, jossa panic tapahtui, sen sijaan, että arvo siirrettäisiin ulkopuoliselle. Tämä antaa kehittäjälle vastuun virheenkäsittelystä ja kannustaa häntä pohtimaan syvällisemmin, missä, kuka ja miten virhe tulisi käsitellä. Se takaa käyttäjälle autonomian, mutta jättää myös tilaa pohdinnalle.

Lisäksi sanan "panic" valinta on erittäin onnistunut, sillä toisin kuin try-recover, panic-recover luo jo sanallaan paineen kehittäjälle, että sitä tulisi käyttää vain selkeissä virhetilanteissa, ei pelkissä poikkeustilanteissa. Luonnollisesti kehittäjä ei käytä recoveria väärin, vaan ainoastaan tarvittavissa paikoissa. Tämä auttaa suuresti kirjoittamaan tiivistä koodia Go:ssa.