( SzBlackY | 2015. 07. 16., cs – 08:58 )

Próbálok sorban:

Checked Exception.

nehéz refaktorálni

Ha rosszul volt tervezve (vagyis simán áteresztette magán a belső checked exception-öket, vagyis implementációs részeket leakelt), akkor valóban. Ha viszont saját Exception osztályt használt burkolt belső kivételekkel, akkor (leszámítva az esetet, hogy tudod garantálni a hibamentességet és meg lehet szüntetni az Exception-t :) ) nagyjából ugyanannyi refaktorálni, mintha runtime exception-öket dobáltál volna vagy az exception-t visszaadtad volna.

inkonzisztens állapotot hagyhat maga után és Többszörös érték visszaadás.
nem hagy inkonzisztens állapotot maga után

(Egyébként ha immutable objektumok felett pure function-öket használsz, ez kb. tárgytalan)
Mennyiben segíti a többszörös érték visszaadás az inkonzisztens értékek visszaadását. Ha egy metódus törzsében "középen" kapsz egy hibát, a többszörös érték visszaadás rákényszerít-e, hogy visszatérj egy konzisztens állapotba? Valóban, ugyanígy egy checked exception sem kényszeríti ki a konzisztenciát, viszont (ha csak nem nyeli le a kód az Exception-t), legalább garantáltan propagálódik az értesítés, hogy nem feltétlenül konzisztens.

nehéz kombinálni más dolgokkal (compose)

?
Jó esetben a más dolgoknak is van egy saját kivétele a signiture-ben, egy laza mozdulattal beágyazod a külső kivételbe, és jónapot.

Többszörös érték visszaadás.

könnyebben olvasható a kód

Szerintem nem. Egy kivételnél szépen látod, hogy meddig tart a try blokk, tudod, hogy azon a szakaszon fordulhat elő valami hiba - aminek a kezelése elkülönül a fő ágtól. Linkeltétek a "használjunk wrapper függvényt, ami feljegyzi, hogy volt-e már hiba és ha igen, menjen át noop-ba" megoldást: azon a kódon nagyon szépen látszik, hogy - pont, mint C-ben, jobb eszköz híján - a hibakezelés bekerült a fő ágba.
Ráadásul a példa meglehetősen egyszerűsített, mivel egy homogén művelet hibáit veszi csak figyelembe. Ugyanez mondjuk annál, hogy beszúrsz egy rekordot a DB-be, és küldesz egy értesítő e-mailt már lényegeseb bonyolultabb lesz (és függetlenül attól, hogy hogyan szervezed a kódod, elrejtheted akár 15 hívás mélységben is):
ha a rekord beszúrásánál hiba volt, akkor tranzakció vissza, nem küldünk levelet.
ha a levél kiküldésénél hiba volt, akkor adatbázis tranzakció vissza.
ha nem volt hiba, örülünk.

Ez ugye Exception-ökkel


try {
 db.beginTransaction();
 db.insert(foo);
 mail.send(bar);
 db.commit();
} catch (MailException x) {
 db.rollback();
} catch (DBException x) {

}

A fő ágad és a hibakezelésed szépen elkülönül. Ha nincs kivételkezelésed (pszeudó-kód, mert nem ismerem a go-t)


db.beginTransaction()
err_db = db.insert(foo)
if err_db != nil
  err_mail = mail.send(bar)
  if err_mail != nil 
     err_db.rollback()
  else
     db.commmit()
  endif
endif

A kód komplexitása ugyanaz maradt (4 lehetséges út van), viszont az utóbbinál kénytelen vagy mind a négy utat expliciten megjeleníteni a fő ágadban. Ami a tranzakción belül műveletek számával szépen (talán) exponenciálisan fog nőni (tegyük bele a kötelező naplózást egy audit naplóba, ami ha nem sikerül, vissza kell vonni a tranzakciót - a mail mondjuk itt már keresztbe tesz, mert annak van egy visszavonhatatlan mellékhatása; vagyis azt kell mindig utoljára hagyni), ez újabb elágazást fog jelenteni. Exception-nel ez egy újabb audit.log('foo') hívás, és egy újabb catch block. A komplexitás ott is ugyanaz, _kód szinten_ mégse nő az elágazások száma.

könnyű refaktorálni

Mennyivel könnyebb, mint a check exception-nél? A method signature-t mindenképp módosítanod kell, az meg nagyjából lényegtelen, hogy a visszatérési érték változik, vagy a dobott kivételek listája.

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)