Frustrace ze stavu mainstreamových programovacích jazyků

Kiwi

Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #45 kdy: 21. 08. 2017, 01:02:26 »
Způsobuje separaci místa vzniku chyby od místa jejího zpracování, a to i vertikálně, přes úrovně jednotlivých vrstev, což je IMO zlo. [...] A tak se na to kašle, nechá se to zpropagovat až kdo ví kam a tam se teprve chyba řeší. Jenže takové místo je z hlediska struktury, tj. viditelnosti a rozsahu platnosti jednotlivých entit, izolované od místa vzniku. Vlastně už se tam nedá dělat nic, než jen vzít na vědomí, že "někde dole" vznikla chyba
...což je přesně to, co u velkého množství programů chceš. Nějaký velký blok kódu řeší jednu věc, například načtení credentials, připojení na server, autentizace. Nechceš řešit všechny možné chybové stavy u všech jednotlivých kroků. Chceš na nejvyšší úrovni dostat informaci "nemohl jsem se připojit, protože ..." (nelze se připojit k DB, credentials jsou neplatné, server je nedostupný apod.)

Kdybys měl opravdu na každém místě řešit úplně všechny chybové stavy, ke kterým může dojít (včetně lowlevel věcí jako např. "out of memory" apod.), tak v té změti checkování bude ten samotný algoritmus jako jehla v kupce sena.

Asi záleží, co kdo dělá. Ve svém oboru (embedded, průmyslová automatizace) jsem vypozoroval, že to není, co chci. Buď budu chybové stavy řešit poctivě, což je u robustních aplikací naprosto nezbytné, ale pak výjimky nepřinášejí žádný benefit, jen se celý kód zaprasí try/catch smetím, a to jak na zdrojové, tak na strojové úrovni, nebo se to bude řešit implicitní propagací chyb, ale pak si do programu zanesu špatně definované, "nelexikální" stavy, což je v tomto oboru naprosto nepřijatelné - takový model ošetření chyb se nedá pořádně ani zauditovat, protože není bezkontextový.
Chyba se musí ošetřit co nejblíže místu, kde vznikla, nebo propagovat explicitně jako reinterpretovaná chyba vyšší vrstvy.

Netvrdím, že výjimky nemají své místo. Umožňují naprasit program, který nakonec vždycky skončí alespoň s vědomím, že se někde něco podělalo, místo aby program dále rozvíjel chybný stav. Ono to dokáže člověka naštvat i u nevinné aplikace, jako třeba nějaký EDA nástroj, kdy někde nějak špatně pohneš myší a celé to spadne na nějaké takové výjimce a půl hodiny práce je v..., zatímco správně ošetřená, lokalizovaná chyba tohoto typu by neměla mít na chod celé aplikace tak fatální následky. Ale u robustní aplikace je takové chování nepřijatelné.

Ano, považuji za normální testovat chybu na místě vzniku, i za cenu "znepřehlednění" algoritmu. Tvorba programu je inženýrská činnosti a inženýr by měl být s takovými situacemi srozuměn a schopen se v nich orientovat. Výmluvy tohoto typu mi připadají podobně absurdní, jako tvrdit, že všelijaká ložiska, těsnící kroužky, gufera, pružiny, podložky, olejové kanálky apod. "znepřehledňují" návrh spalovacího motoru. Jsou zkrátka jeho součástí a samozřejmě, že reálný, prakticky fungující motor je oproti školnímu dřevěnému modelu složitější a tak trochu se v něm ten vlastní princip ztrácí. Tak to prostě v životě je.

Zrovna nedávno jsem psal jeden takový modul, kdy jsem si říkal, že ty testy chybových stavů tvoří většinu kódu. Přirozeně to člověka dokopalo k refaktoraci, po níž je kód i bez použití výjimek naprosto přehledný, z hlediska (chybových) stavů dobře analyzovatelný a přitom robustní.

Mám takový pocit, že výjimky jsou jedním z mechanismů, jež pomáhají činit nevhodně navržené programy životaschopnými. Ale nejsem přesvědčen o tom, že to je dobře.


Aoidhghean

Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #46 kdy: 21. 08. 2017, 01:10:26 »
Způsobuje separaci místa vzniku chyby od místa jejího zpracování, a to i vertikálně, přes úrovně jednotlivých vrstev, což je IMO zlo. [...] A tak se na to kašle, nechá se to zpropagovat až kdo ví kam a tam se teprve chyba řeší. Jenže takové místo je z hlediska struktury, tj. viditelnosti a rozsahu platnosti jednotlivých entit, izolované od místa vzniku. Vlastně už se tam nedá dělat nic, než jen vzít na vědomí, že "někde dole" vznikla chyba
...což je přesně to, co u velkého množství programů chceš. Nějaký velký blok kódu řeší jednu věc, například načtení credentials, připojení na server, autentizace. Nechceš řešit všechny možné chybové stavy u všech jednotlivých kroků. Chceš na nejvyšší úrovni dostat informaci "nemohl jsem se připojit, protože ..." (nelze se připojit k DB, credentials jsou neplatné, server je nedostupný apod.)

Kdybys měl opravdu na každém místě řešit úplně všechny chybové stavy, ke kterým může dojít (včetně lowlevel věcí jako např. "out of memory" apod.), tak v té změti checkování bude ten samotný algoritmus jako jehla v kupce sena.

Asi záleží, co kdo dělá. Ve svém oboru (embedded, průmyslová automatizace) jsem vypozoroval, že to není, co chci. Buď budu chybové stavy řešit poctivě, což je u robustních aplikací naprosto nezbytné, ale pak výjimky nepřinášejí žádný benefit, jen se celý kód zaprasí try/catch smetím, a to jak na zdrojové, tak na strojové úrovni, nebo se to bude řešit implicitní propagací chyb, ale pak si do programu zanesu špatně definované, "nelexikální" stavy, což je v tomto oboru naprosto nepřijatelné - takový model ošetření chyb se nedá pořádně ani zauditovat, protože není bezkontextový.
Chyba se musí ošetřit co nejblíže místu, kde vznikla, nebo propagovat explicitně jako reinterpretovaná chyba vyšší vrstvy.

Netvrdím, že výjimky nemají své místo. Umožňují naprasit program, který nakonec vždycky skončí alespoň s vědomím, že se někde něco podělalo, místo aby program dále rozvíjel chybný stav. Ono to dokáže člověka naštvat i u nevinné aplikace, jako třeba nějaký EDA nástroj, kdy někde nějak špatně pohneš myší a celé to spadne na nějaké takové výjimce a půl hodiny práce je v..., zatímco správně ošetřená, lokalizovaná chyba tohoto typu by neměla mít na chod celé aplikace tak fatální následky. Ale u robustní aplikace je takové chování nepřijatelné.

Ano, považuji za normální testovat chybu na místě vzniku, i za cenu "znepřehlednění" algoritmu. Tvorba programu je inženýrská činnosti a inženýr by měl být s takovými situacemi srozuměn a schopen se v nich orientovat. Výmluvy tohoto typu mi připadají podobně absurdní, jako tvrdit, že všelijaká ložiska, těsnící kroužky, gufera, pružiny, podložky, olejové kanálky apod. "znepřehledňují" návrh spalovacího motoru. Jsou zkrátka jeho součástí a samozřejmě, že reálný, prakticky fungující motor je oproti školnímu dřevěnému modelu složitější a tak trochu se v něm ten vlastní princip ztrácí. Tak to prostě v životě je.

Zrovna nedávno jsem psal jeden takový modul, kdy jsem si říkal, že ty testy chybových stavů tvoří většinu kódu. Přirozeně to člověka dokopalo k refaktoraci, po níž je kód i bez použití výjimek naprosto přehledný, z hlediska (chybových) stavů dobře analyzovatelný a přitom robustní.

Mám takový pocit, že výjimky jsou jedním z mechanismů, jež pomáhají činit nevhodně navržené programy životaschopnými. Ale nejsem přesvědčen o tom, že to je dobře.
Toto je přístup tvůrce softwaru pro jaderné elektrárny nebo sondu, co má přistát na kometě. Dobře, trochu přeháním... Ono to je v podstatě metodicky správné a kdyby bylo bezprostřední ošetření chyby na jeden řádek, tak by to bylo ideální. Problémem v Go je to nešťastné gofmt, které z každého "if err!=nil{return nil,err}" udělá tři řádky.

.

Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #47 kdy: 21. 08. 2017, 02:40:20 »
Toto je přístup tvůrce softwaru pro jaderné elektrárny nebo sondu, co má přistát na kometě. Dobře, trochu přeháním... Ono to je v podstatě metodicky správné a kdyby bylo bezprostřední ošetření chyby na jeden řádek, tak by to bylo ideální. Problémem v Go je to nešťastné gofmt, které z každého "if err!=nil{return nil,err}" udělá tři řádky.
To, že většina používá explicitní "if err!=nil{return nil,err}" neznamená, že je to vždy jediná možnost. Doporučuji se podívat třeba na package bufio a scanner.Err().

jsou to dvě strany téže mince.
Co? Co je jedna strana a co druhá? A jaké jedné mince?
Až doteď jsem si myslel, že ti to pálí trochu víc... ;)

Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #48 kdy: 21. 08. 2017, 03:52:02 »
Toto je přístup tvůrce softwaru pro jaderné elektrárny nebo sondu, co má přistát na kometě. Dobře, trochu přeháním... Ono to je v podstatě metodicky správné a kdyby bylo bezprostřední ošetření chyby na jeden řádek, tak by to bylo ideální. Problémem v Go je to nešťastné gofmt, které z každého "if err!=nil{return nil,err}" udělá tři řádky.
Ale vy oba pletete hrušky s jabkama. Výjimky umožňují reagovat na chybu v nějakém *bloku*. Tj. je mi jedno, na jakém řádku v bloku k chybě X došlo, prostě blok jako celek selhal kvůli X a reaguju na to způsobem Y. Výjimky slouží k tomu, abych nemusel Y opakovat po každém řádku v bloku. Se spolehlivostí to nemá co dělat.

Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #49 kdy: 21. 08. 2017, 03:54:10 »
Až doteď jsem si myslel, že ti to pálí trochu víc... ;)
Pálí a nepálí jsou dvě strany téže mince, takže ses nespletl.


Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #50 kdy: 21. 08. 2017, 06:59:52 »
Toto je přístup tvůrce softwaru pro jaderné elektrárny nebo sondu, co má přistát na kometě. Dobře, trochu přeháním... Ono to je v podstatě metodicky správné a kdyby bylo bezprostřední ošetření chyby na jeden řádek, tak by to bylo ideální. Problémem v Go je to nešťastné gofmt, které z každého "if err!=nil{return nil,err}" udělá tři řádky.
Ale vy oba pletete hrušky s jabkama. Výjimky umožňují reagovat na chybu v nějakém *bloku*. Tj. je mi jedno, na jakém řádku v bloku k chybě X došlo, prostě blok jako celek selhal kvůli X a reaguju na to způsobem Y. Výjimky slouží k tomu, abych nemusel Y opakovat po každém řádku v bloku. Se spolehlivostí to nemá co dělat.
To jsou ty dvě strany mince - buďto mám kód, který jednoznačně handluje chyby - příkaz po příkazu (bude delší, ale názorný) nebo používám výjimky, kde handlování může (a nemusí) být daleko od vzniku. V GO je víc rozlišeno jestli se jedná o chybu, kterou lze ošetřit nebo výjimku, u které autor předpokládal, že dál v procesu nejde pokračovat - např. došla paměť, atd.

Kiwi

Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #51 kdy: 21. 08. 2017, 10:11:19 »
Toto je přístup tvůrce softwaru pro jaderné elektrárny nebo sondu, co má přistát na kometě. Dobře, trochu přeháním...

Sice je náhodou pravda, že na řídících systémech JE jsem se učil, ale platí to IMHO pro většinu provozů - ať už se řídí reaktor, nebo granulační kotel či ethylenová jednotka. Ve všech případech bude nespolehlivý software příčinou škod.

Se spolehlivostí to nemá co dělat.

Ano i ne. Prvoplánově výjimky spolehlivost zvyšují, protože garantují, že každá chyba někam spadne. Jenže tu zároveň vzniká hned několik nových problémů.
* delokalizovaná chyba se špatně řeší; není to přímo problém samotných výjimek, ale jejich přístup programátory nemotivuje k lokalizaci chyby; čím výše chyba propadne, s tím větším kanónem se pak na ni jde
* problém nedefinovaných stavů, typicky nedokončená inicializace/likvidace; u jazyků s GC je tento problém méně palčivý, ale i tam existuje a o to může být zákeřnější; výjimky de facto násobí počet možných stavů programu a to považuji za velké zlo
* problém optimalizace; mechanismus výjimek redundantně testuje chyby i v místech, kde z principu být nemohou, např. protože už dané hodnoty byly otestovány jinde; to mimo jiné vede k doporučením psát "exception-driven" stylem, kdy např. pole procházíš hlava-nehlava, dokud nevyletí cosi jako array index out of bounds, takže vedle opravdových chybových stavů si vytváříš a testuješ ještě umělé chybové stavy a výsledná změť try-catchů zatemňuje algoritmus mnohem efektivněji než klasické testování návratových hodnot.

Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #52 kdy: 21. 08. 2017, 10:33:37 »
není to přímo problém samotných výjimek, ale jejich přístup programátory nemotivuje k lokalizaci chyby; čím výše chyba propadne, s tím větším kanónem se pak na ni jde
No, tak jsme se dostali k tomu, co jsem říkal: ve výjimkách problém není - pokud je to potřeba, dají se používat se stejnou granularitou jako návratové kódy.

V Erlangu se výjimky používají a těžko bysme hledali něco, co je víc synonymem pro robustnost než Erlang.

.

Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #53 kdy: 21. 08. 2017, 12:35:43 »
není to přímo problém samotných výjimek, ale jejich přístup programátory nemotivuje k lokalizaci chyby; čím výše chyba propadne, s tím větším kanónem se pak na ni jde
No, tak jsme se dostali k tomu, co jsem říkal: ve výjimkách problém není - pokud je to potřeba, dají se používat se stejnou granularitou jako návratové kódy.

V Erlangu se výjimky používají a těžko bysme hledali něco, co je víc synonymem pro robustnost než Erlang.
Otázka je, jestli to není spíš dáno těmi pěti programátory, kteří jediní v Erlangu programují. :D

Ale vážně, pokud bychom hledali absolutní synonymum spolehlivosti, pak by to byl asi TeX. A ačkoliv spolehlivost je určitě dána i povahou a vlastnostmi jazyka (tady konkrétně WEB/CWEB), mnohem víc ji ovlivňuje to, že v něm programují pouze experti, podobně jako v tom Erlangu.

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #54 kdy: 21. 08. 2017, 13:05:12 »
panic/recover (jen jinak pojmenované výjimky)
Aha, na to jsem ještě nenarazil :) Na první pohled to nevypadá úplně blbě, problém je, že se to nikde nepoužívá - všude jsou ty explicitní návratový kódy.
Používá se to pro uklízení gorutin, když 3rd party kód zpanikaří (třeba na blbém out of index, nepřípustném přetypování nebo něco takového), runtime zlikviduje tuto jednu padlou gorutinu a jde-li třeba o obsluhu http požadavku, musí knihovna po sobě uklidit.

kimec

Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #55 kdy: 21. 08. 2017, 18:51:48 »
není to přímo problém samotných výjimek, ale jejich přístup programátory nemotivuje k lokalizaci chyby; čím výše chyba propadne, s tím větším kanónem se pak na ni jde
V Erlangu se výjimky používají a těžko bysme hledali něco, co je víc synonymem pro robustnost než Erlang.
Zbytocne tu nedrazdite ludi. Neni kazdy ready na Erlangove "let it crash" a kontrolovany damage mode skrz hierarchiu supervisor actorov.

Jan Korous

Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #56 kdy: 21. 08. 2017, 23:52:46 »
Pokud to neni prilis mimo tema, byl bych zvedavy na vase nazory ohledne vyjimek v C++. Zatim byla diskuze hodne dobra, tak snad to nezazdim.

Specificita
Definujete si vlastni vyjimky nebo hazite vyjimky z STL? Vytvarite pripadne rozsahle hierarchie s konkretni chybou staticky vazanou na typ vyjimky nebo to resite na urovni dat hozene instance?

Modularita systemu
Sveho casu jsem byl ovlivnen C++ FAQ od Marshalla Cline, ktery kazal mit vyjimky definovane spolecne pro cely system bez ohledu na rozhrani a moduly. Dnes uz si tim nejsem tak jist.
https://isocpp.org/wiki/faq/exceptions#mindset-for-proper-use-of-eh
Citace
Exception classes cross subsystem boundaries — they are part of the intellectual glue that holds the architecture together.
Delate to stejne nebo mate na kazdem rozhrani definovane vyjimky a v implementaci prekladate?

Aoidhghean

Re:Frustrace ze stavu mainstreamových programovacích jazyků
« Odpověď #57 kdy: 22. 08. 2017, 09:14:18 »
Pokud to neni prilis mimo tema, byl bych zvedavy na vase nazory ohledne vyjimek v C++. Zatim byla diskuze hodne dobra, tak snad to nezazdim.

Specificita
Definujete si vlastni vyjimky nebo hazite vyjimky z STL? Vytvarite pripadne rozsahle hierarchie s konkretni chybou staticky vazanou na typ vyjimky nebo to resite na urovni dat hozene instance?

Modularita systemu
Sveho casu jsem byl ovlivnen C++ FAQ od Marshalla Cline, ktery kazal mit vyjimky definovane spolecne pro cely system bez ohledu na rozhrani a moduly. Dnes uz si tim nejsem tak jist.
https://isocpp.org/wiki/faq/exceptions#mindset-for-proper-use-of-eh
Citace
Exception classes cross subsystem boundaries — they are part of the intellectual glue that holds the architecture together.
Delate to stejne nebo mate na kazdem rozhrani definovane vyjimky a v implementaci prekladate?
Není-li nezbytné poskytnout nějaký specifický kontext, je pohodlnější házet výjimky z STL.

Re:výjimky
« Odpověď #58 kdy: 22. 08. 2017, 10:19:32 »
Velice děkuji všem řečníkům za tenhle rozbor "výjimek". Je to hrozně stará vesta, ale mému hovězímu mozku výjimky dlouhodobě "tak nějak nevyhovují" a nedocházejí. Teď dokážu ten pocit asi i definovat: vadí mi samotný princip, že se snažím oddělit místo zjištění chyby od místa, kde se na ni snažím nějak smysluplně reagovat. V mém přízemním pojetí místo zjištění chyby poskytuje maximum kontextu, potřebného k nějaké smysluplné reakci na vyskytnuvší se chybu. Mohu to zkusit znova, mohu si učinit specifickou poznámku pro nějaké následné zpracování, mohu inteligentně uklidit a nahlásit nějakou mírně abstrahovanou informaci o úroveň výš apod. Jasně, toto lze i s použitím výjimek. Jako výhoda výjimek bývá uváděna čistota kódu, nezapraseného ustavičným lokálním ošetřováním chybových stavů. Nojo, ale když ty chybové stavy řeším pak někde o kus dál všechny na jedné hromadě, oddělené od kontextu jejich vzniku, to má být přehledné a pochopitelné?

Mám pocit, že ať už to člověk píše "postaru" nebo s výjimkami, nakonec je to hlavně o sebekázni a pečlivosti - jak vysoko (daleko od místa vzniku) chybu zachytit a řešit, jak podrobně předem počítat s možností výskytu různých druhů chyb, jak moc "defenzivně" je vhodné programovat apod.

Re:výjimky
« Odpověď #59 kdy: 22. 08. 2017, 11:00:57 »
Nojo, ale když ty chybové stavy řeším pak někde o kus dál všechny na jedné hromadě, oddělené od kontextu jejich vzniku, to má být přehledné a pochopitelné?
Tohle ale není moc dobrý příklad použití výjimek. Když použijete výjimky správně, budete výjimku pořád ošetřovat v místě jejího vzniku, kde znáte kontext, a pokud se nepodaří ji na daném místě vyřešit, pošlete dál nějakou obecnější výjimku.

Tím „nezaprasením kódu lokálním ošetřování chybových stavů“ se nemyslí to, že se v celé aplikaci nebudete o výjimky zajímat a ošetříte je všechny najednou někde v main. Tím se myslí to, že nemusíte kontrolovat chybový stav po provedení každé jednotlivé funkce a nemusíte na to reagovat pořád dokola tím stejným kódem.

Třeba když chcete otevřít soubor, něco z něj přečíst a soubor zavřít – může dojít ke spoustě výjimečných situací, např. může být soubor v každém kroku nedostupný (např. root odmountuje zařízení, na kterém soubor leží). Nevidím žádnou výhodu v tom ošetřovat tenhle stav znovu po každém z těch třech kroků, protože nezáleží na tom, ve kterém kroku k té chybě došlo, reakce bude pořád stejná.