Přejít k navigační liště

Zdroják » Různé » Antipatterny, smradlavý kód a Peterův princip v IT

Antipatterny, smradlavý kód a Peterův princip v IT

Články Různé

U předchozího článku se už v titulku objevilo slovo „antipattern“. Jak samotný název napovídá, jde o určitý protipól návrhových vzorů, „patternů“, ovšem tentokrát v opačném smyslu, tedy „jak to nedělat“. Pojďme si taková „antidoporučení“ projít – a nezapomeňme se přepnout do módu „nadsázka povolena“.

Peterův princip říká, že v hierarchické organizaci jsou lidé povyšováni tak dlouho, až se dostanou na pozici, na kterou už nestačí. Je to logický důsledek snahy povyšovat lidi, kteří se na svém místě osvědčili – jednoho dne jsou povýšeni do funkce, kterou už nezvládnou, a tam se jejich postup zastaví.

Generalizace tohoto principu říká, že cokoli, co funguje, bude používáno pro stále složitější a odtažitější úkoly, až to bude nasazeno někde, kde to už fungovat nebude. Každý z nás jistě dokáže vyjmenovat několik takových příkladů z oboru software a IT vůbec. Nástroje, původně napsané pro určitou konkrétní oblast, se ukázaly životaschopnými – a za chvíli je vývojáři ohýbali pro použití v oblastech, kde víc práce zabralo samotné ohnutí oblíbeného nástroje než použití jiného, vhodnějšího.

Softwarový Peterův princip má význam lehce odlišný. Popisuje vývoj softwarového projektu, který se pomalu stává složitějším a složitějším, až sami vývojáři přestanou rozumět tomu, na čem vlastně pracují, a projekt ještě chvíli jede setrvačností, dokud s rámusem nepadne. Následně je označen štítkem EPIC FAIL a starší kolegové jím straší ty služebně mladší.

Příčiny takového selhání mohou být tři (a většinou chodí ruku v ruce). První příčinou mohou být nezkušení vývojáři. Druhou příčinou pak vývojáři sice zkušení, ale nekompetentní. Definici „nekompetentního vývojáře“ nabízí Steve McConnell v knize Code Complete. Podle něho jsou nejlepší vývojáři ti, kteří pochopili, že je důležitější komunikovat s lidmi než se strojem. A nemusí to být jen třeba zákazníci nebo uživatelé – je potřeba komunikovat i s lidmi, co se o kód budou starat po vás. McConnell říká, že nekompetentní programátor upřednostňuje pokročilé a složité konstrukce či málo známé vlastnosti programovacích jazyků („programování na hraně“) před čitelností kódu. Kód psaný takovými programátory zvyšuje složitost celého projektu (i když mnozí z nich považují právě takové složité konstrukce za znak opravdového machra, co fakt do toho jazyka vidí).

Třetí příčinou selhání podle Peterova principu je ztráta koncepční jednoty. O tomto problému jsme si už na Zdrojáku říkali v článcích o projektovém řízení – ve chvíli, kdy začnou vývojáři podléhat nadšení z toho, co všechno by do projektu ještě mohli přidat, a nesoustředí se na základní funkčnost, je celý projekt na nejlepší cestě do pekel. Proto je potřeba, aby projekt řídil jeden člověk (nebo malý tým), který právě tyhle tendence udrží na uzdě a dokáže vývoj směřovat k určitému cíli. V projektech bez silného vedení a jasně dané koncepce se míchají otázky návrhu s otázkami implementace, a jejich řešení bývá ponecháno na uvážení programátorů. V případě, že mají programátoři v těchto oblastech přílišnou volnost, začnou přidávat nové funkce a zkoušet nové postupy a přepisovat už napsaný kód – a celý projekt se pak sype jak domek z karet.

Smradlavý kód

Vývojář s mnohaletou zkušeností dokáže kouknout na cizí kód a – aniž by ho podrobněji studoval – říct: S tím budou problémy. Jak to pozná? Většinou intuitivně. Špatný kód, se kterým budou problémy, totiž zapáchá (Code Smell). Co si pod takovým smrdutým kódem představit?

Nejčastější „smradlavé konstrukce“ jsou takové, o nichž každý programátor s alespoň základním teoretickým vzděláním ví, že je dělat nemá (ale v praxi pak vznikají „nějak samy“). Například duplikovaný kód – stejný nebo velmi podobný kód na různých místech. V OOP to jsou třeba příliš velké třídy, třídy s velkým množstvím funkcí, dlouhé metody, nebo naopak třídy příliš krátké, příliš „líné“ (lazy class, freeloader). Zapáchající kód představuje třeba třída, která přepisuje svého předka takovým způsobem, že ji lze za potomka považovat už jen stěží (viz Liskov substitution principle a související Circle-ellipse problem). Zapáchá i třída, jejíž správné fungování závisí na konkrétní implementaci jiné třídy (inappropriate intimacy) nebo taková, která zneužívá metody jiné třídy.

Zapáchající kód vznikne i přílišným lpěním na dogmatech – například použitím složitého návrhového vzoru tam, kde by stačilo jednoduché a přímočaré řešení. Problém mohou signalizovat i literály (konstantní řetězce či čísla) roztroušené po celém kódu, nebo používání složitých jmenných konvencí pro odlišení případů, které měly být odlišené samotnou architekturou.

Kód, v němž se takové příznaky vyskytují, zkrátka čpí na sto honů, a i když je možné, že bude teď a tady fungovat a bude svou funkci plnit, je velmi pravděpodobné, že s ním budou problémy při další údržbě, třeba při nutnosti přidat nebo pozměnit nějaké jeho funkce. V takovém případě je téměř jisté, že se něco rozbije

Antipatterny – „návrhové horrory“

Na rozdíl od návrhových vzorů, které nabízejí modelová řešení pro konkrétní situace a je dobré se jimi řídit (resp. ve standardní situaci použít standardizovaný vzor), jsou antipatterny spíš návrhové horrory. Jsou to často používaná (či „často vznikající“) řešení, která jsou možná funkční, ale z principu špatná. Popisují nejčastější kategorie vývojářských „nočních můr“. Pojďme si některé z nich představit.

Obrácení abstrakce (Abstraction inversion)

Obrácená abstrakce popisuje situaci, kdy kód sice dělá něco, co uživatel požaduje, ale autor tyto funkce nezpřístupní ostatním. Výsledkem je, že programátor musí tutéž funkci, která už je uvnitř implementovaná, napsat znovu, místo toho, aby ji prostě využil – nemá totiž jak. 

Hrouda bláta (Big ball of mud)

Už samotný název tohoto antipatternu říká, jak vypadá takový kód. Je to kód, v němž není rozpoznatelná struktura; slepenec tříd, metod, rozhraní, to všechno s nejasnými vazbami a souvislostmi. Čeština má pro takový kód rčení „prase aby se v tom vyznalo“.

Databáze jako komunikační rozhraní (Database-as-IPC)

Někdy není zbytí a prostředky, co máme k dispozici, jsou tak omezené (představme si např. sdílený LAMP hosting), že je potřeba řešit komunikaci mezi procesy pomocí databáze, v níž si nasimulujeme frontu zpráv. Což ale neznamená, že to je správné řešení. Správné řešení je použít vhodný IPC nástroj.

Pozlacení (Gold plating)

I tento antipattern jsme si už představovali v článcích o principu „good enough“. Každý projekt se dostane do bodu, za nímž už se nevyplatí vynakládat další prostředky na vývoj funkcí, protože jejich přínos je nižší než ty vynaložené prostředky. Takové perfekcionalistické „vyvíjení za hranicí rentability“ lze přirovnat k pozlacování kuchyňského nože – je to zbytečné, nepřináší to žádné zásadní vylepšení ani novou funkci a výsledek je jen dražší.

Efekt vnitřní platformy (Inner-platform effect)

Program někdy nabízí takové možnosti přizpůsobení, rozšíření, doplnění, upravení a nastavení, že se stává sám vývojářskou platformou. Jako příklad lze použít známý bonmot: „EMACS je skvělý operační systém, kterému chybí jen použitelný textový editor“.

Nafouknuté rozhraní (Interface bloat)

Navrhněte rozhraní tak mocné a schopné, že bude extrémně složité ho implementovat.

BaseBean

Tento antipattern popisuje situaci, kdy potřebnou funkci z pomocné třídy dědíme, místo toho, abychom ji na tuto třídu delegovali.

Kruhová závislost (Circular dependency)

Mějme třídu A, která je závislá na třídách B a C. Třída C je závislá na třídě D, která je závislá na třídách B a E, a třída E je závislá na třídě A. Nebo třídu P, která závisí na třídě Q, která závisí na třídě P. V extrémním případě pak „rekurze: viz rekurze“.

Božský objekt (God object)

Už jsme na něj narazili výš, v části o zapáchajícím kódu. Božský objekt vznikne sloučením velkého množství (leckdy nesouvisejících) funkcí do jednoho místa.

Objektové orgie (Object orgy)

Stav, kdy vývojář rezignuje na zapouzdření objektů a všichni tak mají neomezený přístup ke všem vnitřním hodnotám a metodám.

Poltergeist

Poltergeist je mysticky vznikající a zase mizící objekt s krátkou životností. Typicky vznikne, zavolá nějakou funkci, a zase zmizí. Často bývá plodem programátorova předjímání, že tam někde bude někdy v budoucnu něco složitějšího, a ono tam nakonec nic složitějšího není, ale zbytečný mezikrok tam straší dál.

Sequential coupling

Třída, která vyžaduje, aby její metody byly volány v přesně daném pořadí (a to nikoli z logiky věci, ale kvůli implementaci).

Problém joja (Yo-yo problem)

Tento problém je patrný v situaci, kdy se programátor snaží pochopit závislosti tříd a dívá se na jejich graf. Když mu pohled létá nahoru a dolů, jako kdyby sledoval jojo, je to příznak, že struktura trpí tímto antipatternem (nebo že dokumentaci tvořil sadista, co chce ostatním znepříjemnit pochopení problému). Často se vyskytuje při extrémním „rozdrobení“ struktury na malé kousky, které jsou pospojovány zcela zběsilým způsobem.

Akce na dálku (Action at a distance)

Nečekaná interakce mezi velmi vzdálenými částmi systému. Třeba systém, kde si TCP/IP stack volá pro výpočet čísla sekvence ovladač tiskárny. 

Slepá víra (Blind faith)

Slepou vírou se proviní každý, kdo:

  • spoléhá na to, že chybu opravil správně,
  • spoléhá na to, že funkce vrátí správnou hodnotu,

aniž by si to otestoval. Bude potrestán prapodivnými chybami, které se náhodně projevují a nelze je vystopovat.

Kotva (Boat anchor)

Po delším vývoji najdete v systému části kódu, které už nikdo nepoužívá, ale přesto tam jsou. To jsou právě takové kotvy.

Kargokultické programování (Cargo cult programming)

Programátoři, vyznávající kargo kult, se projevují tím, že mechanicky používají vzory a postupy, aniž by opravdu chápali, proč je používají. A týká se to nejen programátorů…

Skrývání chyb (Error hiding)

Někteří vývojáři vyznávají princip „chyba je selhání vývojáře“. Někdy takový princip vyznává vedoucí týmu. Logickým protihmatem je tedy všechny výjimky odchytit, nevypsat nic a tvářit se, že chyby nejsou. A po pravdě řečeno – vypsat chybové hlášení „Došlo k chybě, ouha“ je v zásadě totéž jako nevypsat nic.

Loop-switch sequence

Představte si, že máte v kódu vykonat určitou posloupnost činností. Pokud chcete využít tento antipattern, udělejte si smyčku FOR s proměnnou, řekněme, i, do těla smyčky dejte switch podle této proměnné a pro každou hodnotu nadefinujte jednu činnost. Úspěch zaručen!

Magická čísla (Magic numbers)

a = n ^ 0.15915494309189533576888376337251  – prosím? Nechť zvedne ruku každý, kdo na první pohled pochopil, že to číslo je 1/(2*PI)… Pokud už nějaké takové číslo potřebujete, vložte ho jako pojmenovanou konstantu a vysvětlete význam.

Copy and paste programming

Programování metodou copy-paste porušuje hned několik zásad správného programování. Zamyslete se, jestli by nešlo nahradit zkopírovaný (a pozměněný) kód nějakým obecným řešením.

Zlaté kladivo (Golden hammer) a stříbrná kulka (Silver Bullet)

Oblíbený postup, u něhož věříme, že je vždy použitelný, je takové zlaté kladivo. Oblíbený postup, u kterého věříme, že vyřeší všechny možné problémy, je stříbrná kulka. Obojí je většinou iluze.

Faktor nepravděpodobnosti (Improbability factor)

V systému je známá, i když vzácná chyba, ale místo toho, abychom s ní počítali a ošetřili ji v kódu, tak se spoléháme na to, že zrovna u nás nenastane. Proč si přidělávat práci, že?

Programování metodou pokus-omyl (Programming by permutation, „programming by accident“)

Cyklus změna – test – změna – test…, aniž bychom věděli, co máme změnit a proč, ale spíš naslepo střílíme a čekáme, že to jednou začne fungovat.

Vynalézání kola (Reinventing the wheel)

Existuje přijatelné a odpovídající obecné řešení problému, ale my si přesto zvolíme cestu psaní vlastního kódu s bonusovou možností nasekat stejné chyby, jaké udělali tvůrci toho řešení, a přidat i pár nových.

Vynalézání hranatého kola (Reinventing the square wheel)

Existuje přijatelné a odpovídající obecné řešení problému, ale my si přesto zvolíme řešení na míru, které bude mnohem horší.

Projektové antipatterny

Pochod smrti (Death march)

Všichni vědí, že projekt skončí katastroficky, ale skrývají skutečný stav věcí, aby se vyhnuli zastavení a zrušení celého projektu. Někdy se to podaří utajovat a celý projekt uměle udržovat při životě až do chvíle, kdy přijde Den D. Jiná definice pochodu smrti říká, že jde o situaci, kdy jsou vývojáři nuceni pracovat přesčas a o víkendech, i když je každému jasné, že termín dokončení je naprosto nesmyslný a nelze to stihnout, ani kdyby měl den 36 hodin.

Groupthink

Termín z psychologie, popisuje situaci, kdy se skupina lidí uzavře před pohledem zvenčí a navzájem se ujišťují, že jejich pohled na věc či zvolený postup je správný. Též „nemoc výborů“ a „problém komisí“.

Analysis paralysis

Tak dlouho se vypracovávají analýzy, zprávy, rozbory a posudky, až už není potřeba nic programovat. Důsledným analyzováním všeho a neustálým svoláváním porad lze zaměstnat hned několik týmů na dlouhé měsíce, během nichž budou všichni pracovat, aniž by vytvořili cokoli funkčního.

Navrženo komisí (Design by committee)

Návrh potřebuje jednotnou vizi. V situaci, kdy do návrhu mluví každý a každý považuje svůj pohled za stejně důležitý jako pohled ostatních, vznikne nekoncepční zmetek.

Komise rozhodla (Escalation of commitment)

…a pak se ukáže, že její rozhodnutí je špatné. Ovšem nikdo ho už není schopen odvolat, a tak se dál pokračuje špatným směrem.

Morální hazard (Moral hazard)

Popis tohoto antipatternu je všeříkající: o věcech rozhoduje člověk, který nikdy nepocítí následky svého rozhodnutí. 

Houbový management (Mushroom management)

Zaměstnanci jsou v prostředí připomínajícím pěstírnu hub: udržováni v temnotě, obklopeni hnojem, a jakmile vystrčí hlavu, tak jsou odříznuti a odstraněni. Tato obrazná definice popisuje situaci, kdy management cosi rozhoduje, ale zaměstnanci nedostávají pořádné instrukce, pokyny si často protiřečí, všechno je tajné, nikdo do ničeho pořádně nemůže mluvit, nikdo neví, kdo o věcech vlastně rozhoduje…

A mnohé další…

Antipatternů je mnohem víc, vybrali jsme jen některé z nich. Zájemci najdou víc v literatuře. Nezbývá než popřát všem takovou práci, kde nebudou muset žádný z nich používat.

Tento text čerpá z popisů antipatternů na Wikipedii, a vychází proto pod licencí CC-BY-SA.

Komentáře

Subscribe
Upozornit na
guest
93 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Blaazen

Pěkný článek, člověk se v něm občas najde – to (ne)klidně přiznám. Jen si musím dát pozor na antipatternofobii – stav, kdy se člověk tak bojí, že jeho kód bude odpovídat nějakému antipatternu, že kvůli tomu píše pomalu a pořád se kontroluje. To by byl vlastně nový antipattern.
Pro jistotu si ale dám článek do záložek. :-)

Ondřej Mirtes

Zkušenný/dobrý programátor voňavý kód píše automaticky, ne? :) A pokud je otestovaný, není problém ho refaktorovat.

kraken

Jak se bránit „Poltergeistu“, pokud v době jeho vytváření předpokládám, že časem funkčnost přidám (a tedy vytvořím takový objekt)?

jehovista

Jestli casem znamena za hodinu, tak to asi takovy problem nebude. Jestli casem znamena mozna v pristi verzi SW, tak je asi lepsi obejit se bez nej.

Hans

Nevytvářet objekty do zásoby.

X

Joshua Bloch: „When in doubt, leave it out.“ – prostě situace „někdy se tady ta složitost bude hodit“ řešit tím, že tam tu složitost přidám až teprve to skutečně bude potřeba. Ne preventivně dříve!

belzebub

Popisovana temata povazuji za extremne dulezita, takze na jednu stranu jsem rad ze se o nich pise – na stranu druhou mi pride celkem ubohy opisovat wikipedii a vydavat to za clanek..

biq

preco, mne sa to na wiki hladat nechce, tu to mam pekne pokope precitane za par minut. Diki autorovi

belzebub

„hledat na wiki“?!?! to opravdu myslite vazne? zadat do vyhledavaciho okenka „wiki antipatterns“ je otazkou mene nez 5 sekund..

..nehlede na to ze pokud se o tom chci neco dozvedet, stejne musim rozkliknout odkazy z clanku – a ty me privedou hadejte kam ?
..no ale vzhledem k tomu, ze se vam to asi nebude chtit hledat, to prozradim: na popisy antipatternu na wikipedii :)

Ivan Nový

A kdy naposledy vás něco podobného napadlo do wikipedie zadat?

boban

Přesně. Je dobré, že na to autor upozornil, jinak by to nikoho nenapadlo hledat..

kronta

Souhlasím. Autor se zcela jasně netají vazbou na wiki a každá osvěta dobrá.

Musíme o těch problémech mluvit, jinak se nám těmato hnusama bude kód plíživě zanášet.

Myslím, že nestačí propagovat, jak by se to mělo dělat. Strašně důležité je pořád si opakovat, na co si dát pozor.

koudy

Zrovna vcera, protoze tu(nebo abclinuxu?) byl nejaky clanek o programovani a presne tuhle stranku na wiki jsem vcera cetl, ale je pravda ze jsem nevedel, ze neco takoveho je popsane. Uz nekolikrat jsem se s antipatterny setkal a ani jsem to nevedel. :)
Clovek se snazi nedelat tyto veci a je dobre vedet, ze „tudy ne pratele!“ :)

???

Tak si ale uvědom, kolik článků je na internetu skutečně původních, tzn. takových že autor publikuje výhradně své myšlenky a občas se na něco odkáže. Tenhle článek je shrnutí toho co je na wikipedii v Češtině. A kdyby článek nebyl, většina lidí by o antipatternech nic nezjišťovala, někteří by ani dosud nevěděli co to je. Myslím že takovéto články mají smysl, je to jako slevo-mánie. Napadlo by tě normálně zajít na Křižíkovu fontánu do Prahy, mě spíš ne, kdybych k tomu neměl jiný podnět, ale když to máš na slevo-serveru, jako nabídku a ještě k tomu se slevou, tak se někdo chytne.

uf

Je dobře, že se o tom píše. Já jsem třeba o některých nevěděl, že jsou pojmenované.

Ale fakt nevím, proč píše o mýc programech …

Radek

Akorát že na Wikipedii je před spoustou těch článků několik varování (např. neutralita článku je zpochybněna, neuvádí žádné zdroje, apod.), viz http://en.wikipedia.org/wiki/BaseBean
Prostě čtenář je varován, že se tam můžou tvrdit dost pochybné věci. Naproti tomu Zdroják nám to předkládá jako fakt. Ano viděl jsem v perexu „nadsázka povolena“. Ale vidíte to sami – jakmile někdo něco napíše, byť na místo, kam může psát každý, spousta lidí tomu začne slepě věřit :-)

wellczech

A proto máme pod články diskuze, abychom se o tématu dále pobavili. A ještě lepší by bylo po diskuzi vyvodit závěry, shrnout je do nového článku nebo diplomové práce a upravit wiki včetně odkazů :)

pht

Ono je to celkem jedno odkud je to opsane. Z takovehleho clanecku ani z clanku na wiki z vas mistr nebude. Na to je potreba precist toho trochu vic a hlavne to zkouset v praxi. Doporucuju napr. knihu „refactoring to patterns“, z toho clovek ziska docela dobry nahled.

tdvorak

Nebude z nikoho mistr, ale uvedomi si ze nejaky problemy jsou. A dost mozna si hned vybavi nejakej svuj kod. A to by mohlo stacit k tomu, aby to cloveka motivovalo dal to resit a opravit. Jiste ze ucelena publikace to vysvetli lip, ale tenhle clanek si clovek prolitne o poledni pauze a neco mu to da.

snehuliak

Race condition sa nehodila?
V buducnosti by bolo dobre uviest aj zdroje na tom zrojaku…

cpt. Rumpill

Uvést zdroje? Jako napsat třeba „Tento text čerpá z popisů antipatternů na Wikipedii, a vychází proto pod licencí CC-BY-SA“? A zkusil ses podívat na konec textu?

JScore

Dnes ráno jsem přečetl a ani sem netušil jak rychle se s tímto setkám :D

http://demo.online-kurz.net/scripts/jscalendar/calendar.js
řádek 1595

Fandik Hacker

Myslim, ze v tomto pripade se uplne nejedna o antipattern loop-switch sequence.
Jde tu spise o velmi prehlednou a udrzovatelnou konstrukci parsovaci funkce.

Autor se urcite poucil u knihovni funkce printf(...) a jejich derivatu, kterou programatorsky svet zna cca od roku 1970 a jeji implementaci muzete v jazyce C nalezt napriklad v <stdio.h>.

JScore

no přiznám se tak jsem kód do hloubky nezkoumal. ale opravdu může mít daná konstrukce opodstatnění. Napadá mě například počítání znaků, čísel a speciálních znaků v řetězci. Vlastně algoritmus pro frekvenční analýzu.

mmad

Její jednoduchá verze:
<?php
$retezec_ptakovin = „neco neco blbost necojineho ptakovina“;
$res = array();
for ($i=0; $i<256; $i++) {
switch ($i) {
case 1:
$d = „neco“
break;
case 7:
$d = „necojineho“
break;
case 44:
$d = „blbosti“
break;
/* … */
default:
$d = „“;
}
if (!$res[$d]) $res[$d] = 0;
$res[$d] += substr_count($re­tezec_ptakovin, $d);
}
print_r($res);
?>
Verze bez switche…
<?php
$retezec_ptakovin = „neco neco blbost necojineho ptakovina“;
$hled = array(„neco“,“ne­cojineho“,“blbos­t“);
$res = array();
foreach ($hled as $i => $v) {
if (!$res[$v]) $res[$v] = 0;
$res[$v] += substr_count($re­tezec_ptakovin, $v);
}
print_r($res);
?>
A jednotlive znaky – kdy ma for vyznam…
<?php
$retezec_ptakovin = „neco neco blbost necojineho ptakovina“;
$res = array();
for ($i=0; $i<256; $i++) {
$c = char($i);
if (!$res[$c]) $res[$c] = 0;
$res[$c] += substr_count($re­tezec_ptakovin, $c);
}
print_r($res);
?>

phr

Ano, přibližně tohle jsem chtěl napsat. Taková konstrukce se někdy veeelmi hodí, protože dokáže dobře zpřehlednit co ten kód vlastně dělá.

Jirka

Mezi antipatternem uvedeným na Wikipedii a Vámi uvedeném javascriptovém kódu je obrovský rozdíl. V prvním případě autor ví, že první parsovaná hodnota je „key“, druhá „value“ a pak následují parametry. V druhém případě je pořadí volání parsovacích funkcí libovolné.

maryo

Komu se clanek nelibi, nepochybne jeho kod spada do jednoho z bodu a jen si to nechce priznat :)…

Vebloud

Mě se článek extrémě líbí, protože právě dělám na projekty, který se tím hemží. Takže jsem nasadil PHP Mass detector, Copy Paste detector a snažíme se vylepšit co se dá. Jenže…

Branik

Copy Paste detector :) to je dobrej napad to je nejakej tool ? da se to pouzit na c++ ?

Michal Augustýn

V TeamCity je třeba vestavěnej Duplicates Finder (pro Javu a .NET).

Infragile

Doporucuju Sonar! http://www.sonarsource.org/ nejlepsi nastroj tohoto razu co znam.

Inkvizitor

ale nabízená definice „nekompetentního vývojáře“ mi přijde pojatá dost nešťastně. Samozřejmě, kód by měl být vždy psaný tak, aby byl co nejpochopitelnější, ale primární problém přece není v tom, že někdo použije „málo známou vlastnost jazyka“. V prvé řadě jde o to, aby v kódu bylo co nejméně závislostí na okolí, jednoznačné identifikátory, rozumné komentáře (hlavně u popisu funkcí/metod). Používání „obskurních konstrukcí“ by samozřejmě nemělo být samoúčelné, ale často vede k daleko kratšímu nebo rychlejšímu kódu. A ať se na mě nikdo nezlobí, programátor, který nerozumí svému vlastnímu programovacímu jazyku nebo mu dělá problém konstrukci najít někde v dokumentaci nebo na Internetu, by se měl nad sebou minimálně zamyslet.

Opravdový odborník :-)

+1  

Inkvizitor

Obecně naprostý souhlas (až na to, že hacky a „obskurní konstrukce“ bych rozhodně nesrovnával), ale chtělo by to asi pár konkrétních případů. Asi hodně záleží na jazyku; osobně mě nenapadá třeba v Pythonu (který mě z větší části živí) žádnou konstrukci (když vynechám staré třídy) konstrukce, kterou by si programátor v našem týmu mohl dovolit ignorovat a čekat, že ho v tom nechám. Na druhou stranu jsem velice přísný, co se týče přehlednosti a dokumentace kódu. Chceš použít nějakou cool feature? OK, ale ať už používáš cokoliv, chci, aby kódu pokud možno porozuměl i ten, kdo nezná kontext a zdroják vidí poprvé. Ono to většinou opravdu jde.

Aichi

Mohu se zeptat v jake kapitole popisuje nekompetentniho vyvojare? Rad bych si to precetl :)

Martin Soušek

Tohle je sice všechno krásné, ale být dobrý programátor se nedá naučit. Buď to máte v krvi, anebo nemáte.

Řadu těch antipatternů lidé používají především proto, že to lépe neumí a i kdybychom jim v tom tisíckrát hlavu vymáchali, tak to líp nikdy nesvedou.

Branik

s tim nemohu souhlasit programovani se da naucit . Anti paterny jsou vysledkem lenosti ! Typicky magicke konstanty.

.

Jako gramatika, že?

ahmul

Morální hazard… to je antipattern z naší politické sféry, ne?:)

asdasd

Ovšem v kombinaci s pokročilým houbovým managementem.

Ondřej Mirtes

Ke článku bych rád doplnil další antipatterny.

Nejzákeřnější jsou ty, které jsou prezentovány jako návrhové vzory – tedy osvědčená „nejlepší“ řešení, které chytře řeší určený problém.

Na školách se vesele vyučuje např. Singleton, který je ovšem příšernou ukázkou antipatternu. Jedna instance objektu v aplikaci se dá zařídit i jinak, než že udělám privátní konstruktor a globální statickou metodu getInstance(). Stačí se domluvit, že daný objekt nebudu nikde instanciovat, ale zavolám na něm new jen jednou a budu si ho všude předávat. Takové řešení je testovatelné a nezblázním se, když takové objekty najednou potřebuju dva.

Dalším takovým je Service Locator, kterým se zabýval díl zdejšího seriálu o Dependency Injection.

Dalšími „code smelly“ jsou globální proměnné, statické atributy tříd, „statické třídy“ – tedy třída sloužící jen jako jmenný prostor pro funkce, které nemají žádnou návaznost na instanci objektu.

Nedostatečná dekompozice objektů – pokud budu mít systém s jemnější granularitou, jeho části se pak snadněji znovupoužívají. Také by se neměla využívat dědičnost tříd tam, kam nepatří.

Aleš Roubíček nedávno prohlásil, že mutable objekty jsou také anti-pattern, byl bych rád, kdyby tuto myšlenku rozvedl :)

Z manažerských anti-patternů se mi líbí Brooksův zákon, který říká, že přidáním dalších programátorů do zpožděného projektu narůstá jeho zpoždění :) A deadliny jsou vlastně taky anti-pattern :)

Opravdový odborník :-)

1) Singleton: ten se vyučuje v první řadě proto, aby studenti na jednoduchém příkladu pochopili, co to návrhový vzor je. Na lepších školách zároveň řeknou, že to má i svoje úskalí a není moc dobré ho používat. Ale jako ilustrační školní příklad na pochopení smyslu návrhových vzorů je dobrý.

2) Service Locator: záleží na kontextu, s čím to srovnáváte — ve srovnání s zpraseným kódem, kde jsou stejné věci na spoustě míst, je SL spása a krok dopředu. Samozřejmě to lze dělat lépe. A opět, jako ilustrační příklad dobré.

3) „statické třídy“ jsou v pořádku, jsou to normální knihovny funkcí — a ano, třída v takovém případě plní pouzi jmenného prostoru, ale pokud chceme používat funkce (a ne jen metody) v jazyce, který funkce formálně nemá, tak je knihovní třída jasná volba.

blizz

„Dalšími „code smelly“ jsou globální proměnné, statické atributy tříd, „statické třídy“ – tedy třída sloužící jen jako jmenný prostor pro funkce, které nemají žádnou návaznost na instanci objektu.“

To neni žiadny code smell, statická trieda = modul.

citujem: „Zapáchající kód vznikne i přílišným lpěním na dogmatech – například použitím složitého návrhového vzoru tam, kde by stačilo jednoduché a přímočaré řešení.“

asdasd

+1 Přesně tahle věta se mi hned vybavila. Bohužel to je velice rozšířená úchylka a s postiženými se většinou nedá diskutovat.

Aleš Roubíček

Ovšem modul musí mít všechny znaky modulu a jeho fukce musejí být opravdovými funkcemi. tj. žádný sdílený stav, žádné vedlejší efekty. Čož bývá velmi zřídka k vidění, a proto to všeobecné lpění na tom, že jde o zlo.

Radek Miček

Čož bývá velmi zřídka k vidění

Proč si to myslíte?

Aleš Roubíček

Zkušenosti, za ta léta jsem viděl soustu code base a viděl spoustu takových statických API se sdíleným stavem a side effecty, že si musím nalít dalšího panáka, když si na to vzpomenu…

asdasd

S první větou souhlasím. Ovšem to, že někdo něco neumí použít z toho ještě nedělá špatný postup, ne?

Aleš Roubíček

Pokud není blbu vzdorný a umožňuje snadno dělat prasárničky, pak to z něj špatný postup dělá.

asdasd

Aha. A co říkáte třeba na jazyky, ve kterých jsou přístupné všechny objekty skrz na skrz? Ty by se asi měly přinejmenším zakázat, protože o nějaké „blbuvzdornosti“ nemůže být ani řeč, přitom v nich vznikají skvěle navržené programy – není někde chyba? Chorobná preventivní opatrnost by klidně mohl být další antipattern.

Michal Augustýn

V C# třeba považuju prakticky za jediné moduly s funkcemi statické třídy s extenzníma metodama.

František Kučera

A přesně k tomu jsou ty návrhové vzory — knihovní třída má mít soukromý konstruktor a nikde se pak její instance nevytváří, sdílený stav ani vedlejší efekty nemá a jediné co obsahuje jsou statické metody (ve skutečnosti ony opravdové funkce) a třída je pouze modulem, jmenným prostorem.

ondra.novacisko.cz

Moc zrovna nesouhlasím s tím, co tvrdíte o singletonech. Možná jde jen o použití. Singleton samozřejmě není speciální třída, ale speciální použití a pokud jde o singleton sedící za rozhraním, na kterém je metoda getInstance(), tak samozřejmě u mě má tato metoda ještě sestřičku, setInstance(), kterou mohu dosadit vlastní implementaci. Singletony mají rozhodně své opodstatnění.

To samé se Service Locátory, třeba například v mé knihovně mám vlastní implementace funkcí, které na základě jména otevřou někde stream, což může být soubor, ale i TCP spojení. Je tam rozhraní se singletonem, za ním sedí service locátor, který na základě názvu vydá patřičný objekt, který následně je použit k uspokojení požadavku. Přijde mi to jako nejčiščí řešení, protože žádná část programu následně nemusí řešit, koho se mají doptat na konkrétní implementaci služby, a všechny části jsou schopné pracovat i se službami, které v době návrhu neexistovali. Maximální flexibilita.

Aleš Roubíček

A proč raději nepoužít vzor Strategie?

Michal Augustýn

Co řeší ta další metoda setInstance()? A jak se to bude chovat ve vícevláknovém prostředí (třeba webový server) ?
Singleton je prostě zlo – jediné použití, kde bych ho toleroval, je tam, kde není technicky možné injectovat závislosti (a v tom případě je oním Singletonem Service Locator).

ondra.novacisko.cz

Co to je za zbytecnou otazku? To je snad jasne ne? Tenhle typ singletonu je vetsinou, nebo spis vzdycky urcen pro zajisteni sluzeb s vnejsim prostredi, ktere je vzdy jedno. Zpravidla vetsina aplikaci bezi napriklad v ramci jednoho operacniho systemu soucasne, ktery ma zpravidla jeden filesystem (i kdyz jich ma vic, ale aplikaci poskytuje jedno rozhrani) atd. Podle vaseho dotazu hadam, ze jste tak uplne nepochopil, k cemu to je.

A proc chci mit moznost to globalne zmenit? Treba proto, ze chci rozsirit moznosti vnejsiho prostredi, nebo emulovat funkce vnejsiho prostredi, ktere to prostredi genericky nenabizi

Michal Augustýn

To není zbytečná otázka. Takže znovu – co řeší ta metoda setInstance() ? Co dělá je jasné, ale já se ptám, co z architektonického hlediska řeší. IMHO jen zavádí další smell a případnou race condition, kdyby se nedejbože nějaká třída rozhodla tu metodu zavolat.

Třída by měla jasně deklarovat své závislosti. V C++, C#, Javě apod. by se tedy měly všechny závislosti předávat přes parametry konstruktoru (příp. přes property setter injection). Použití singletonu vede k tomu, že třída používá něco, co v konstruktoru nedeklaruje.

Pokud je například to zmiňované API operačního systému pro práci s file systemem poskytováno jako singleton, tak s tím nic nenaděláme, a v takovém případě je potřeba se této neprůhledné závislosti zbavit na vhodné úrovni.
Např. jestli by měla třída FileLogger používat API pro komunikaci s file systemem napřímo nebo jestli by měla používat nějakou non-singleton abstrakci, to už je do jisté míry otázka vkusu. Já osobně bych třeba použil to API napřímo, protože třída vyjadřuje do jisté míry tuto závislost svým jménem.

To jsou vynucené singletony, se kterými nemůžeme nic moc dělat. Ale v žádném případě bych nezaváděl vlastné singleton – je to prostě špatně.
Třídy pak jasně nedeklarují své závislosti a třída, která singleton používá, může být netestovatelná (např. když chceme v jednom kontextu spustit více testů paralelně a každá třída potřebuje singleton jinak namockovaný).

ondra.novacisko.cz

Proto tvrdim, ze to moc nechapete. V jazycich zalozenych na tridach a instancich mate ke kazde instanci adekvatni automaticky vytvoreny singleton, jak vy tvrdite asi vynuceny. Ano, je to trida, s tridnimi funkcemi a promennymi, s jednou a neprepsatelnou metodou new.

Pokud to nahradim tovarnimi objekty, vzdycky chte nechte narazime na problem s tim, ze potrebujete aby vam nekdo vyrobil instanci tovarny, nebo instanci tovarny tovaren. Nakonec skoncite u singletonu. Ze ne? No minimalne na operator new, coz je vlastne singleton.

A co delat setInstance? No to co u new nikdy neudelate, mate moznost zmenit superglobalni tovarnu tovaren, treba tim, ze dodate vlastni instanci, ktera implementuje nejaka vylepseni. Ja neobhajuju objekty navrzene jako singletony. At jsou navrzene tak aby si nekdo tu superglobalni tovarnu mohl predavat v promenne a tim se vyhne tem vasim race condition… a zmene instance tovarny za behu. Ona setInstance by se taky mela volat tak jednou za cely beh, na zacatku treba jako konfigurace knihovny, nebo pri vyznamnych udalostech… prirovnal bych to treba udalosti zmeny runlevelu v linuxu

Michal Augustýn

> Ano, je to trida, s tridnimi funkcemi a promennymi, s jednou a neprepsatelnou metodou new.

Jak už psal jiný Ondřej, statické položky tříd a statické třídy jsou taky smell. První jmenované jsou totiž prakticky globální proměnné a druhé vytváří singleton. Proto by se neměly používat.
A metoda new se volá jen v kompozičním rootu – jak říkal Miško Hevery na jedné ze svých přednášek, tak jedním ze znaků špatně testovatelného kódu bývá přítomnost volání new někde jinde.

> Pokud to nahradim tovarnimi objekty, vzdycky chte nechte narazime na problem s tim, ze potrebujete aby vam nekdo vyrobil instanci tovarny, nebo instanci tovarny tovaren.

Ano – tomu se říká kompoziční root aneb konfigurace aplikace.

> A co delat setInstance? No to co u new nikdy neudelate, mate moznost zmenit superglobalni tovarnu tovaren, treba tim, ze dodate vlastni instanci, ktera implementuje nejaka vylepseni.

Pokud chci změnit superglobalni tovarnu tovaren, udělám to na úrovni konfigurace aplikace. Pokud by to měl dělat někdo níže odspodu, popíralo by to IoC.

> Ona setInstance by se taky mela volat tak jednou za cely beh, na zacatku treba jako konfigurace knihovny, nebo pri vyznamnych udalostech…

Než nějaké „by se mela volat“ raději navrhnu aplikaci tak, aby bylo nesnadné dostat ji do nějakého špatného stavu.

ondra.novacisko.cz

Nojo, jenze cokoliv se nachazi v rootu je vlastne singleton. Takze je ekvivalentni globalni deklaraci. Jedina vyhoda mit jeden root a v nem singletony je v tom, ze si teoreticky mohu vytvorit vice rootu.

Pak je otazkou, zda zbytecne netvorime kotvy nebo poltergaisty. Ono to, „co kdyby nahodou“ pak vede k tomu ze na jednom miste obchazime pasti, ktere jsme si jinde vytvorili

Aleš Roubíček

Užití singletonu je vlastně speciální případ service locatoru. Navíc je to lifestyle. Pokud se volání getInstance() vyskytuje více než právě jednou jde o smell. Ve spojení s IoC je implementace vzoru singleton ok.

xxx

Naopak, singleton je absolutne nekompatibilni s IoC. V tom pripade jste totiz omezovan na jednu konkretni implementaci service locatoru (za predpokladu, ze nemate neco jako setInstance(), coz ale pak neni pravy singleton). Je to pak prakticky to same, jako by jste service locator nepouzili vubec a instance si delali „na miste“.

Aleš Roubíček

No chce to asi ještě trochu představivosti praxe. Ono vám totiž vůbec nic nebrání v tom, aby singleton implementoval rozhraní, volání getInstance() bylo provedeno právě jednou v composition rootu aplikace a všude byla tato instance injektována (klidně pomocí poor man’s DI). V takovém případě máme čisté IoC, s troufám si tvrdit, že nejde o smradlavé užití Singletonu.

Pro lepší představu připojuji ukázku:

class FooSingleton : IFoo {
    static IFoo instance = new FooSingleton();
    private FooSingleton() {}
    public static IFoo Instance { get { return instance; } }
}

class Bar {
    public Bar(IFoo foo) {}
}

class Program {
  static void Main() {
    var bar = new Bar(FooSingleton.Instance);
  }
} 
Branik

Singletony jsou krasnej priklad paternu, kterej se velice rychle muze zvrhnout v antipattern . Nekolik singletonu propojenejch jako jojo poruznu rozhazenejma volanima a callbackama a clovek se pak jen divi co to vzniklo za spiders nest .

phr

Globální proměnné jsou softwarovou implementací Archimédova principu „Dejte mi pevný bod a pohnu Zemí“. A jako takové mohou mít smysl, ale samozřejmě nesmí se to s nimi přehánět nebo je používat zbytečně.

Tonda

Singleton se asi z nějakého důvodu jmenuje singleton a svoji fukci plní dokonale. Používá se tam kde potřebuješ mít jednu instanci a ne dvě nebo tři. To že v průběhu implementace zjistíš, že najednou potřebuješ instance dvě není problémem singletonu, ale tvůj, protože jsi tu aplikaci blbě navrhnul. Chtěl bych vidět jak bys v týmu dvaceti vývojářů všem vysvětloval co si kam mají předávat protože to není singleton, ale instance má být jenom jedna :-D

Ondřej Mirtes

Prosím, abys zamířil do zdejšího seriálu o Dependency Injection.

jos
class foo
{
  function __construct()
  {
    if(self::$counter) {
      throw new LogicException(
        'použij existující instanci pičo'
      );
    }
    ++self::$counter;
  }
  private static $counter = 0;
}
Nox

Je ovšem rozdíl mezi „používá se jen jedna“ a „je absolutně nemyslitelné, aby se v aplikaci objevila druhá instance“. Druhá verze je singleton (a nic jiného singleton není) a osobně si nedovedu představit případ, kdy by bylo nutné něco takového vynucovat
(a navíc se stejně často odhalí že instancí je třeba víc http://phpfashion.com/singleton-sofie-s)

Větu o týmu neberu, pokud má tým takové komunikační a programátorské problémy, tak nevím jak by mohl vůbec fungovat

vonRibbentrop

Ono se ale těžko programuje, když se člověk nemůže spoléhnout na to, že funkce vrátí správnou hodnotu.

Michal Wiglasz

„aniž by si to otestoval“

Po otestování se už spolehnout může, hm?

Sten

Tipuji to na chybu v komunikaci mezi Wikipedií, autorem článku a publikem :-). Funkce nemusí vrátit správnou hodnotu, protože může vrátit chybový stav a to i postranním kanálem (třeba readdir_r), což při neodchycení často znamená katastrofu.

utx

Už párkrát jsem si říkal, že GTK+ nezveřejňuje věci, které programátoři potřebují, a musí složitě reimplementovat. To jsem ještě nevěděl, že se tomu říká Obrácení abstrakce.
https://bugzilla.gnome.org/show_bug.cgi?id=554229#c4
http://developer.pidgin.im/ticket/14245

Při ladění jsem už několikrát narazil na Poltergeist. U jednoho kuriózního nebyla kvůli chybě ve vyšší vrstvě nikdy volána velká část kódu ve vrstvě nižší, aniž si toho kdokoliv všiml (viz Skrývání chyb). Až jednoho dne jeden člověk našel v nikdy nevolaném kódu bezpečnostní chybu…

A sám se přiznávám k tomu, že jsem párkrát použil Programování metodou pokus-omyl dokonce v kombinaci s metodou Magická čísla.

ondra.novacisko.cz

Obrácená abstrakce – od jisté doby nepoužívám private:, pouze protected:, která chrání atributy z venku, ale umožňuje přístup zevnitř, takže funkce, které zůstávají neveřejné lze případně potřeby volat poděděním objektu. Nevýhodou je, že za správné použití zodpovídá potomek a s tím souvisí i problémy související třeba s nečekaným updatem předka například v další verzi. Nicméně, pořád to má tu výhodu, že při náhlé změně se musí opravit jedno místo v programu (potomka), než kdyby různé části programu přistupovali k atributům deklarovaným public.

Private je moc restriktivní, a kolikrát proklínám programátory, že do toho zabalí deklarace, které by se mohly venku hodit.

Ondřej Mirtes

Třída by měla být na dědění uzpůsobená a měla by k tomu poskytovat prostředky – např. protected metody, které umožňují překrytí. protected atributy umožňují zasahování do implementace i na místech, kde to není vhodné.

ondra.novacisko.cz

ano,to je taky antipattern, lpeni na dogmatech.Proboha proc?

ondra.novacisko.cz

Bohuzel, kristalove koule jsou prakticky nesehnatelne. Takze vymyslenim mist, kde se bude trida v budoucnu rozsirovat je podle me zbytecna ztrata casu a vytvari akorat zbytecne kotvy

uf

Tendence by měla být spíš opačná: Schovat toho co nejvíc a v případě nutnosti lze restrikce změkčit.

Já se nepovažuji za dobrého programátora, ale nesnáším protected atributy. Je to zdroj zla. Dokonce ani ve třídě, která je navržená jako (nejlépe abstraktní) bázová pro dědění. Dnešní IDE vám sice řeknou, odkud proměnná pochází, ale plnit proměnnou, kterou nemám deklarovanou, je magie. O to víc mě mrzí, že je to běžné v JDK.

ondra.novacisko.cz

Protected v jave je neco jineho nez v C++

František Kučera

Vždyť ji deklarovanou máš — akorát v předkovi.

uf

Deklarovaná je, a to záměrně protected v předkovi. Ale (mluvím tedy o Javě) porušuje zapoudření.

Aminux

„EMACS je skvělý operační systém, kterému chybí jen použitelný textový editor“
Ta to by chtělo implementovat Vim do EMACS třeba jako plugin.

Sten
verajo

Diky za tento clanek. Ja myslim, ze jestli se v nem nekdo aspon v necem castecne nenasel, tak nikdy neprogramoval, protoze vsechny tyhle „antipatterns“ jsou dusledkem bezne praxe.

rooobertek

vyzerá to, že niekto písal o firme, v ktorem pracujem :) Tu by ste našli asi všetky antipatterny popísané v článku.

carlo.kokoth

… ale komentář se tak rozrostl, ze jsem si (konečně) založil blog, udělal z toho první zápisek a časem budu přidávat věci které jsem už chtěl dávno napsat.

Nenechte se odradit nazvem blogu / permalinkem (nesnáším politickou korektnost, svět je plný věcí hodných kritiky a servítky si brát nehodlám), samotný zápisek je až překvapivě uhlazený :
http://svetjeplnyblbcu.blog.root.cz/2011/06/27/obskurni_featury_my_ass/

100% Lenin

Ideální kodér píše správný kód ve stylu
try …
try …
try …
catch nic

Na dotaz proč to tak napsal mi odpověděl – správná aplikace nesmí strašit uživatele chybami

a to je vše, drzí přátelé. :D

100% Lenin

:D (už na to nevidím). Myslel jsem“A to je vše, drazí přátelé.“

veselej

Takhle jsem se dlouho nenasmál :-) Největší joke je, jak to naprosto sedí na reálné situace projekty. Člověk trochu zavzpomíná na léta minulá a na některé oblíbené projekty. Super článek!

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.