GoSuda

Syy, miksi Go valitsi eksplisiittisen virheen palauttamisen ja panic-recover-mekanismin try-catch-poikkeusten heittämisen sijaan

By Rabbit Princess views ...

Go-kieli ei tarkoituksellisesti tue try-catch-rakennetta, vaan ainoastaan panic-recover-syntaksia. Tämä on herättänyt paheksuntaa lukuisten kehittäjien keskuudessa, jotka ovat tottuneet try-catch-pohjaiseen virheenkäsittelyyn. Miksi try-catchia sitten ei ole otettu käyttöön? Syynä on se, että try-catchiin liittyy useita ongelmia.

try-catch-finally

Try-catch (try-catch) -rakenne on syntaksi, jolla käsitellään ohjelman suorituksen aikana (ajonaikaisesti) ilmeneviä virhe- ja poikkeustilanteita. Finally-lohko puolestaan sisältää koodin, joka on suoritettava ehdoitta riippumatta siitä, esiintyikö poikkeus.

Virheenkäsittely ja vastuu

1980- ja 1990-luvulla virheenkäsittely oli hyvin yksinkertaista. Virheilmoitukset olivat ainoastaan seuraavat: "levy on täynnä", "asemassa ei ole levykettä" ja "levykkeelle kirjoittaminen ei ole sallittua". Tuolloin kehittäjä heitti virheen (throw) virheenkäsittelykohtaan asti, kun virhe ilmeni, ja käsitteli sen siellä yhtenäisesti. Tässä tilanteessa try-catch-rakenne toimi tehokkaasti.

Ajan myötä tilanne kuitenkin muuttui. Liiketoimintalogiikka monimutkaistui, tietokantoja ja transaktioita ilmestyi, verkon yli kutsuttiin lukuisia rajapintoja ja samalla oli tulkittava suuri määrä pyyntöviestejä. Rinnakkaisohjelmoinnin yleistyessä virheitä oli lisäksi käsiteltävä muissa säikeissä kuin pääsäikeessä.

Virheet eivät enää olleet hallittavissa yhdessä paikassa, eikä mikään yksittäinen kohta voinut vastata kaikista virheistä. Tässä kohdassa try-catchiin kehittyy vakava ongelma.

try-catchin vastuunsiirto

Try-catch on lyhyesti sanottuna tapa, jolla virheen aiheuttava taho siirtää virheestä aiheutuvan vastuun (jälkihoidon) jollekin toiselle. Tämä taho voi olla catch-lohko, oma kutsuva metodi tai jokin kauempana kutsupinossa oleva metodi. Toisin sanoen maailmassa, jossa virheenkäsittely lisääntyy ja monimutkaistuu, try-catchin valitsema menetelmä on juuri ajatus "joku hoitaa tämän". 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}

Edellä olevan koodin ongelmana on, ettei ole selvää, kuka printStackTrace-kutsun tuloksen käsittelee, eikä voida tietää, missä kohdassa koodia virhe syntyi. Kun try-lohkossa on enemmän logiikkaa, ongelma pahenee entisestään. Paradoksaalista kyllä, kehityksen monimutkaistuessa kehittäjät turvautuivat yhä enemmän vastuuta siirtävään try-catch-rakenteeseen. He lakkasivat pohtimasta virheenkäsittelyä, vastuuntunto heikkeni, ja lopulta he unohtivat virhe- ja poikkeuskäsittelyn olemuksen. Miten golang sitten ratkaisi tämän ongelman?

panic, recover

Yksi Go-kielen vahvuuksista on se, että sen järjestelmät ohjaavat kehittäjää hyviin käytäntöihin eivätkä vie häntä huonoille poluille. Ne kasvattavat hänestä hyvän kehittäjän. Myös panic-recover on tästä hyvä esimerkki. ​ Panic ja recover näyttävät ensi silmäyksellä vastaavan try-catchia, mutta ne eroavat siinä, että ongelman ilmetessä vastuuta ei siirretä ulospäin. Go-kielessä paniikin tapahtuessa arvoa ei ole tarkoitus välittää ulos, vaan ratkaisu on tehtävä siinä kohdassa, jossa paniikki syntyi. Tämä antaa kehittäjälle vastuun virheenkäsittelystä ja kannustaa häntä pohtimaan syvällisemmin, missä, kuka ja miten virhe on käsiteltävä. Se takaa käyttäjälle itsenäisyyden ja jättää tilaa harkinnalle.

Lisäksi sanavalinta panic on erinomainen. Toisin kuin try-recover, panic-recover painostaa kehittäjää käyttämään sitä ainoastaan selvissä virhetilanteissa eikä poikkeustilanteissa. Luonnollisesti kehittäjä ei käytä recover-toimintoa liikaa, vaan ainoastaan siellä, missä se on tarpeen. Tämä auttaa merkittävästi kirjoittamaan tiivistä koodia Go-kielellä.