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

Zdroják » JavaScript » Prasit, či neprasit?

Prasit, či neprasit?

…aneb Lightbox implementovaný na dva způsoby. Ukážu vám dvě implementace notoricky známého widgetu Lightbox. Ta první je maximálně naivní, ta druhá sofistikovaná. Obě jsou postavené nad Google Closure Library, což ale není to podstatné. Podstatné je, jak jsou napsané.

Na Githubu naleznete zdrojové kódy k článku.

Ten první způsob lze nazvat “Co na mysli, to na klávesnici.” Žádné velké přemýšlení, rovnou píšeme kód. Druhý způsob je jiný, vyžaduje přemýšlení dřív, než napíšeme jediný řádek.

Prvním stylem je napsaná většina jQuery pluginů. Ten druhý využívá třídy, dependency injection, dokumentační komentáře, unit testy, a je implementovaný TDD stylem vývoje. Smyslem článku není obhajovat jeden styl vývoje na úkor druhého, naopak! Oba příklady ilustrují oprávněné způsoby vývoje software, a my si ukážeme některé techniky, které je odlišují. Na závěr se zamyslíme, kdy kterému dát přednost.

Co je špatný kód?

Snad každý instinktivně cítí, co je špatný kód. Je to impress.js? Z jednoho úhlu pohledu opravdu ne. Je to perfektní, minimalistická, vylepšená reimplementace core feature prezi.com, která navíc nepotřebuje Flash. Neobsahuje ani žádné významné code smells.

Z jiného úhlu pohledu se ale jedná o tragicky špatný kód. Dovedete si představit, že byste jej použili ve svojí aplikaci? Bez copy&paste a kompletní reimplementace? Stěží. Impress.js je technologické demo, prototyp. Netestovatelné, znovu nepoužitelné, a nejen to.

Ale dost teorie, sem s tím ukázkovým kódem.

Naivní ligthbox

(Ukázkový skript)

To, co vidíte, je základní princip lightboxu.

Click na odkaz s lightbox rel attributem zobrazí view s poloprůhledným pozadím, a přes něj obrázek s ovládacími prvky next, previous, close a title odkazu.

Podívejte se na kód, myslím, že je velmi srozumitelný. Dá se číst odshora dolů jako povídka. Je tedy takový kód v pořádku?

Zkuste se zamyslet, jak by kód vypadal, kdyby se dále rozvíjel ve stejném duchu. Chceme přidat animace. A list malých náhledů všech obrázků ve spodním pruhu. A možná nějaké další informace týkající se obrázku aktuálně vybraného. A možnost obrázek označit. A otočit. A tagnout v něm někoho.

A teď si představme, že chceme mít více verzí samotného lightboxu, jednu pro přihlášeného uživatele, druhou pro nepřihlášeného uživatele. Kolegu ve firmě náš výtvor zaujal, protože korektně zobrazuje fotky i na malých zařízeních (což 95 % lightboxů nezvládá), a chtěl by lehce modifikovaný lightbox pro svůj e-shop. Možností je nespočet, a pokud budeme lightbox rozšiřovat prostým přidáváním metod, záhy se náš rozkošný malý scriptík změní ve velikou kouli bláta, ulpívající na programátorově noze. Co s tím? Na scénu přichází sofistikovaný lightbox.

Sofistikovaný ligthbox

(a opět odkaz na ukázkový kód)

Sofistikovaný lightbox se snaží už od začátku i do tak malého kódu, jakým naivní lightbox je, vnést trochu řádu. Programování není o ničem jiném. Princip „jak psát správně velké aplikace“ je jednoduchý: nepsat velké aplikace. Rozbít velkou třídu do menších, co spolu komunikují. Prostě mít solidní objektový návrh.

Takže znova, a tentokrát začneme testy.

TDD a unit testy

Test driven development. Svatý grál vývoje, vychvalovaný až do nebe, každý ho používá.

Však to znáte: v hlavě si představíte, co by kód měl dělat (tady bude takový a takový formulář), napíšete kód, přepnete do prohlížeče (bavíme se o webu), dáte F5 a hned vidíte výsledek. S uspokojením dáme ALT-TAB, v editoru napíšeme další řádky kódu. A zase ALT-TAB, F5, ALT-TAB, F5… S tím jak aplikace kyne, množství ručních na-oko-testů roste.

Jak je zřejmé, každý testuje. Nedovedu si představit, že by někdo nasadil kód, který by alespoň jednou ručně nevyzkoušel. Problém je v tom “v hlavě” a “ručně”. Nebylo by lepší mentální obrazy raději zatavit do kódu, a místo ručně testovat automaticky? Ano. Ale tohle dělá skutečně málokdo.

Proč se tak málo píšou testy? Důvody jsou dva.

  1. Lidé neumí psát kód tak, aby se dal dobře a rychle testovat.
  2. Lidé si neumí nastavit vývojové prostředí tak, aby je spouštění testů neobtěžovalo.

V textu se soustředím na bod první.

@stevenmak: QOTD: „If you think test-first is expensive, try debug-later“” Even worse, try ‚debug after customer defect report‘ – https://twitter­.com/#!/dmatej/sta­tus/139994293082398721

Jak psát testovatelný kód

Začneme tím, že si představíme z jakých dílků by se lightbox měl skládat, a napíšeme na to test. Pokud se podíváme na naivní implementaci, je zřejmé, že lightbox se skládá z něčeho, co poslouchá bublající click eventy, a na ten správný zobrazí view. Lightbox agreguje anchorClickHandler a faktory metodu, která nám na požádání vytvoří view. Test může vypadat třeba takto:

suite 'este.ui.OOPLightbox', ->

    suite 'OOPLightbox.create', ->
        test 'should create lightbox instance with object graph', ->
            lightbox = OOPLightbox.create()

            lightbox.should.be.instanceof OOPLightbox
            lightbox.anchorClickHandler.should.be.instanceof ooplightbox.AnchorClickHandler
            lightbox.viewFactory.should.be.instanceof Function

https://gist.git­hub.com/1578979

Spustíme test (v některém dalším článku vám ukážu, jak mít testy, co se spouštějí samy). Test neprojde, protože použité třídy a metoda create ještě neexistují. Tak je to správně, nikdy nevěřte testu, který neselhal! Za pozornost stojí, že jsme začali s třídami, a ne vlastní logikou lightboxu. To je také správně, protože nemůžeme přeci začít psát metody, když nemáme třídy, do kterých bychom je psali. To, že jsme začali factory funkcí, ilustruje jeden důležitý aspekt vývoje OOP aplikací, který bývá často nepovšimnut, především u zbastlených aplikací. Míchání logiky stavby aplikace s její business logikou. Lightbox je také aplikace, i když maličká. Nějakým způsobem pospojovat dílky, to je úkol pro factory metodu create. Chceme trochu jiný lightbox? Třeba s view pro registrovaného uživatele? Použijeme jinou factory metodu.

Tohle mimo jiné znamená, že se ve vašem kódu, implementujícím business logiku, nikdy nesmí objevit operátor new.

Řekl jsem nikdy? Ok, lhal jsem. Pokud operátor new instancuje value object, případně jiný leaf object grafu, zkrátka a polopatě řečeno, pokud instancujeme něco, co už nic jiného dalšího neinstancuje, pak je operátor new v pořádku. Nebude nám to komplikovat testování v izolaci, a docela jistě nepotřebujeme ani vlastní factory.

Testování v izolaci a dependency injection

Zmínil jsem testování v izolaci, a.k.a. unit testy. Díky testování v izolaci není nutné vizuálně ověřovat, zdali napsaný kód dělá, co má. Pak se taky nesmírně zrychluje provedení všech testů. To, co testy zdržuje, zpravidla není to, co nás v testech zajímá. To, co testy zdržuje, je práce se skutečnými soubory, skutečnou sítí, skutečným prohlížečem. V unit testech nás ale zajímá jen náš vlastní kód, ne to, jestli prohlížeč XY správně implementuje attachEvent. Podívejte se na anchorclickhan­dler_test.cof­fee (link).

AnchorClickHandler je komponenta, která zapouzdřuje funkcionalitu lightboxu. Sleduje bublající click event, a pokud se kliklo na ten správný odkaz, sama odpálí vlastní click event, v jehož vlastnosti anchors jsou všechny odkazy lightboxu. Klasická event delegation technika, díky které není nutné registrovat listenery na všechny odkazy ve stránce, lightboxy tak mohou být klidně generované ajaxem.

Kdybychom v testu pracovali se skutečným DOM modelem, a ne jeho mockem, nejenže bychom zaváděli do testu externí závislosti, tudíž by se jednalo o testy integrační, ale testy by se nám i zpomalily. Aby bylo jasno, pokud provedení všech testů bude trvat déle než pár sekund, bude nás čekání na jejich výsledek rozptylovat (co je asi nového na Twitteru?).

Aby bylo možné třídu od externích závislostí oprostit, je nutné jí všechny závislosti předat explicitně, typicky přes konstruktor. Třídy se musí na své závislosti aktivně ptát. Nenechte je jejich závislosti pasivně vyhledávat. V tom nám pomůže technika dependency injection, hezky stručně shrnutá zde. A zde je příklad v Coffeescriptu:

# Dependency injetion example.
class House
    # We are asking for things in contructor.
    constructor: (kitchen) ->
        @kitchen = kitchen

# Service locator antipattern example.
class House
    constructor: ->
        # our class is looking for kitchen
        @kitchen = new Kitchen

# another point of view

# house is frozen
class House
    constructor: ->
        @kitchen = new Kitchen

# now house can have any kitchen
class House
    constructor: (kitchen) ->
        @kitchen = kitchen

https://gist.git­hub.com/1584972

It´s always important to emphasize that dependency injection is just plain-old good OO design – Markos Charatzas

Psaní testů před samotným kódem a důsledné vyvarování se service locatorů znamená, že budeme schopni instancovat každou část aplikace v izolaci. Nejen my, ale i ostatní. V testech, i kdekoliv jinde. To je klíč ke skutečné znovupoužitel­nosti kódu.

Psaní testů na už existující kód je ošidné. Můžeme napsat nefunkční test, a ani se to nedovíme, protože neuvidíme test spadnout. Můžeme dokonce zjistit, že napsat test není vůbec možné, nebo je to obtížné. Pokud o takový netestovatelný kód stojíte, zde najdete pár tipů, jak na to.

A ještě jedna poznámka: Podívejte se na mock DOM elementu (viz zde). Jak víme, které metody má mock mít? Nevíme. Nepotřebujeme to vědět. Spustíme test, a chybové hlášky nám to samy odhalí.

TypeError: Object #<Object> has no method ‚attachEvent‘

Provázání tříd

V našem sofistikovaném lightboxu máme tři třídy: Ligthbox, AnchorClickHandler a View. Jak spolu třídy komunikují? V zásadě existují dvě možnosti – voláním metod nebo reakcí na události. Náš AnchorClickHandler vyhazuje událost click. Klidně by ale mohl volat metodu show na injectované instanci View (nebo čehokoliv jiného). Kdy zvolit který způsob? Zvolte způsob vám v danou situaci pohodlnější, sofistikovný lightbox demonstruje oba. Vodítkem vám může být třeba when to use events.

Poznámky k implementaci

Oba příklady jsou napsány nad Google Closure Library. K testování byl užit testovací framework Mocha, s assert frameworkem should.js. V repository najdete zdrojový kód jak v Javascriptu, tak v Coffeescriptu. Ve svém dev prostředí mám všechny testy spouštěné automaticky při uložení souboru. Jen tak docílíte toho, že vás test driven development nebude vytrhávat z flow a vy se budete moci plně soustředit na svou práci zábavu, aniž byste opustili editor.

Google Closure Library

Oba příklady také demonstrují, že rozsáhlá Google Closure Library, knihovna na které jsou postaveny nejsložitější ajaxové aplikace, lze použít i na maličké projekty. Však každý velký strom vyrostl ze semínka. Pro mne je Google Closure Library stejně praktická a příruční záležitost jako Nette pro Davida Grudla http://phpfas­hion.com/tohle-kurva-ani-omylem.

Pokud se chcete o knihovně Google Closure Library dozvědět více, a pokud chcete vědět, jak si správně nastavit testovací prostředí, navštivte nový kurz Daniela Steigerwalda „Google Closure a test driven development“.

Hypované mikroframeworky, stejně jako tweet sized snippety, jsou – až na naprosté výjimky – roztomilými hříčkami, pro vývoj aplikací nevhodné. Jen pro zajímavost, zkompilovaný sofistikovaný lightbox má něco kolem 6kb.

Závěr

V zájmu udržení rozsahu článku jsem zmínil jen to, co je podstatné k pochopení přiložených příkladů. Záměrně jsem opomenul složitější témata jako IOC, MVC, BDD a další, což si nechám pro články budoucí. Nejbližší budoucí článek se bude věnovat popisu a srovnání některých javascriptových MVC frameworků.

Závěrečná otázka: prasit, nebo ne?

Tento článek vznikl stejným způsobem jako doprovodný kód. Nejprve jsem „naivně“ naprasil hrubou strukturu, až pak jsem jej vypiloval k přečtení, zasadil věci do kontextu, doplnil odkazy, komentáře. Určitě je tak pro vás mnohem přínosnější. Jen mi to zabralo více času…

Neexistuje jediná správná odpověď. Všechno je tradeoff, kvalita kódu je jen jedna z mnoha proměnných, a vy sami musíte určit, jakou zrovna tato má váhu. Moc pěkně to shrnul Uncle Bob Martin.

“When designs are cheaper than builds, e.g. a skyscraper or a bridge, big up front design makes good sense.” https://twitter­.com/#!/uncle­bobmartin/sta­tus/156020534382047232

“But when builds are cheaper than designs, e.g. software or oil painting, short and iterative design and build steps are best.” https://twitter­.com/#!/uncle­bobmartin/sta­tus/156021350492934144

Do češtiny převedeno: Dvakrát měř, jednou řež. Ale jenom pokud je řezání alespoň dvakrát těžší než měření.

Komentáře

Subscribe
Upozornit na
guest
119 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Radek Miček

> Psaní testů před samotným kódem a důsledné vyvarování se service locatorů znamená, že budeme schopni instancovat každou část aplikace v izolaci. Nejen my, ale i ostatní. V testech, i kdekoliv jinde. To je klíč ke skutečné znovupoužitelnosti kódu.

Klíč ke znovupoužitelnosti a testovatelnosti je čistě funkcionální kód.

Nox

Mohl bys to prosím popsat hlouběj? Proč to stejné nejde třeba v OOP

Radek Miček

Čistě funkcionálním kódem mám na mysli, že funkce by měly být bez side effectů a vrácená hodnota by měla záviset pouze na vstupních parametrech. Lze to dělat i v OOP.

Ještě dodám, že vstupních parametrů by mělo být málo a měly by být jednoduché (tj. aby se nepředával celý svět).

Jirka Chmiel

> Ještě dodám, že vstupních parametrů by mělo být málo a měly by být jednoduché
> (tj. aby se nepředával celý svět).

Nevzniklo mj. právě kvůli tomuto OOP?

JS

Ne, to platilo porad.

ggael

Právě, že vzniklo. Alan Kay to jednou zmínil (totiž že rozsáhlé používání side-effectů součástí jeho původního plánu na ovládnutí světa nebylo).

Radek Miček

Vůbec nechápu, jak s tím souvisí OOP. Můžete to vysvětlit?

JS

IMHO idea, ze funkce maji byt male, delat jednu funkci, a byt bez vedlejsich efektu, je-li to mozne (predevsim v drivejsich dobach bylo ovsem pouzit vedlejsi efekt casto jedina cesta, jak neco delat efektivne), podle me saha az nekam k Lispu.

blizz

súhlasím, ale nedá sa to brať dogmaticky. trebars funkcia vracajúca presný čas, alebo náhodné číslo vráti vždy inú hodnotu bez ohľadu na vstupné parametre.

Daniel Steigerwald

A proto by se měli zamockovat.

Pavel Šimerda

„Čistě funkcionálním kódem mám na mysli, že funkce by měly být bez side effectů a vrácená hodnota by měla záviset pouze na vstupních parametrech. Lze to dělat i v OOP.“

Počítáš ukazatel na objekt „před tečkou“ mezi vstupní parametry?

Radek Miček

> Počítáš ukazatel na objekt „před tečkou“ mezi vstupní parametry?

Ano, počítám.

blizz

tá v tom zelenom má pekné kozy

Lol Phirae

Taky si říkám, že bych ji klidně zprasil. ;-)

Palo

Nepoznate ani svoje krajanky? Veronika Zemanova!!!

bakerman

Mě víc dostala ta s těma flaškama

Riff

Mě zase nejvíc dostaly ty flašky.

Patrik Votoček

Mám jeden trochu OT dotaz. Ale už delší dobu mě vrtá v hlavě.

Dokázal by někdo jednoduše popsat výhody should.js oproti klasickému assertu?

Jiří Knesl

Should pochází z Behaviour Driven Developmentu. Cílem je změnit běžné testování stavu typu:

assert.equal abc, def

na formát:

abc.should.equal def

Čímž získáváš super čitelnost a DSL-like syntaxi (jakkoliv BDD toho zahrnuje mnohem víc). Proč psát testy víc jako věty výborně vysvětluje Dan North, autor BDD tady http://dannorth.net/introducing-bdd/

Miloslav Ponkrác

A proč nezavádět věci jako psaní vět objasňuje studium jazyka COBOL.

Miloslav Ponkrác

P.S.: Kdo nestuduje historii, je odsouzen k opakování chyb.

Blb

Nemůžete pro nás tupce tu svojí hlubokou myšlenku ještě trochu rozvést?

alancox

Klidně. :-)

Prostě kdosi tu pronesl dogma, že je príma dělat programy či jejich části (konkrétně zde assery) jako věty. A že je to nejlepší možná věc.

Já jsem uvedl příklad, že o to už se tu lidé snažili, stačí se podívat na programovací jazyk COBOL.

Pro ty „tupce“, já jsem nenapsal, že je správné první nebo druhé. Jen mě trochu pije krev, že kdosi tu bez důkazu napsal „získáváš super čitelnost“ a zároveň odkaz na to proč „psát jako věty víc“. V poslední době se namísto praktických aspektů z programování dělá ideologie.

Namítl jsem tedy protipříklad – jazyk COBOL se důsledně řídil tím, že „psát věty co nejvíce je príma“. A pokud chcete psát věty víc, swičnutí na jazyk COBOL je nejlepší co můžete udělat. Byl to programovací jazyk, který vznikl právě na základě, že programování by mělo co nejvíce připomínat přirozený lidský jazyk a přirozené lidské věty. Jak se ukázalo, byl to omyl a slepá cesta vývoje.

Bohužel se tento omyl projevil někde kolem roku 1961 a poté co devastoval řadu let nervy programátorů. Nicméně dnešní generace nejspíše na jazyk COBOL a jeho historické poučení už zapoměněla – a tak znovu koketuje s tím, že psát vše jako věty je príma. Doporučuji tedy přejít na jazyk COBOL, navíc je to špičkově placená práce a kdo umí dobře COBOL je velmi luxusně placen. A zároveň nikde nenajdete lépe splněné paradigma, že psát věty je príma.

A nic Vás z tohoto paradigmatu také rychleji nevyléčí. Věřte mi, že po krátké době už Vám to príma připadat nebude.

Ono je hezké psát věci jako věty do té doby, než to lidé vezmou vážně a pak z toho budou mít bolení hlavy.

A to je vše.

Miloslav Ponkrác

Daniel Steigerwald

Ne programy, ale testy.

alancox

Test není většinou kus kódu? Že by mi něco ušlo?

Daniel Steigerwald

Testy jsou specifické tím, že jsou na sobě nezávyslé. V případě should.js jde opravdu jen o jiný slovosled, nic víc.
should.equal(str, ‚foo‘) je pouze jinak zapsaný assert.equal(str, ‚foo‘)

alancox

Samozřejmě.

A čistý program a naprasený program se od sebe může lišit jen jiným slovosledem. Nebo jinými názvy.

Ale rejpnu si přímo ďábelsky: Obhajujete, že je možné použít jiný slovosled, a že to nevadí, protože je to malý nezávislý test.

Ve větším měřítku by to vadilo? Kdyby to byl závislý kód?

Nenapsal jsem, že jedno nebo druhé je špatně. Pouze jsem vytvořil rovnováhu k reklamně jásavému „proč používat v kódech věty víc“.

Já osobně budu používat vždy assert. Jednak je to IMHO přehlednější. Jednak jakmile vidím v kódu/testu assert, je jasné, že následuje kód pro test. Vizuálně to snadno odliším. Je tak nějak přirozenější v celém OOP jednotně dodržovat, že první název je objekt či modul a akce přicházejí za názvem objekty. Existuje soubor.cti() a klavesnice.cti(). Jedna ze základních zásad pro čitelný (rozuměj neprasácký program) je dodržování stejného code style pro celý projekt. Pokud OOP vynucuje mít název modulu či objektu jako první jméno, pak ve stejném duchu je mít assert vlevo.

Jak by se Vám líbil program ve stylu:

x == y if
file.open();
x > 10 while
file.write(x);

To je totiž ve stejném duchu jako should.

Všichni programátoři očekávají assert na testy. To je obecná konvence napříč všemi programovacími jazyky.

Stejně tak mohu udělat program v C++/C#/Pythonu/Ruby atd., kde protože se mi to líbí změním konvence. Operátor + bude dělit a operátor – bude odmocňovat.

A znovu, mě je jedno kdo si bude používat should a na co chce. Jen by bylo třeba méně jásání typu „proč něco používat víc“ a podložit to nějakými argumenty.

Miloslav Ponkrác

Jiří Knesl

Zrovna syntax:

show results if response.status is yes
renderer.show row if row.active

považuju za jednu z největších vychytávek v CoffeeScriptu, která zdrojové kódy ohromně zpřehledňuje. Vypadá to jako věta. Jen na konec napsat tečku.

Oldisy3

to je sice fajn, ale programovani neni psani knihy. Cist stale dokola ty same vety zacne byt unavne a nakonec budete muset vic cist nez budete moct psat. Velka vychytavka. Je v tom takovy rozdil jako mezi zadanim slovni matematicke ulohy a jeji matematickou interpretaci.

gilhad

Tyto vychytavky jsou skvele, teda az na spoustu pripadu, kdy snizuji citelnost, coz je skoro vzdy.

Je nutne je pouzivat, pokud neni neco lepsiho k dispozici, napriklad standardni funkce zname vsem.

Zarucene tak dostaneme jednoduse citelny kod, jen obcas dost neprehledny, zejmena v beznych pripadech.

Takhle jsem to myslel s tim if na konci radku?

brablc

Potkal jsem noisy words v COBOLu (slova psaná pouze pro zlepšení čitelnosti kódu, lze je vynechat) i obrácenou syntaxi if z Perlu (vychytávka/vy­kopávka). Spolu s unless (negativní k if) zrychluje psaní kódu a osobně to používám.

V obou případech to znesnadňuje čtení třetím osobám, nicméně oproti CoffeeScriptu jsou stále oba jazyky čitelné bez studia syntaxe. Ale možná už jenom stárnu.

alancox

Ještě by se slušelo říci, že bořit zažité konvence a to konvence na úrovni de facto standardu jako je assert chce hodně silný argument, který dává omračující výhodu.

Není-li omračující výhoda tak silného kalibru, že ospravedlňuje zboření v celém oboru zažitého standardu, tedy slova assert – platí zákon Occamovy břitvy.

Proto jsem na obhajobu změny konvence slova assert, který je používán na celém světě všemi programovacími jazyky už celá desetiletí očekával něco trošičku víc a nějaké silné argumenty, tedy hodně silné argumenty, než jenom „mělo by se to používat víc“.

Proč by třeba if nemohlo dělat cyklus? Nebo proč by slovo for nemohlo dělat návrat z funkce? Mohlo. Ale konvence říkají jinak. Nic než konvence. Ale každý tomu rozumí.

Důvod, proč se vyznáte ve svém i cizím programu je v první řadě ten, že dodržuje konvence. Až budete mít skvěle a čitelně napsaný programu, který znamnénkem + násobí, metoda read() bude zapisovat do souboru, metoda getSize() vrátí IP adresu apod., pak pochopíte proč boření konvencí je blbost, není-li pro to opravdu dobrý důvod. Zkuste si takový program napsat a udržovat.

A teď si zkuste udržet program po kolegovi v týmu, který začne konvenci inovovat. Jednu změnu unesete, možná i dvě, ale pak začne být husto.

A dál už přispívat k této diskusi nebudu, nedostatek času.

Miloslav Ponkrác

Daniel Steigerwald

Díky za vaše komentáře. Ve skutečnosti je syntax assert frameworku málo důležitá. Je to implementační detail. Mocha umí pracovat s různými assert frameworky, já si zvolil should.js, ale klidně sem mohl použít assert. Opravdu, tohle není zas tak podstatné, a hlavně, o tom článek není.

František Kučera

Jenže on má pravdu (minimálně v tomhle případě…).

wtf_prezdivka?

nemate nekdo horkou linku do pekla ? rekl bych, ze tam asi zaclo mrznout ;-)

David Grudl

Chtěl bych se jen zeptat, jestli to, že COBOL, jenž co nejvíce připomínal přirozený lidský jazyk, což jak se ukázalo byl omyl a slepá cesta vývoje, podpoříš i nějakým odkazem, nebo je důkazem tvé prosté konstatování ve stylu „všichni jste hlupáci“?

Martin Malý

Mrtvej jazyk, wtz!

JS

Duvod, proc pokus o programovani v „prirozenem“ jazyce IMHO selhaly je v tom, ze to plete. Prirozeny jazyk totiz snese drobne odchylky v syntaxi (napriklad zmenu slovosledu), kdezto pocitace ne (specialne COBOL je hrozne citlivy na ruzne tecky). Takze se to pak spatne pamatuje, jaka je presna syntaxe, protoze je prilis podobna te prirozene. Druhy, i kdyz trochu vedlejsi problem, jsou zavorky.

David Grudl

Nemám pocit, že by SQL selhalo nebo že by tam byl nějaký problém se závorky, když se tedy bavíme o jazycích podobným přirozeným jazykům.

JS

Nevim. Prijde mi, ze lide se naopak snazi, sec jim sily staci, se SQL ruzne vyhnout. Ale mozna, ze ty jazyky jsou proste stare.

Ja to ovsem vidim jeste jinde – Common Lisp ma makro „loop“, a to umoznuje zapisovat smycky v jakemsi „cloveku blizkem“ pseudojazyce. Ovsem pokud si zrovna nepamatujete konkretni idiom, je to dost zkoumani, jak v tom neco zapsat. Prijde mi, ze to plati i o SQL.

František Kučera

Tady je otázka, jestli je SQL tak úspěšné díky tomu, že se podobá přirozenému jazyku, nebo navzdory tomu. Např. mně se na něm líbí, že je deklarativní – ale to, zda ty dotazy vzdáleně připomínají anglické věty nebo ne, je mi celkem ukradené.

David Grudl

Netvrdil jsem, že je SQL díky tomu úspěšné, prosím nepodsouvat. Jen jsem se ptal, jestli Miroslav Ponkrác má v plánu svůj bohorovný komentář i doložit jinak, než tím, že jej podepsal Miroslav Ponkrác. Což bylo pochopitelně hovorová otázka a tudíž na ni nebylo třeba reagovat ;-)

kvr

Já bych hlavně netvrdil, že SQL je postavené na přirozeném lidském jazyce. Na první pohled úplně základní syntaxe by tak možná mohla vypadat, ale třeba sloupeček v tabulce se zapisuje „tab.col“, nikoli jako třeba v Cobolu „col in tab“. Ten posun k lidskému jazyku je tam maximálně na úrovni jaký má Java oproti C++ (tedy sem tam klíčové slovo navíc oproti dvojtečce apod.).

Že se snaží SW vývoj vyhýbat zápisům v SQL (zmíněno někde dříve či později), je spíš snaha se vyhnout zásahům do dalších vrstev kódu, která je obvykle definována deklarativně a oproti business vrstvě může mít odlišnosti, které se vyvíjí nezávisle na vyšších vrstvách. Jinými slovy, proč to dělat ručně, když to není třeba.

Argument, že Cobol není mrtvý jazyk, protože existují pozice pro vývojáře, je absurdní. Cobol je mrtvý, protože žádný nový SW v něm už nevzniká, pouze se udržuje/rozšiřuje stávající (a taky je ten poměr cena/výkon oproti současnému vývoji pěkně drahý).

Jinak samozřejmě 100% souhlas, co se lidského vs. formálního jazyka týče, zkuste nahradit současný jazyk matematiky a logiky jazykem lidským a vrátíte se na úroveň filosofů antického Řecka (no offence).

brablc

Měl jsem svého času na starosti přes 10 lidí na Německé burze ve Frankfurtu (Eurex, Risk Management) v maintence týmu. Cca 2 mil řádků kódu, z toho většina C a hodně COBOLu (OpenVMS). Nejlepším COBOL developerům bylo už před 10 lety přes 60 a byli to externisti z UK. Jeden z nich si vždy udělal hardcopy na papír a potom to četl stránku po stránce a lokalizoval chybu ;-)

COBOL je na rozdíl třeba od CoffeeScriptu čitelný pro každého. Zmatení ale nastane, když ty věty začně někdo říkat jinak, nebo když přidá noisy words. To vede ke zmatení nezkušených developerů v důsledku toho vznikaly nové programy se zcela zbytečnými sekcemi, protože se je programátoři báli osekat. Bylo toho tam potom i 2x více než bylo nutné. Ano, je to problém nezkušených programátorů, ale pro COBOL už v podstatě člověk nějak moc jiné nesežene.

ADD 1 TO WS-RECORD-CNT
MOVE WS-NO TO WS-INIT-FLAG
MOVE ORDR-NO-REC OF REC-WS-REC TO a_order_no IN T_QUOTE
CALL "EXT_FUNC" USING WS-VARIABLE GIVING a_exp_year IN T_QUOTE
IF MOVE_SHORT IN POSITION_TRANSACTION < ZERO
    MULTIPLY MOVE_SHORT IN POSITION_TRANSACTION BY -1
        GIVING MOVE_SHORT IN POSITION_TRANSACTION
END-IF

No není to úplně nejstručnější.

Oldisy3

prijde mi ze je lepsi kdyz se koder nauci jazyk nez kdyz se jazyk snazi simulovat literaturu. Matematika se taky neprizpusobuje tomu kdo se ji zabiva ale naopak.
Napriklad ten kus kodu co jste sem vlepil, nez budu vedet co to dela tak to musim cele precist, musim si precit kazde slovo a spravne si ho zasadit v kontextu.
i++ si myslim je rychleji citelne nez add 1 to i.

Jiří Knesl

Jenže problém je v tom, že:

+ v běžné algebře sčítá a mám za to, že dokonce je v matematice dohoda, že je zakázáno vytvořit takovou grupu, kde by byla operace násobení popsána operátorem +. Neexistuje racionální důvod, proč by někdo přetížil + na násobení.

getSize() vrací velikost. Jiné použití by byl code smell. Tím pádem iracionální řešení.

Zatímco změna pořadí volání, aby kód připomínal víc angličtinu, to je dokonale racionální řešení. Jednou už v programování používáme anglická slova a kód:

if x > y do; echo x + 1; done;

považujeme za kód v pořádku. Pokud by nemělo programování připomínat angličtinu, mělo se zvolit něco jiného.

Místo if třeba #3, do ~1, ; ^7, done &99.

Pak by takový kód vypadal takhle:

#3 x > y ~1^7 echo x + 1 ^7 &99^7

Máte to, už to nevypadá jako anglická věta. Jste šťastný?

Radek Miček

> mám za to, že dokonce je v matematice dohoda, že je zakázáno vytvořit takovou grupu, kde by byla operace násobení popsána operátorem +.

+ je jen symbol jazyka teorie grup a není žádný důvod, proč takto omezovat jeho interpretaci

Jiří Knesl

Ohromně se mýlíte.

Obecně můžete vidět 2 druhy jazyků. Jedny se přibližují „matematickému zápisu“ (C, VB, Pascal, PHP). Ty jsou vhodné pro popisy algoritmů. Zápis výpočtů je v nich obvykle velmi dobře čitelný. Naopak na objektové programování se nehodí, protože otravují spoustou syntaktického bordelu (a to si myslím i o C++, C#, Javě).

Pak jsou jazyky, které připomínají běžné věty (Ruby, Smalltalk, CoffeeScript, Self, AppleScript). Ty jsou vhodné pro objektové programování. Objektové programování totiž nění o ničem jiném, než o tom, že A posílá zprávu B a k tomu nepotřebujeme žádné speciální znaky. Na druhou stranu zapisovat v takových jazycích výpočty by byl porod (proto si berou kusy syntaxe z prvních jazyků, takže i v tom Smalltalku můžete napsat 1 + 1 místo 1 plus: 1).

User Stories jsou text. Jsou zadání. Běžné věty. Můžete buďto vzít Story a vyrobit parser a přepsat ho do syntaxe jazyka (jako to dělá Cucumber), nebo můžete přímo upravit syntax jazyka tak, aby zápis programu vypadal jako ta Story (to dělá třeba RSpec nebo Should.JS). Já ten popis beru, šetří čas, kontroluje syntaxi, kdokoliv se s tím setkal, to chápe a velmi dobře se mu to čte.

Radek Miček

> Objektové programování totiž nění o ničem jiném, než o tom, že A posílá zprávu B a k tomu nepotřebujeme žádné speciální

A jak do toho zapadají jazyky s multimetodami?

Ladislav Thon

Když se bude dispatch vyhodnocovat dynamicky, tj. ne jen podle typu přijímajícího objektu, ale i podle typů parametrů, tak to budou vlastně taky multimetody ;-) (Jeden z nejrozšířenějších dynamicky typovaných jazyků pro JVM takhle funguje.) Ale jinak tohle považuju spíš za slovíčkaření, v naprosté většině případů lidi, kteří mluví o OOP, mluví o OOP založeném na třídách, což je na jednu stranu nepřesná, na druhou stranu užitečná zkratka.

Daniel Steigerwald

Čitelnější syntax, nic jiného.

Michal Augustýn

Super článek, Dane!

Aleš Roubíček

Použít na závěr citaci Uncla Boba a říct, že můžemo volit tak či tak, chce koule. :)

Citace se vztahují k návrhu, k architektuře. Uncle Bob říká, že tam, kde je drahé měnit již vybudované (tj. hmotná díla jako budovy, nábytek), je důležité mít dobrý návrh dopředu. Naopak, že tam, kde výsledné dílo můžeme měnit snadno (u software nebo uměleckých děl), je výhodnější iterativní design.

Uncle Bob neřeší, zda prasit nebo ne. Profesionál neprasí. Uncle Bob neřeší, jestli psát unit testy nebo ne. Profesionál praktikuje TDD. Pseudopragmatické závěry jsou k ničemu. ;)

Neznamy Hrdina

mozna ze netreba prebytecne koule, mozna ze staci drobny nedostatek v jine oblasti (prekladatelske ci kognitivni schopnosti). ale to nema ten „ring“, pravda ;-))

perfektni pouziti slusnyho hlodu ;-)

Petr Janda (twitter.com/petrjanda)

Diky za super clanek o TDD a doufam, ze si z nej ctenari odnesou podstatu!

S cim vsak nesouhlasim je pouziti dependency injection. Chapu jej jako techniku znamou ze statickych jazyku, ktera usnadnuje testovatelnost, ale proc ji pouzit v Javascriptu?

Spis bych byl pro stub/mock framework, jehoz napsani je v javascriptu pomerne trivialni.

Aleš Roubíček

Dependency injection nemá nic společnýho se statickým typováním ani testováním. Je to technika dobrého objektového návrhu.

Mock/Stub framework není v JS vůbec potřeba, díky dynamičnosti a slabému typování jazyka.

Petr Janda (twitter.com/petrjanda)

Pokud dependency injection nema souvislost s testovatelnosti, tak nevim, proc by DI byl takto obsirne zminen i v tomto clanku, ktery se primarne testovani venuje.

Myslim ze koncept DI ma smysl i v Javascriptu, kdyz chces implementovat napr. Strategy pattern, ale nemyslim si ze je treba jej pouzivat dogmaticky. Vetsinu pripadu bych nahradil prave stubbingem. Viz treba jak to dela Jasmine a jeho spies. http://pivotal.github.com/jasmine/.

Pozn.: Na druhou stranu si nedovedu predstavit jak bych bez DI psal testy napr v C++.

Aleš Roubíček

Jenže článek vůbec není o testování. ;) Článek je o prasení/neprasení. Testování, DI, TDD, dobrý OO návrh, to všechno jsou věci které spadají do neprasení.

Pro stubování potřebujete DI, jinak se jedná o monkey-patching.

Petr Janda (twitter.com/petrjanda)

Pravda, stubovani je v podstate DI :) jen psany trosku jinak (prave diky dynamicnosti jazyka).

Aleš Roubíček

Stub je objekt, který nahrazuje závislost systému pod testem. Pokud se tato závislost nahrazuje jinak než pomocí DI, jde o monkey-patching (právě díky dynamičnosti jazyka).

Petr Janda (twitter.com/petrjanda)

Chapu dobre, ze podle Vas nasledujici node.js kod je spatny a jeho test je monkey-patching?

https://gist.github.com/1606059

Bylo by spravne predat http knihovnu jako dependency do objektu App?

Aleš Roubíček

Nikoliv. App je, pokud to dobře chápu, Composition Root aplikace. Otázka, je zda má hlubší smyl App testovat?

Petr Janda (twitter.com/petrjanda)

Samozrejme se jedna o pomerne jednoduche konstrukce, ale myslim, ze v tymu, kde s kodem pracuje vice lidi, take ruzne urovne, ma smysl testovat vse :)

Spis jsem tim chtel ilustrovat pointu, ze se da psat citelny kod i bez vkladani vsech dependencies. Samozrejme pri modelovani slozitejsich vazem mezi objekty je DI platna a dobra technika v mnoha pripadech.

Aleš Roubíček

Jenže spyOn není zrovna ukázkou čitelného testu. Zavádí tam „magic“ a to může být matoucí.

Jaký konkrétně smysl má testovat Composition Root? To už je jen testování pro testování, obvzlášt, když stejně „závislosti“ fejkujete.

Petr Janda (twitter.com/petrjanda)

Pro me jsou spies citelne, ale to je vec nazoru (zajimalo by me, jak by mohl test vypadat bez jeho pouziti).

Jak pisu, priklad je trivialni, kdybych do metody init() pridal logiku, ktera by napriklad nejakym zpusobem podminovala vytvoreni serveru (napr. overeni, ze options obsahuji nutne parametry), pak nevidim duvod proc netestovat.

Nox

Velmi hezký článek

Jen … šlo by objasnit v čem je BDD složitější než TDD? Podle informací co jsem našel*, je to to stejné, jen používá jiné termíny, příp. „BDD is TDD done right. TDD done right is BDD.“

* např. http://stackoverflow.com/questions/4395469/tdd-and-bdd-differences

Ladislav Thon

A nebo „TDD done right is called TDD. The term BDD wastes a slot in term space.“

Aleš Roubíček

TDD a BDD jsou dvě zcela odlišné věci.

TDD je praktika iterativního vývoje. Primárně je to nástroj vývojářů.

BDD je framework na psaní akceptačních testů. Primárně je to nástroj testerů a product ownerů.

Nox

Děkuji za odpověď. Jak je to potom v praxi, nejsou nakonec ale výsledné kódy a subjekty TDD a BDD dost podobné?
„Testy“ napsané v rámci Test Driven Developmentu tedy jsou testy, nebo nejsou?

Aleš Roubíček

Testy vzniklé při TDD samozřejmě testy jsou a konkrétně unit testy popř. integrační testy. Takové testy jsou značně low level, ověřují správnou implementaci algoritmů, chování jednotlivých objektů. Naproti tomu BDD slouží k psaní akceptačních testů, které slouží k ověřování business pravidel, chování systému jako celku. Takové testy by měli být srozumitlné i neprogramátorům, expertům z problémové domény.

Nox

Ok, díky za osvětlení

Palo

Ja pridam uz len svoj neoblubeny nazor:
Ako sa da nieco co je napisane v JS alebo PHP nezprasit? To su prasacke jazyky rovno od prirodzenia.

tdvorak

To, že umožňují prasit, ještě neznamená, že to nejde jinak. Prasáckej kód napíšete v každém jazyce. Některé jazyky se tomu jen snaží bránit víc než jiné. Nakonec, článek je o návrhu a ten jde zmršit vždy a všude, na jazyku nezáleží.

Palo

Ja viem ale nemozem si pomoct. Ked vidim ako sa snazi niekto dorobit objekty do neobjektoveho jazyka vzdy mi je cudne od zaludka. A to sa naozaj bavime o tych ‚neprasackych‘ verziach toho kodu.

Nox

Ale JavaScript JE objektový jazyk. To že není tím „jedním a správným způsobem“ neznamená, že není.

Napsat o jazyku, kde skoro vše je objekt, že není objektový … je docela wtf.

Palo

Podporuje object oriented a asociativne polia su skutocna objektova podpora jazyka.

blizz

ono sa to nezda ale JSko je skutocne objektovejsie ako vacsina beznych jazykov zalozenych na triedach. prave ten jednoduchy a flexybilny objektovy model js dava programatorovi obrovsku slobodu. ale to pochopis az ked v nom budes dlhsie programovat a zistis ze OOP neni o zapuzdreni, interfacoch a triedach ale o v prvom rade o objektoch a objektovom mysleni.

alancox

„Ja viem ale nemozem si pomoct. Ked vidim ako sa snazi niekto dorobit objekty do neobjektoveho jazyka vzdy mi je cudne od zaludka. A to sa naozaj bavime o tych ‚neprasackych‘ verziach toho kodu.“

Pokud si někdo nedokáže představit čístý kód v nějakých běžných jazycích – pak je to proto, že je sám prase. Dál už je to jen efekt hesla podle sebe soudím Tebe.

Objektové progamování nepotřebuje objektovou podporu v jazyce.

Nicméně JS i PHP jsou objektové jazyky.

David Grudl

Přesněji objektově orientované, jinak souhlas.

Oldisy3

Proc na nej reagujete? je to nevychovatelnej dogmatik.

skrat

Toto nezmyselne pravidlo uz bolo vyvratene a oznacene za antipattern vela krat. 100% pokrytie kodu testami? Aky to ma zmysel? A ked nieje potreba 100% pokrytie, tak ako zistist ci ma zmysel napisat test? Tym ze ho napises skor ako implementaciu, aby si potom v implementacii zistil ze nieje co testovat a tym padom tvoj test (1+1=2, amen) je k nicomu?

skrat

No a k tym testom. Co „konkretne“ testujes s „click on anchor should call element.query­SelectorAll“ ? Podobne veci som videl u svojich prasackych kolegov ktory napisaly platobny system kde test suite mala velkost 4x implementacie, vsetko svietilo na zeleno, akurat ze zakaznikov ten system oberal o peniaze raz tolko ako mal.

Toto sa vola „testing for the sake (and fun) of testing“. Inymi slovami, s projektom stravis viac casu nez je treba, bez ziadnej pridanej hodnoty. Testy typu „should call“. Potom zmenis implementaciu, trebars nieco zoptimalizujes, stale to bude krasne fungovat ale tvoj „should call“ test failne, a budes ho musiet opravit. Presiel som vsetky testy v lightbox-example repo. a je tam toho kopec.

IMHO testovat sa ma to co je viditelne uzivatelovi a na vystupe. V pripade lightboxu:

* kliknutim na link, zobrazi sa?
* kliknutim na next, zobrazi sa dalsi?
* atd.

Daniel Steigerwald

Kdo ho vyvrátil?

skrat

Doporucam precitat http://goo.gl/dXcln . Je proste nezmysel porovnavat abstraktne (len eventualne materialne – maintenance) pojmy ako „kvalita kodu“ s materialnymi ako „trvanie a cena vyvoja“. Za dalsie, TDD dava zmysel len a len v tazko korporatnom prostredi kde sa vyraba softver ako vo fabrike na beziacom pase. Jeden projekt za druhym, ano vtedy je dolezite aby sa tvoji zotroceni robotnici drzali TDD praktik za ucelom maximalizacie produktivity a „kvality“ kodu. Ja osobne sa tesim z toho ze takyto job ma nepostihol, a moja praca je rozmanita a kreativna. A keby som sa tu drzal TDD tak ma trafi slak. Akoby si aplikoval TDD na vyvoj povedzme grafickeho alebo zvukoveho programu? Ako by si testoval ci hra vyzera naozaj naozaj dobre, alebo ci syntezator na ktorom pracujes naozaj znie tak ako chces?

KarelI

Ve chvili kdy se o ten kod budete muset delsi dobu starat, rozvijet ho a opravovat, tak se vam pojem „kvalita kodu“ zmaterializuje hodne rychle. A TDD je jeden ze zpusobu jak docilit aby to nebylo moc drahe. Troufam si tvrdit, ze pro dodavatele netrivialniho softu je jen otazkou casu, kdy jim to dojde.

TDD se nejak vylucuje s rozmanitosti a kreativitou?

Ze nevidite uplatneni TDD pri vyvoji grafickeho programu mi naznacuje, ze vubec nemate predstavu a fantazii co je tim mysleno, tedy pochybuji i o vasi kreativite. Berte to jako podnet k vlastnimu rozvoji.
K vlastni otazce – az ten graficky program zacne opravdu neco umet, budete tam mit treba konvolucni filtr, muzete si na to napsat tridu, ktera ho bude pocitat a muzete si napsat UT, ktery vam otestuje ze ma vhodne rozhrani, ze dostane vse co potrebuje a ze dava spravne vysledky. Jeste driv nez ji vubec zavolate z GUI.

K tomu korporatnimu prostredi – na pohovory nam chodi 3 typy kandidatu – ti co maji OOP, navrh, TDD apod. v malicku, ti co se k tomu blizi, maji chut na sobe pracovat a naucit se nove veci. Tretim druhem jsou ti co je takove podruznosti nezajimaji a nepotrebuji to k tvorbe genialnich programu – bez vyjimky to jsou neskutecni patlalove.

skrat

Si vlastne rozumieme. Takze aky zmysel ma „A should call B“ ?

Daniel Steigerwald

Píši to v článku, ale klidně to zopakuji.
1) nemusíte spouštět celý program, abyste si ověřil požadované chování jedné jeho části
2) a nemusíte si to ani pamatovat, test si to pamatuje za vás
3) to, že každý řádek třídy musíte otestovat, vás nutí udržovat třídy jednoduché
4) až budete refaktorovat kód, nebudete si muset pamatovat co se kde volá, testy si to „pamatují“ za vás

Satai

Poznamenal bych, ze 4) netrepi ty, co pouzivaji staticke typovani. Ostatne casto uvadena vyhoda testu pri refaktorovani plati jen pokud nema jazyk dobry typovy system a dobre IDE.

Daniel Steigerwald

Dobrá poznámka. Avšak netýká se Javascriptu, tedy pokud není použit Google Closure Compiler například :)

Satai

Spis divialni postreh ;)

Daniel Steigerwald

Na to bych vám mohl reagovat, že článek vyvracející 100% pokrytí testy…, už byl také vyvrácen – http://blog.8thlight.com/uncle-bob/2012/01/11/Flipping-the-Bit.html. Nejsem si ale jist, zdali by taková forma diskuze, byla přínosná.
Jestli sem vás dobře pochopil, tak jste myslím smysl unit testů dobře nepochopil. Snažíte se jim přisuzovat nadpřirozené schopnosti. Přiznávám, opravdu netuším jak bych napsal unit test, aby „hra vyzerala naozaj dobre“.
To ostatně smysl unit testů ani není. Jak bych TDD aplikoval na vyvoj grafickeho nebo zvukového programu? Úplně stejně. Copak grafický nebo zvukový program, není zase jenom kód?

skrat

To bolo pointa, ja len nesuhlasim s pravidlami TF a TATFT, a 100% CC. Pretoze TF ma velmi blizko k „premature optimization“ (zvysok poucky poznate, konci to slovickom evil). Unit testy pisem ked mam hotovy prototype (sketch code), a to len pre tie casti programu ktore povazujem (zo zkusenosti) za problematicke.

alancox

Ten člověk má pravdu a zřejmě nebyl pochopen.

Na jednu stranu je spousta lidí, kteří netestují – špatně. Na druhou stranu je mnoho lidí, kteří testování považují za boha – ještě horší.

Jsem ze starší školy. Jedna matematická poučka zní – neexistuje – a to je prosím seriózně matematicky dokázáno – možnost jak otestovat na 100 %, že v programu není chyba a že běží správně.

Jinak řečeno, nějaké pokrytí 100 % testy je víra nepodložená realitou. Můžete pokrýt 100 % kódu testy, ale je otázka, zda je to vždy potřebné, účelné a nutné. Ale hlavně, vždy a jakékoli testy odhalí jen zlomeček možných chyb. Přesněji odhalí ty chyby, které předpokládáte a na které si uděláte testy. Což je zlomeček chyb, které mohou nastat.

Z tohoto pohledu se dělání testů zaměňuje za test kódu. I testovat se musí umět.

Dále, abych interpretoval kolegu, kterého jste utřel, ale nejsem si jist zda správně. Existují programy, které nemají výstup testovatelný programově, ale přitom tento výstup je jejich účel. A zrovna občas grafické nebo zvukové programy alespoň část takové funkce mají.

Já bych přidal ze svého pohledu ještě další věc. Jsou programy a rutiny, kde není rychlostní rezerva na to dodržovat všechny zásady aby šlo do toho snadno vložit unit test. Každá abstrakce a každý luxus programátora má dost často jako za následek nižší výkon programu. A někdy se to nehodí. Třeba doporučuji si pokusně stvořit článek – jak bych použil unit testy na video kodeky. Pohoříte jako papír. Nic uvnitř rozumně neotestujete, pouze celý kodek jako černou skříňku. Ani není prostor na to uvnitř dodržovat pravidla pro to aby unit testy bylo snadné použít.

Beru ovšem, že tento článek je pro TDD, kde testování je základ. Takový vývoj není vhodný pro každý projekt ani každý program. Dokonce bych řekl že pro většinu není vhodný. Nicméně pro enterprise projekty nebo běžné desktop programy celkem ano či je to dokonce jedna z nejelpších metodik.

Metodu 100 % pokrytí testy bez přemýšlení považuji osobně za dogmatickou ptákovinu.

Miloslav Ponkrác

Aleš Roubíček

Jenže 100% CC nezaručuje to, že se v kódu nevyskytují chyby, ale to, že se tam nevyskytují známé chyby. Když píšete kód pomocí TDD, řídíte se nějakým UseCase, který obsahuje očekávané chování a některé výjimečné situace. Ty pokryjete testy. Pokud bylo v Use Case něco opomenuto a projeví se to jako bug, napíšete padající test, který bug reprodukuje, fixnete ho a máte jistotu, že když se bug opět objeví, tak se o tom velice rychle dozvíte.

TDD není Bůh. Nemůžete věřit, že s TDD bude SW bez chyby. Ale je dokázáno, že SW psaný pomocí TDD obsahujě řádově méně chyb, a oprava chyb nalezetých je také řádově snažší (tj. levnější oprava). Ale kdo rád tráví hodiny s debuggerem, pro toho TDD samozřejmě moc není.

Ale pozor na to. 100% CC neznamená psaní tuny zbytečných testů. Psát dobré testy je dovednost, která potřebuje znalosti a praxi.

Ad výkon. Vy jste jistě z velmi staré školy. Dnešní iPad 2 má tolik výkonu, že by v devedesátých letech patřil mezi top 50 superpočítačů. A to je jen blbej tablet. Abstrakce v kódu nám umožňují oddalovat rozhodnutí o detailech, které mají vliv na výkon. Je dokázáno, že změnou architektury můžete ovlivnit výkon řádově lépe než mikroptimalizacemi. A potlačování vhodných abstrakcí je mikroptimalizace.

Ano, jistě jsou časově kritické aplikace v letadlech nebo jaderných elektrárnách. Jenže pochybuju o tom, že by si tam někdo dovolil do produkce nasadit kód, který před tím neotestoval. Pevně v to věřím.

František Kučera

+1

Nechceš tyhle poznámky někdy napsat jako článek (je jedno, kde vyjde)? V komentářích to zapadne.

Satai

OT: Pomalu s tou matematickou karou. Samozrejme, ze existuje moznost dokazat, ze program pobezi vzdy spravne. Jen to omezuje mnozstvi programu, ktere lze napsat.

František Kučera

Ad „Samozrejme, ze existuje moznost dokazat, ze program pobezi vzdy spravne.“

A test taky považuješ za program nebo ne?

Pokud ano, pak je potřeba otestovat i ten test – dalším testem, který je opět potřeba otestovat…

Pokud ne* tak test považujeme za nějaký neomylný překlad analýzy (zadání, požadavků) a nekriticky věříme v jeho 100% správnost – věříme, že ten, kdo test psal, zcela pochopil analýzu a bezchybně ji vyjádřil formou testu.

Vlastně akorát víru v dokonalost programátora nahrazujeme vírou v dokonalost testera. Tím nechci říct, že testování nepomáhá zlepšovat kvalitu, ale že 100% bezchybnost je prokazatelně** nedosažitelná.

*) s čímž tedy nesouhlasím, ale budiž

**) ačkoli bezchybný program může existovat, nemůžeme se 100% jistotou dokázat, zda nějaký konkrétní program bezchybný je nebo ne.

Satai

Spatne. O konkretnim programu lze nekdy dokazat, ze je bezchybny (pokud neverite, tak vemte trebas vypocet faktorialu, napiste si invarianty a pouzijte indukci). Neexistuje postup, jak to delat pro libovolny program.

František Kučera

Ale pořád to stojí na předpokladu, že tester pochopil zadání a napsal správně test – v tomto případě: že ví, co je to faktoriál, ovládá základy matematiky a nedělá ve svých rovnicích chyby. Můžeš tento předpoklad 100% potvrdit? Nebo je to opět jen víra?

Satai

Take musim napriklad verit, ze se mi nezdate.

should.be.irrelevant()

pokud neci argumenty neustoji ani kritiku vyplodu jeho predstavivosti …
aneb tva reakce vyvolava „obrazek“ psa jak si leha na zada a chcije na sebe.

Aleš Roubíček

Testy testuje implementace.

František Kučera

To je asi jako říct, že implementaci testuje kompilátor :-) (což je částečně pravda, ale opravdu jen částečně).

Trochu to souvisí s tím, co psal Daniel v článku: „nikdy nevěřte testu, který neselhal“.

To je dobrá rada a je dobré se jí při testování řídit (buď psát nejdřív testy, nebo si aspoň zkusit udělat v programu dodatečně chybu a zkontrolovat, že testy spadnou). Ale opět to není nic 100% – tímto způsobem otestujeme test jen na některé chyby, které v něm mohou být – rozhodně ne na všechny.

Aleš Roubíček

BTW tu větu má Dan ode mě.

Přestaňme žít v iluzorním ideálním světě a začněme chápat, že nemít 100% jistotu je mnohem lepší než mít 100% nejistotu.

František Kučera

Ale o tom tohle vlákno vůbec není. Začalo to pod větou Miloslava Ponkráce:

„neexistuje … možnost jak otestovat na 100 %, že v programu není chyba a že běží správně.“

které někteří začali oponovat. A já k tomu napsal důkaz, že 100% jistotu bezchybnosti opravdu mít nelze.

Takže bychom to asi mohli uzavřít s tím, že 1) testování je dobré, protože snižuje pravděpodobnost chyby 2) ale nesnižuje ji na 0%. OK?

David Grudl

Věta „neexistuje možnost jak otestovat na 100 %, že v programu není chyba a že běží správně.“ byl takzvaný hastroš (tedy něco, co odpůrce nikdy neměl na mysli a nic v tom smyslu neřekl), kterého následně Ponkrác polemicky vyvrátil, aby dokázal, jak se odpůrce mýlí.

Neznamy Hrdina

az na to ze ho nevyvratil ale pouzil jako odrazovy mustek …

rony

vsetko pekne pani. len teoria tu trochu nakopla prax.

oba ukackove lightboxy nefunguju na ipade. podotykam, ze som este nenasiel znamejsie obdoby lightboxu, ktore by nefungovali. a ak aj nespustia js, tak mi aspon dovolia otvorit odkaz a zobrazi sa konvencny, sposobom obrazok.

dakujem za clanok, toto je len poznamka, ze sa oplati kod testovat.

David Grudl

Po nějaké době se mi na iPadu rozchodily, ale jinak bug potvrzuji.

František Kučera

To je přesně ono – dneska lidi často napíší* jednotkové testy a myslí si, jak mají otestováno…

*) a to většinou jen jako, aby vykázali 100% pokrytí – jestli to ale skutečně smysluplně testuje, je jim jedno.

Michal Till

TDD není primárně nástroj pro quality assurance proces (ve smyslu dodání bezchybného produktu), ale *návrhový* proces. Co se kvality týče tak spíše zajišťuje, že nová verze produktu je stejně tak dobrá/stabilní jako minulá.

František Kučera

Nemluvil jsem o TDD, ale o testování jako takovém. A narážím na to, že si hodně lidí myslí, že testování = jednotkové testy.

Pepa

Lightbox je především nehorázná prasárna z hlediska UX.

František Kučera

Souhlas. Ale jak to řešit lépe, aby uživatel mohl přecházet z jednoho obrázku na druhý, zpátky, aby si mohl zobrazit všechny náhledy…?

Možná by server mohl posílat nějaké zvláštní HTTP hlavičky, kde by byl odkaz na další a předchozí obrázek a odkaz na galerii – a www prohlížeč by se pak postaral o zobrazení obrázku ve vhodném rozlišení + vykreslení tlačítek + případného pásu s náhledy atd.

Nebo by www prohlížeč mohl nějak inteligentně rozpoznat, že se jedná o galerii obrázků, a přidat tlačítka další/předchozí sám (to myslím dělá Opera).

Případně použít FTP/WebDAV/… a galerii otevřít ve skutečném prohlížeči obrázků (ne ho parodovat v HTML), klidně zasazeném do panelu www prohlížeče, nebo otevřeném v novém okně, podle přání uživatele.

Pepa

O tohle nejde. Jde o to že to „vyskakuje“ a zakrývá celou stránku. Stejnej vopruz jako klasický pop-upy, který snad už nikdo nepoužívá. Teď je potřeba odnaučit se zlozvyk jménem lightbox.

František Kučera

Tohle mi zase nevadí – když si prohlížím obrázky, tak nechci, aby mě rušily ostatní prvky na stránce.

Pepa

To máš pravdu. Jenže „prohlížení obrázků“ je zřídkakdy primární funkcí dané stránky a ve všech ostatních případech je lightbox vopruz (typicky eshop, zpravodajské weby, osobní portfolia, atd.)

Oldisy3

Prohlizec v opere stoji za prd. Kdyz se kouknu na czc a nebo alzu, oboje je na prd, v czc jdu pres x dalsich stranek a nakonec skoncim v novem okne abych mel obr pres celou stranku. na alze to same jen je tam o jednu stranku mene. princip light boxu si myslim je dobry, neopoustim aktualni stranku, takze se k ni nemusim vracet, zakryje pozadi a do popredi zobrazi obrazek tak jak se vejde no view, neroztahne se vic a kdyz sou ovladaci prvky stale na stejnem miste je to idelani.

5o

Zacilnal som s PHP a pisal som proceduralne webstranky. Teraz robim OOP s PHP a bez unit a integracnych testov si neviem predstavit continuous integration.

Unit testy mi z velkej casti nahradili debuging, nutia ma pisat jednoduchsie triedy a kazdy riadok ma presne dany zmysel, nie je priestor pre prasaciny + reporty mess detector, code violations, checkstyle atd. je neskutocna pomoc ak chcete softwer vyvijat dlhodobo.

V takomto prostredi vyzera vyvoj nasledovne: developer v SDK naprogramuje balicek s testami. Ked su u neho testy passed posle commit do repozitara. CI server potestuje balicek a urobi build balicka a ostatnych zavislych balickov. Ak vsetko svieti OK moze sa spravit release. Odkedy toto dodrzujem moj zivot programatora ma opat zmysel.

S TDD viem ze si mozem dovolit refactoring a neboli ma od strachu zaludok.

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.