Roztříštěnost JavaScriptích knihoven

JavaScript mám docela rád. Kór dnes s ES6, ES7 a Reactem je psaní SPAček radost. Dokud není potřeba využít nějakou knihovnu. To pak přestává být sranda. Původně jsem chtěl napsat do nadpisu nepoužitelnost, ale nakonec lze knihovny nějak použít. Je s tím však spousta trápení.

Jeden z příkladů může být samotný React a známé a používané knihovny. Vyšel nový React 0.14, který přinesl zajímavé featury. Především stateless komponenty. Samozřejmě, že po pár týdnech jsem se rozhodl novinek využít. Jenže problém – používám taky react-bootstrap a podpora je až od verze 0.27. O pět čísel větší než s kterou jsem web napsal. Za tu dobu samozřejmě stihli sáhnout přesně na ty komponenty, které používám. Takže jsem šel upravovat čerstvě napsaný kód…

Což ještě není to nejhorší, horší je závislost na knihovnu, která na kompatibilitu kašle. Pak jen koukáte do konzole, jak React warninguje, a doufáte, že autor knihovny to také upraví. Nejpozději do vydání nové verze, která warningy transformuje na errory. S takovou zkušeností mi přijde, že se vyplatí záviset jen na populární knihovny a zbytek si udělat sám.

Má to ještě jeden ironický důvod. Možnost výběru je zlo. Pro různé úlohy existuje bambilion různých balíků. Každý si napsal něco a řekl si „to se bude někomu hodit, zveřejním to“. Taková blbost! Nyní je těžké se v nepřeberném množství zorientovat. S absencí dokumentací (pahýly mezi dokumentace nepočítám) je pak těžké najít, co vlastně řeší můj problém. A hlavně aby taková knihovna byla udržovaná a stabilní, tedy neprefixovaná nulou.

Další extrémní příklad je pořádná výzva: ES6 a pár ES7 featur, React, JSX. Zkuste s takovou kombinací rozchodit testy. A to ještě není nejhorší varianta! S takovými AMD moduly to je ještě větší sranda. V práci jsme narazili na bug v testovací knihovně. Možnosti jsou dvě – buď se o verzi vrátit. Nebo ve světě JS je naopak vždy dostupná novější verze, takže upgradovat. To nám ale zařvalo z důvodu absence nejnovějšího Nodu. Čerstvého Node 4. Na Debianu samozřejmě není dostupný, ale ne protože to je Debian, kde jsou balíky se zpožděním, ale protože to chce nový gcc dostupný až pod Jessie. Tedy: chceš testovat JavaScript? Upgradni si operační systém. Jo a taky si to zkompiluj…


Lehce to zveličuji. JavaScript se mi líbí. Občas ale dokáže vytočit. Proto chci spíš šířit následující zprávu, která se nemusí nutně vztahovat na JavaScriptí svět (jen to pro něj patří z důvodu spoustu edge novinek dvojnásob):

Chápu, každý chce být autorem populární knihovny. Populární knihovna ale nevznikne rychlým nabastlením, zveřejněním a doufat v open source boha. Už na začátku je potřeba se ke kódu chovat jako bych ho měl maintenovat do konce života. Což znamená si dobře promyslet API hned při prvním návrhu, aby se později měnilo minimálně. Také to znamená být připraven řešit všechny use-casy. Jak by se asi používalo request-get, request-post, request-json, … pokaždé od jiného autora? V neposlední řadě řádně zdokumentovat, co vlastně moje knihovna řeší a popsat jak s ukázkami.

Databáze v testech?

Včera jsem měl na první české PyCON konferenci přednášku o pytestu. Na Twitteru se rozjela diskuze o tom, že můj ukázkový test není unittest. Což je teda úplně mimo moji přednášku, protože jsem mluvil o unittestu jako toolu, nikoliv typu testu, vs. pytestu. A integrační test jsem vybral, protože je to prostě dobrá ukázka pro běžnou praxi.

Každopádně bych chtěl sdílet můj názor na toto téma. V Twitter vlákně se řeší několik věcí – udržovatelnost takových testů, zda mít různé typy separátně, spolehlivost, schopnost najít co nejvíce chyb a hlavně teorie. A jak já rád říkám, teoreticky mezi teorií a praxí není rozdíl, ale prakticky… :-)

Samozřejmě, nejlepší možný test je unittest, který nepotřebuje nic. Žádné cizí rozhraní, žádnou databázi, žádný přístup na disk ani nikam jinam, prostě nic. Pokud něco takového lze udělat a otestuje se tím vše potřebné, pak máte vyhráno. Pak vás nemusí zajímat boj s integračními testy. I to je důvod, proč Selenium je pro puristy tak děsivé.

Jenže v praxi to tak nefunguje. V praxi často něco čteme a zapisujeme. Můžeme takovou aplikaci otestovat tak, že vrstvu zařizující komunikaci s databází či něčím jiným nějak nahradíme/vyřadíme. Jenže, co jsme tím získali? Nic moc ve skutečnosti. Máme otestované algoritmy a provázanost naší aplikace, ale vůbec nevíme, zda funguje. Mohu otestovat, že moje aplikace správně vygenerovala XML a nikam ho neodeslat. Jenže po nasazení mi mohou klidně poslat neskutečné množství uhlí

OK, špatný příklad. Ale ten příběh mne fakt pobavil. :-) Vezměme jiný příklad: chci otestovat statistiky. Ano, mohu při testování podsunout aplikaci data, která chci, a podívat se, zda se čísla přelila takhle tam, tohle zase tam, a výsledek je takovýhle. Jenže… jenže po nasazení do provozu zjistím, že v SELECTu je překlep v jednom případě. Který sice testuji, ale bez databáze.

A takhle to je se spoustou aplikací. Proto, abychom měli větší jistotu, testujeme s databází. A pokud je to pouze s databází, říkáme tomu stále interně unittest. Pokud je to unittest bez databáze, říkáme tomu pure unittest. Pokud voláme i cizí rozhraní, zapisujeme na disk, …, říkáme tomu integrační test.

Řešili jsme, jak takové testy rozdělit. Původně jsme je měli rozdělené na „unittesty“ a na integrační testy. Ale byl v tom guláš, co kde vlastně testujeme a proč. Někdy bylo prostě vhodnější nechat integrační test, někde zase naopak. Takže testování nějaké funkcionality máme v jednom souboru a rozdíl mezi testy řešíme označením pomocí dekorátoru @pytest.mark.*. Tak hned vidím všechny testy pohromadě.

A jak nám to funguje? Velice dobře. Testy máme rychlé, v průměru 125 ms na test (s tím, že to hodně zvedá především pár integračních testů kvůli účetnictví pod Windowsem). S databází nemáme problémy. Dokonce CI tool (u nás Jenkins) si pro každý běh nejprve vytvoří novou databázi (cca deset vteřin). Tedy máme pod kontrolou, co v databázi je. Najde nám to více chyb. Nespočet chyb bylo v SQLku… Nemluvě o tom, že nemusíme složitě mockovat.

Abych to shrnul: integračních testů se nezbavíme a jsou potřeba. S knihovnou unittest je těžké takové testy udržovat a měli jsme s tím opravdu problémy. Ale díky pytestu a tipům, o kterých jsem mluvil a dříve i psal, už problémy žádné nemáme, ba dokonce je to stejně snadné jako jednotkové testy.

P.S.: Omlouvám se všem puristům za zemřelá koťátka. :-)

Whisky festival 2015

Z letošního whisky festivalu jsem si odnesl několik poznámek:

Až do roku cca 1950 byla whisky bílá. Pilo se tak rychle, že v sudu moc dlouho nevydržela. Takže barva, vůně i chuť byla úplně někde jinde, než jak ji známe dnes. Když dnes takový vzorek pošlete whisky specialistům, odpoví ve stylu „to není whisky, co to je?“ Jelikož na toto téma nemohu nic dohledat, věřím John Lamondovi jen tuto část, a pokračování, že žena chtěla před mužem ukrýt alkohol, na který narazil o několik let později… mu už nevěřím. :-)

John Lamond s námi prošel šest ochutnávek a chci vypíchnout jedinou – Ben Nevis. Konkrétně jsme pili dvanáctiletou ze sudu po sherry z roku 2002. Koukal jsem, že se nedá sehnat, tak snad bude stačit jiný rok a především ze sudu po sherry. Je to podceňovaná whisky a sám, když jsem byl na whisky cestě po Skotsku, jsem byl celý den kolem ní, a vůbec ji nenavštívil. Jaká škoda. Začátek byl velmi příjemně ovocný a myslím, že by ji měli rádi i newhiskaři. Co ale na whisky mám hodně rád je finish. Tak se podle mého názoru pozná opravdu dobrá whisky. Tento Ben Nevis 12yo měl krásný dlouhý ocas s nádechem kouře a štiplavosti. Hned bych si dal zase.

Ale moc mne neposlouchejte, jelikož whisky znalec zřejmě vůbec nejsem. Letošní whisky roku vyhrála Kavalan, tak jsem ji chtěl samozřejmě zkusit, když už ji tam měli. Loni jsem poprvé zjistil, že asijské whisky mohou být opravdu dobré a Kavalan příjemně překvapila. Každopádně výherní lahev mi vůbec nechutnala. Marně jsem v ní hledal, za co vlastně vyhrála.

Aspoň příjemným překvápkem je, že Lost Distillery lze pořídit již i u nás. Prý ve Warehouse #1 kousek od Křižíkovy. Loni jsem si velice oblíbil kouřový Gerston, který chci mít doma. Od loňska navíc přivedli zpět na svět další distilerky, které stojí za to vyzkoušet.

Na závěr jsem zkusil GlenDronach 18yo (Old Allardice), která je popisována jako „výbuch chutí“ a lepší nechat na závěr večera. Rozhodně to je zajímavá whisky, kterou musím ochutnat znovu a prozkoumat všechny chutě a rozhodnout se, zda se mi to líbí, či ne. Přeci jen jsem ji zkoušel na závěr večera. :-)

Jediné vím jistě, je to další whisky ze sudu po sherry a zdá se, že krom kouřových whisky budu ujíždět i na ty po sherry. Trochu jsem se bavil na toto téma a zjistil, že sudy po sherry jsou pětkrát tak dražší, než jiné sudy. Proto to není úplně obvyklá whisky. Některé distilerky dokonce kupují celé roční výroby sherry, aby měli zajištěny sudy. Ale samozřejmě o obsah jim nejde, ten klidně někde rozdají.

Už se těším na další ročník!

Zbytečné optimalizace

Vývojáři mají skvělý dar. Optimalizovat to, co je nejvíc zbytečné. Aneb příklad z praxe. :-)

Potřebovali jsme funkci batches s následujícím chováním podporující jakýkoliv iterable:

>>> list(batches.batches(range(10), 5))
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
>>> list(batches.batches(range(10), 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

Udělali jsem tedy základní implementaci během minutky:

def batches(iterable, batch_size):
    bucket = []
    for item in iterable:
        bucket.append(item)
        if len(bucket) == batch_size:
            yield bucket
            bucket = []
    if bucket:
        yield bucket

Jenže… jenže to nevypadá sexy. Přeci to musí jít udělat nějak cool! A taky efektivněji. Například pro velký batch_size to musí být náročné. Pojďme zkusit udělat generátor generátorů.

def batches(iterable, batch_size):
    def batch_generator():
        for x in range(batch_size):
            yield next(iterable)

    while iterable:
        yield batch_generator()

Vypadá to docela hezky. Jenže to má zásadní problém. Předchozí ukázka totiž nikdy neskončí. Jakmile se dojede vstupní iterable, funkce bude generovat prázdné generátory do nekonečna. To je potřeba nějak vyřešit…

První nápad je odchytávat StopIteration. Co ale dál? Během chvilky jsme se dostali do velmi nehezkých konstrukcí a stejně zůstali v nekonečné smyčce. Kolegu napadlo si z vnitřního iterátoru předávat, zda bude něco následovat nebo ne. Idea je taková, že si první elementy ohandluju ručně nějak takto:

def batches(iterable, batch_size):
    def batch_generator():
        try:
            first = next(iterable)
        except StopIteration:
            yield False  # Hele, uz nic neprijde, tak to stopni.
        else:
            yield True  # Jasne, jeste neco prijde.
            yield first

        for x in range(1, batch_size):
            yield next(iterable)

    while True:
        gen = batch_generator()
        if next(gen):  # Prvni polozka je rucne vlozena.
            yield gen
        else:
            break

Super! Máme generátory. Generují dokonce správně. Jenže… jenže to vypadá opravdu ošklivě. Navíc je podporován jen takový vstup, který zvládne next. Zkusili jsme testy, zda jdeme dobrým směrem a… horší než jednoduchá jasná implementace! Možná to šetří pamětí, ale podstatně trpí výkon kvůli samému generování.

Tak znovu na začátek a jinak a lépe. itertools obsahují funkci groupby. S pomocí Google jsme došli k následujícímu řešni:

def batches(iterable, batch_size):
    iterable = iter(iterable)
    counter = itertools.count()

    def func(key):
        return next(counter) // batch_size

    for key, group in itertools.groupby(iterable, func):
        yield group

Vypadá elegantně, ale pokud k tomu nebude výklad třikrát tak dlouhý, jako celá funkce, nebude jasné, co se děje. A výsledek? Taky pomalejší. Výkon s groupby se od předchozího kódu moc neliší.

Závěr: neoptimalizujte. Optimalizujte až v případě, kdy je to opravdu potřeba. Raději pište čitelný kód. A pokud už bude potřeba optimalizace, ten čitelný kód nemažte – nechte ho vedle toho optimalizovaného. Aspoň budete moci rychle přečíst, co daná funkce dělá, a především zkontrolovat, zda ta zoptimalizovaná dělá skutečně to, co má.

Coders at Work: rozhovory s velikány v oboru

Pořídil jsem si knihu Coders at Work: Reflection on the Craft of Programming. Což jsou rozhovory s velikány z oboru. Chtěl jsem se tedy dozvědět nějaké jejich názory. Takový výtažek, který jsem si z toho vzal, někde i sám přidal, tu sdílím.

Začneme školou: není potřeba. Pro to, abych mohl programovat. Programátorský svět se tak rychle vyvíjí, že se musí učit neustále. Kdyby na škole záleželo, pak by se škola nikdy nemohla opustit.

V rozhovorech se řešilo i jaké má programování postavení mezi obyčejnými lidmi. Zda by se mělo zařadit mezi základní předměty jako jazyk a matematiku. Nemělo. Základní věci lze naklikat a pokročilé věci stejně nepochopí, jako programátoři si nezvládnou ušít oblek.

Taky si pamatujete, jak pracovat ve skupině bylo bráno jako podvod? Tak přesně taková je nejlepší praxe: párovat. Pomůže udržet focus na úkol. Aneb kolikrát začnete lelkovat, když se dostanete do slepé uličky a potřebujete odstup? Ten druhý má ten potřebný odstup. Jiný pohled. A tak.

Párování je dobré taky pro zaučování. Stejně jako jinde se nováček učí pozorováním mistra, aby se jím jednou taky stal, je dobré toto aplikovat i v programátorském světě. Nemusí to být nutně nováček. Spoustu lidí se naučí algoritmy atp., ale nikde se neučí jak debugovat. Což je skill, který trvá dlouho osvojit si. Párováním ho lze získat mnohem rychleji.

Pokud není dostupný nikdo do dvojice, stačí mluvit s něčím. Třeba na PyCON UK 2014 rozdávali debug kachničky. Často jen říct si, jaký mám problém, co je jeho vstupem a výstupem, stačí k jeho vyřešení.

Aby ale nebylo potřeba debugovat, Tony Hoare má skvělou frázi, že lepší mít kód, kde samozřejmě není žádný bug, než kde není žádný zřejmý bug. Nebo lépe v originále: „your code should obiosly have no bugs rather than having no obvious bugs“. Pro to je potřeba držet čitelný kód. Základem je formátovat kód, stejně jako formátujeme běžný text. Což Dijkstra podtrhává větou: „if you can't write in your native language, give it up“. Hned druhým důležitým bodem je správné pojmenování. Jsou i programátoři, kteří mají vždy po ruce slovník.

Čitelnost se pojí i s optimalizováním. Pravidlo je, zůstat u čitelnosti a neoptimalizovat. Protože často, ne-li vždy, programátoři řeší optimalizaci toho, co je cool, zajímavé, náročné. Ale tyhle části nemají žádný zásadní vliv na optimalizaci a co je skutečně potřeba, na to se nesáhne. Proto lepší zůstat u čitelnosti a až když je opravdu potřeba, teprve pak jít optimalizovat. Což má druhou výhodu – čitelnou verzi už mám a tu nesmažu. Nechám ji vedle té optimalizované. Tak bude kód čitelný a pokud se najde chyba, můžeme přepnout na pomalejší správnou. Mimochodem jednodušší je optimalizovat správný kód, než opravovat optimalizovaný kód.

Postupným vývojem ale kód tak jako tak degraduje. Když se problém zapisuje do kódu, musí se najít způsob, jak to zapsat. Jenže postupem času se problém může trochu změnit. Nebo naopak problému začneme lépe rozumět. Tím nám původní kód přestává vyhovovat a musí se upravit. Protože když se ponechá ve starém znění, kód začne být nečitelný.

Otázka je, kdy refaktorovat? Někdo říká neustále, někdo po Xtém sprintu, … Udělejte to tak, jak je potřeba. Často stačí držet se skautského „ponechám kód v lepším stavu, než jsem k němu přišel“. Někdy ale je potřeba změnit celou architekturu. To se dá poznat podle pomalosti vývoje, aplikace, bugovosti atp. Vývojáři nejsou ze dne na den horší. To jen kód degraduje a je horší ho udržovat.

Jak ale tohle vysvětlit produkťákům/klientovi? Nijak. Refaktor je potřeba si plánovat mezi běžné věci. Něco odhadnu na tři dny, tak tam šoupnu čtyři na potřebný refaktor. Pokud potřebuji velkou změnu, třeba frameworku, o čem se nerado slyší, zabalím to do jiného názvu. Třeba údržba pro zrychlení vývoje, aplikace a menší chybovost.

Není nic horšího, než když se někdo bojí sáhnout na něčí, či dokonce svůj, kód. Na to je lék testování. Testy dodávají jistotu. Čím lépe otestovaná aplikace, tím větší jistota a klid na duši.

Aby testy měly smysl, je potřeba testovat inkrementálně, stejně jako se píše kód. Nejlépe formou TDD. Často se naráží na problém, že nelze napsat test, pokud nevím, jak kód bude vypadat. To je chyba. Je dobré nejprve vědět, jak chci kód využívat, a poté napsat implementaci. Když udělám opak a zjistím, že chci nakonec používat jinak, musím celé předělat. Pokud z nějakého důvodu takto nelze, aspoň napsat kód nejvíc jednoduše, poté testy, a nakonec udělat refaktor a případné optimalizace.

Testy poslouží i jako taková dokumentace, pokud jinou nemáte. Což teda je potřeba nějakou dokumentaci mít a hlavně ji nepsat až po napsání kódu, ale už s ním. Protože jen tak zdokumentujete, co je potřeba. Za dva dny si těžko vzpomenete na všechny konstrukce, které jste napsali a hlavně proč přesně.

Někdy programátoři dokumentují pouze pokud se jedná o znovupoužitelný kód. Na něco takového zapomeňte, znovupoužitelnost neexistuje. Resp. pouze u stejných problému a často ty stejné problémy jsou již vyřešeny. Vaše aplikace bude jednodušší, pokud ji napíšete jednodušeji bez zbytečných vrstev. Líbila se mi hláška, proč OOP a použitelnost moc nejdou k sobě: „you want banana and they carry around implicit environment with gorilla holding banana within jungle“.

Je to trochu tím, že vývojáři píší kód. A když píšou knihovnu (nebo klidně i celý jazyk, podívejme se třeba na Ruby), chtějí přidat něco svého. Jenže je více věcí, které lze přidat, než věcí, které by se pouze měli přidat. Na to je potřeba cit, který má málokdo. Softwarový vývoj je hodně jiný oproti cokoliv porovnatelnému a stále se učíme jak ho nejlépe vést. I hardware se vytváří jako například stavba domu – cihlu položit na cihlu, sem dám dveře, okno.

Například na otázku „jak bude dlouho trvat tahle změna?“ máme několik možných odpovědí. Pokud je to změna na jeden řádek, víme, že máme rychle hotovo. Jenže pokud je taková změna nesystémová, víc takových hacků by znepřehlednilo kód a pozdější maintenance. Takže druhá možnost je zahrnout nějaké lepší pojmenování a refaktor okolního kódu. Tím ale pouze oddálíme čas, kdy se dostaneme do situace, jako v prvním případě. Pak je třetí možnost, že to uděláme pořádně. Což znamená úpravu zanést řádně do celé aplikace. A to musí programátoři vidět a dát odhad přibližující se poslední možnosti. Pak by nemělo dojít k nutnosti začít na zelené louce.

Nejchytřejší programátoři by neměli automaticky o všem rozhodovat. K dobrému rozhodnutí je právě potřeba ten cit. Bez empatie či emoční inteligence půjde těžko navrhnou dobrý jazyk, API, GUI apod.

Na závěr zmíním, že produkty se netočí kolem technologie, ale kolem výsledku produktu samotného. Technologie je jen prostředek. Takže je jedno, který framework nebo jazyk se použije a není třeba se kolem toho hádat. Já mám rád třeba čokoládový Häagen Dazs, vy zase jinou zmrzlinu. A taky se u toho nehádáme. :-)

Matka moudrosti: jak testovat

Nic z následujícího textu není nové. Určitě to někdo v podobném znění už někde sepsal. Ale pořád se na to naráží a opakování je matka moudrosti. :-)

Extrémní TDD říká, že by se měl napsat minimální test, počkat až selže, poté napsat minimální kód pro průchod testu, ověřit funkčnost, rozšířit test a tak pokračovat do nekonečna. Například:

  1. Napíšu test na zavolání funkce add.
  2. Test selže, protože funkce add neexistuje.
  3. Napíšu funkci add. Jen definici, aby ji šlo zavolat.
  4. Test projde.
  5. Napíšu test, že funkce vrací pro parametry 2 a 3 hodnotu 5.
  6. Test selže, protože funkce nic nevrací.
  7. Napíšu return 5.
  8. Test projde.
  9. Napíšu test, že funkce vrací správné výsledky i pro jiné hodnoty.
  10. Test selže, protože vrací stále samé číslo.
  11. Napíšu algoritmus pro běžná čísla.
  12. Test projde.
  13. Napíšu test na mezní hodnoty.
  14. Test selže.

Kvůli tomu často lidi na TDD zanevřou a buď testují špatně nebo vůbec. Aspoň mi to tak přijde. Přitom, pokud se to nevezme tak extrémně, je programování mnohem lepší. Mám totiž svoji verzi TDD: zůstávám u psaní testu předem, ale neiteruji tolik vášnivě. Testy spíš beru jako takový popis, co vlastně chci dělat. Dokumentaci, dá se říct. Ono pokud žádná dokumentace neexistuje, dá se právě z dobrých testů něco pořádného vyčíst. Můj styl je:

  1. Napíšu všechny testy, co mne na začátku napadnou, pro funkci add.
  2. Napíšu celou implementaci funkce add pod dozorem testů.
  3. Při psaní samotné funkce (či potom) dopíšu další testy, co mne při vývoji napadnou.

Nojo, jenže stále tam je ten test na začátku. Jak mám napsat test, pokud nevím co chci programovat? Otázka, kterou slýchám často. Na to snad jen, pokud nevím, co chci programovat, tak snad raději neprogramovat vůbec. :-)

Na test předem lze nahlížet jako na ukázku předem. Nejprve si tedy udělám kód jak chci asi danou funkci používat. Samozřejmě kód nebude funkční, jde jen o to podívat se, jak skutečně chci funkci využívat. Jakmile zjistím, jak chci funkci využívat, mohu začít psát implementaci. A pokud mám ukázku, upravit ji na test je už drobnost.

Tím si zároveň ušetříte práci. Udělat dobrý návrh na první dobrou vyjde málokdy. Proto je lepší se nejprve zamyslet nad použitím a podle toho udělat API. Jednodušší upravovat ukázku, než udělat celou implementaci a pak zjistit, že se to používá špatně a je třeba celé přepsat.

Dokážu si však představit situaci, kdy nejde napsat test dřív. Například při psaní Selenií. Nebo dělám prototyp čehokoliv a opravdu nemám představu, jaký výsledek bude, a nejde mi o to mít po celou dobu plně funkční kód (který z většiny stejně smažu). Pak je potřeba mít na paměti dvě věci:

  1. Test musím vidět selhat. Pokud napíšu test po kódu, musím kód naschvál rozbít, abych viděl, že test opravdu testuje. Nejde nijak jinak podchytit testy, co nic netestují, než ověřením, že opravdu selhávají. A že jsem už na takové narazil!
  2. Pokud programuji z nějakého důvodu bez testu, napíšu kód nejhloupěji, jak dovedu. Abych při pohledu viděl, že tam není chyba. Poté napíšu testy. Nakonec kód mohu zrefaktorovat a případně i zoptimalizovat. Nejvíce chyb totiž nastává při zhezčování kódu, refaktoringu či optimalizaci. Proto je dobré tuto fázi udělat až s testy.

To jest vše. Kolem testování se dá filosofovat nad více věcmi, ale tohle jsou nejpalčivější otázky, které dostávám a které jsem kdysi sám řešil. Snad jsem vám nějak pomohl. :-)

Krvavý měsíc

Na dnešek mezi třetí a pátou bylo možné sledovat zatmění, jaké se vidí jednou za hodně dlouhou dobu. Jednalo se totiž o úplněk s plným zatměním měsíce. Další takové bude až v roce 2029. Měl jsem bohužel dost oblačno, ale i tak podívaná stála za to. Než mne mraky od show úplně odřízly, zkusil jsem udělat pár fotek…

Zápisky z cest: Londýn

To jsem takhle přemýšlel, kam se jet podívat na krátký výlet. Ve sluchátkách mi zrovna hráli Piano Guys, což bylo dostatečně inspirativní. Podíval jsem se, kde mají koncerty a po vyfiltrování zbyly Paříž a Londýn. Po ověření volných míst pouze Londýn.

Pro ty z vás, kteří neví, co jsou Piano Guys:

Tak jsem koupil vstupenku, letenku a vyrazil. A nelituji. Sice v polovině koncertu jsem si říkal, že hrají sice hezky, ale showmeni to moc nejsou, naštěstí druhá polovina to celé zachránila. Bezvadně prokládali humorem a hudbou.

V několika videích mají, že skladba je poskládána z X zvukových stop. Zajímalo mne tedy, jak vlastně jejich hudba zní, když hrají na pódiu bez postprodukce. Téměř stejně! Čelista má repeater, kterým si ovládal opakování různých částí. Během chvilky tam vykouzlil přes deset zvukových stop, což jsem vůbec nechápal, jak sám zvládá. Dobře on!

Což o to, ještě více mne zajímalo, jak dlouho natáčeli video, kde běhají kolem klavíru (poslední video výše). Spadla mi brada, když začali právě takto obíhat. Živě. Na pódiu. Před mýma očima. Bez chyby.

Jsou prostě skvělí a je dobře, že neskončili u prodávání klavírů. Tak to totiž vzniklo – klavírista chtěl prodávat klavíry. Měl nápad udělat reklamní video, kde něco zahraje. Známý mu doporučil čelistu, ať to nemá tak suché. Natočili jedno video. A bylo tak dobré, že žádný klavír neprodali. Měli spoustu práce s dalšími. Rád se na ně pojedu podívat znovu, jakmile obmění repertoár. :-)


No a když už jsem byl v tom Londýně, pochodil jsem si trochu kolem. Začal jsem v Baker Street, jelikož jsem to měl blízko. Doporučuji si předem načíst pár příběhů, aby návštěva měla fakt smysl. Na detaily paměť opravdu nemám a tak jsem si neužil rekvizity tak, jak bych mohl. Ale i tak bylo zajímavé navštívit místo navržené z knih, které mám rád.

Hned jsem zapátral v paměti, jaké další velké osobnosti v Londýně jsou. Třeba Shakespeare… Šel jsem jak na prohlídku divadla, tak na samotné představení. Nezapomenutelný zážitek, který doporučuji. Sice neoplývám perfektní angličtinou a ještě k tomu se vyznat v tolika postavách hry King John mi dělalo trochu problémy, ale i tak jsem si užil herecké výkony a zpracování. Líbí se mi, jak dříve herci hráli mezi lidmi. O to víc jsem nelitoval lístkem na stání uprostřed davu. Kolem mne totiž herci normálně hráli. Úplně jiný zážitek, než klasické divadlo.

Když jsem u toho úplně jiného zážitku, další podobný pocit jsem měl z katedrály St. Paul. Normálně mne takové budovy nechávají chladné. Přeci jen jsou všechny tak nějak na jedno brdo a jsem takový ateista, že se ani nebojím, že mne Bůh potrestá. Každopádně až tam jsem zažil perfektní zvuk varhan. Jak je katedrála obrovská, zvuk se tam nádherně rozléhá a poslouchá. Jestli někdy skončím v Londýně, zajdu si tam občas odpočinout.

I vnitřek patří k těm lepším. Bohužel focení je zakázané. Aspoň dovolují fotit ze střechy okolí Londýna. A vidět, jak se téměř všude něco staví.

Ale zpět k velkým osobnostem Londýna. Jako třetí se nabízí Bond. James Bond. Toho jsem neměl v plánu navštěvovat (beztak by někde zachraňovat svět), ale beru to jako vyřízené při sledování výměny stráží u Buckinghamského paláce.

Londýn nabízí taky další turistická místa. Například London Eye, což je asi zbytečná ztráta času. Minimálně je potřeba si koupit vstupenku online, aby se nečekalo moc dlouho ve frontě.

Kolem řeky je lepší druhá strana Londýna, kde je právě zmíněný Shakespeare Globe a katedrála. Ale také Tower Bridge a Tower of London. Moc se mi líbila prohlídka provázená královniným gardistou (jestli lze takto přeložit Yeomen Warder). Škoda, že prohlídka není delší. Aspoň dvojnásobná. Vše totiž podával se skvělým britským humorem. Jasně, když jsem šel kolem jiné skupinky, slova byla téměř shodná; mají to nacvičené. Ale to jsou všechna divadelní představení. :-)

Například měl vtipné poznámky na moderní dobu s telefony neustále v ruce. Jakmile někoho viděl s telefonem, hned byl středem posměchu. Nebo se vyptával kdo odkud je. Když se ptal po lidech ze Zélandu, vítal je zpět doma. Či nabádal ženy, až budou stát u krásných drahokamů, aby se podívaly na svou ruku, poté na svou drahou polovičku, napřáhly se a daly takovou facku, jakou v životě ještě nedostal! (Nejsem holt brit a podání je sušší. Jeďte si to poslechnout osobně.)

Ano. Britské klenoty jsou dostupné každý den bez front. Bez žádného bookingu a front jsem měl možnost vidět klenoty jen tak, že jsem šel prostě kolem. Jen fotit jsem nemohl. Naše české jsem ještě neměl příležitost vidět…

Při prohlídce Tower of London jsem se taky dozvěděl, že Británie dostávala spoustu dárků od různých států. Spoustu exotických věcí, ale i zvířat. Sice nevěděli, jak se o taková zvířata starat, ale měli je u sebe a snažili se. Taková menší ZOO. Třeba afričtí sloni nebo čínský drak.

K závěru něco o Londýně všeobecně. Začnu asi dopravou. Říkává se, že motat se v Londýnským metru není žádná sranda. Osobně mi to přišlo velmi dobře zmáklé. V Praze máme možná o něco jednodušší značení, ale taky jsme oproti Londýnu vesnice. Což přináší, že v případě bydlení zde je potřeba mít práci opravdu blízko. Nad zemí se pohybovat je děsně pomalé. I když jako vyhlídková cesta dvoupatrovým autobusem je supr. Ale na skutečné cestování je lepší metro. Které bývá tak přeplněné, že si nelze ani číst. Jako alternativa jsou všude přítomné Santandery. Kola k zapůjčení za docela slušný peníz.

Což se nedá říct o zbytku dopravě. Krátká cesta z letiště do města vlakem stojí necelých 20 liber (vyplatí se vlak zabookovat s předstihem a ušetřit nějakou tu libru). Lítačka po městě (pouze centrum) na pět dní 35 liber. Vůbec Londýn a celá Británie obecně je drahé místo. Když mi přicházely pracovní nabídky s tolika cifry, donutilo mne aspoň nabídku dočíst do konce. Ale teď už vím, že by ty částky musely být ještě větší, pokud bych měl žít v Británii.

Ale mají to tam hezké. Jejich styl se mi moc líbí. Ty jejich taxíky, autobusy, budky (už se nedivím, že Doctor Who nevypadá podezřele při cestování do budoucnosti), budovy, … I styl oblékání. Takové gentlemanské místo.

Python 3.0 až 3.5

Python 2.7 se hodně používá a zřejmě nějaký ten pátek ještě bude. Přechod na Python 3 se ale nevyhnutelně blíží a při takovém přechodu se skočí rovnou na nějakou nejposlednější verzi. Momentálně to může být 3.4 či dokonce před pár dny vypuštěný Python 3.5. Říkal jsem si, co vlastně všechno takového hezkého bylo přidáno od verze 3.0 do 3.5 a nebylo backportováno? Prošel jsem si všechny změny a řekl si, že se podělím o to, co mne zaujalo.

Python 3.0: Print!

print() je funkce. S tím bude těžké sžít se. První třetí verze se objevila v roce 2009 a stále jsem se nenaučil psát závorky.

Další velká změna je, že text je opravdu text a nejde mixovat s binárními daty. Takže žádné fungování při testech a poté v provozu neustálé ošetřování výjimek UnicodeDecodeError.

Všude jsou iterátory. Žádné range vs. xrange, ale pouze range vracející iterátor. Další funkce dříve vracející seznamy také jedou na iterátorech, jako třeba map, filter, zip, … Ale pozor, items, keys apod. nad slovníkem nevrací iterátor, nýbrž view. To je zase trochu něco jiného.

super() bez parametrů!

A detail možnost rozbalit tuple s hvězdičkou: (a, *rest, b) = range(5).

Python 3.1: Vůbec nic

Vše důležité bylo backportnuto i do Pythonu 2.7. Nový Python si holt teprve sedal. :-)

Python 3.2: První featury

První krůčky k asynchronnímu Pythonu, knihovna concurrent.futures.

Konečně si nebudeme muset dělat sami řešení na cachování výsledků funkcí, aneb ať žije lru_cache!

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

>>> [fib(n) for n in range(16)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]

>>> fib.cache_info()
CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)

Ve functools přibyla ještě jedna zajímavost a to, že wraps navíc přidává __wrapped__ odkazující na původní funkci. Takže jde introspektnout, vrátit atp. :-)

OrderedDict dostal novou metodu move_to_end. Jen škoda, že opak udělali ošklivě parametrem…

Je možné mít configuráky s proměnnými díky ExtendedInterpolation. Mimochodem lze předat konfiguraci i jako slovník, což dodává proměnným ještě větší šťávu!

>>> parser = ConfigParser(interpolation=ExtendedInterpolation())
>>> parser.read_dict({'buildout': {'directory': '/home/ambv/zope9'}})
>>> parser.read_string("""
    [buildout]
    find-links = ${buildout:directory}/downloads/dist
    """)
>>> parser['buildout']['find-links']
'/home/ambv/zope9/downloads/dist'

Vzniknul modul argparse. Ten byl teda backportnut i do Pythonu 2.7. Ale chci se pochlubit, že existuje i argparsedialog (jen pro trojku).

Python 3.3: Rozjíždíme…

Je to tu. Tak kolik aplikací 3.3ka složí? :-) Slovník nemá definované pořadí. V dokumentaci bylo upozornění, že se nejedná o náhodné řazení, ale rozhodně se na to nemá spoléhat. Kvůli bezpečnostní chybě už nelze pořadí předvídat.

Nová syntaxe yield from pro delegování generatorů. Především pro to, co přijde v Pythonu 3.4, aby se později stalo v 2.5 zbytečným. :-)) Zkratka pro:

>>> for item in iterable:
...    yield item

>>> yield from iterable

Virtualenv už není třeba, součástí Pythonu je nový pyvenv, který řeší všechny problémy, které nemohly tooly třetích stran vyřešit na 100 procent.

__init__.py není povinný! Ano, NE-NÍ povinný. Jen otázka, zda je to dobrý nápad. Protože pak je možné naimportovat jakýkoliv adresář…

Pokud se odchytí výjimka a ta vyhodí novou výjimku, budou vidět obě. Často zbytečné, ale věřte, že v praxi se stávají i chyby při zpracování chyby, a pak je akorát původní chyba občas nedohledatelná.

>>> class C:
...     def __init__(self, extra):
...         self._extra_attributes = extra
...     def __getattr__(self, attr):
...         try:
...             return self._extra_attributes[attr]
...         except KeyError:
...             raise AttributeError(attr)
...
>>> C({}).x
Traceback (most recent call last):
  File "", line 6, in __getattr__
KeyError: 'x'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "", line 1, in 
  File "", line 8, in __getattr__
AttributeError: x

Přes atribut __qualname__ půjde nově zjistit přesně, kde byla funkce či třída definována.

>>> class C:
...     def meth(self):
...         pass
>>> C.meth.__name__
'meth'
>>> C.meth.__qualname__
'C.meth'

Vytváření souborů a vyhodit výjimku, pokud už existuje, půjde s novým módem x.

>>> open('/tmp/somefile', 'x')
<_io.TextIOWrapper name='/tmp/aaa' mode='x' encoding='ANSI_X3.4-1968'>
>>> open('/tmp/somefile', 'x')
Traceback (most recent call last):
  File "", line 1, in 
FileExistsError: [Errno 17] File exists: '/tmp/somefile'

datetime instance dostala novou metodu timestamp. Ale že to trvalo, že? :-)

>>> some_datetime.timestamp()
1442266005.577331

Nový hezký Pythonic modul ipaddress. Díky tomu lze zapsat například: (IPv4Address('127.0.0.1') + 42).is_private.

mock je součástí unittestu!

Je zpět u'' pro lepší port z dvojky! Není to jediná drobnost, která ulehčuje přechod na trojku. Takže pokud přechod, tak minimálně na… 3.4 (ne, to není překlep, jen dnes dřívější nemá moc smysl).

Python 3.4: Balíky, balíky, balíky, …

ensurepip je nový balík zajišťující přítomnost instalací Pythonu, i když se jedná o projekt mimo samotný Python. Jinými slovy pip po ruce po instalaci Pythonu!

Nový balík pro asynchronní aplikace AsyncIO. To je kde se využije delegování generátorů. AsyncIO je totiž na generátorech tak trochu postavené.

Vlastně až balík pathlib mne nahlodal projít podrobně, co vše v Pythonu 3.x bylo přidáno a upraveno.

>>> p = Path('/etc')
>>> q = p / 'init.d' / 'reboot'
>>> q
PosixPath('/etc/init.d/reboot')
>>> q.resolve()
PosixPath('/etc/rc.d/init.d/halt')

Třeba takový enum se bude taky hodit…

>>> from enum import Enum
>>> class Color(Enum):
...     red = 1
...     green = 2
...     blue = 3
>>> type(Color.red)
<enum 'Color'>
>>> isinstance(Color.green, Color)
True
>>> print(Color.red.name)
red

Nebo různé statistické metody v modulu statistics

Modul functools se rozrostl o další užitečnosti. První z nich je partialmethod, což dodává super nové možnosti:

>>> class Cell(object):
...     def __init__(self):
...         self._alive = False
...     @property
...     def alive(self):
...         return self._alive
...     def set_state(self, state):
...         self._alive = bool(state)
...     set_alive = partialmethod(set_state, True)
...     set_dead = partialmethod(set_state, False)

A pokud vám chybělo method overloading, pak to lze aspoň trochu dohnat se singledispatch. I když nedoporučoval bych takový přístup.

>>> from functools import singledispatch
>>> @singledispatch
... def fun(arg, verbose=False):
...     if verbose:
...         print("Let me just say,", end=" ")
...     print(arg)
...
>>> @fun.register(int)
... def _(arg, verbose=False):
...     if verbose:
...         print("Strength in numbers, eh?", end=" ")
...     print(arg)
...
>>> fun("Hello, world.")
Hello, world.
>>> fun("test.", verbose=True)
Let me just say, test.
>>> fun(42, verbose=True)
Strength in numbers, eh? 42

Občas se může stát, že se do reguláru zapomene přidat dolar nebo se při nějakých změnách vytratí atp., proto další metoda fullmatch.

Zrovna nedávno jsme řešili, že naše aplikace žere docela dost paměti a občas neúměrně moc. Chtěli jsme to pořádně zanalyzovat, ale nebylo čím. Mile mne překvapil modul tracemalloc. S ním to bude sranda debugovat. :-)

Funkce min a max požírají parametr default, řešící současné vyhazování ValueError při prázdné iterable proměnné.

Python 3.5: To nejlepší nakonec

Už žádné yield from s AsyncIO. Vznik nových klíčových slov async a await. Tedy abych byl přesný, pravými klíčovými slovy budou až od Pythonu 3.7, ale je dobré se jim vyhnout už nyní.

async def read_data(db):
    data = await db.fetch('SELECT ...')

Type hinty. Druhá velká věc, o které se hodně mluví. Za mne se moc těším na možnost sem tam vynutit typ a pomoct tak i editorům v napovídání. Vlastně nemusím, jelikož se stub fily lze využít už nyní. Ale přímo v kódu je přímo v kódu. Konečně žádné cusotm dekorátory či asserty na začátku funkce.

def greeting(name: str) -> str:
    return 'Hello ' + name

Jen se mi moc nelíbí jak se budou zapisovat nějaké složitější typy s dodávanou knihovnou typing. No, diskutovalo kolem toho spoustu chytrých lidí, tak uvidíme, jaké to bude v praxi.

Krom nových klíčových slov a type hintů se dostal do Pythonu i nový operýtor @ pro násobení matic. Známá knihovna numpy přijde s podporou ve verzi 1.10. Matematici se mohou na co těšit. :-)

>>> x = numpy.ones(3)
>>> x
array([ 1., 1., 1.])

>>> m = numpy.eye(3)
>>> m
array([[ 1., 0., 0.],
       [ 0., 1., 0.],
       [ 0., 0., 1.]])

>>> x @ m
array([ 1., 1., 1.])

Kolikrát jste potřebovali zmergovat slovník a používali pro to ne úplně jasnou konstrukci dict(first, **second)? Tak nově lze pěkně hezky: {**first, **second}. Samozřejmostí je funkčnost i se seznamy, sety apod.

A to víte, že existuje možnost zabalit Pythoní aplikaci do zipu a přímo spustit? Se zipapp už ano. Zajímavá metoda pro drobnosti, které nepatří do PyPI a je zbytečné dělat jiný, třeba debianí, balík.

configparser ještě jednou. Je možné s předáním converters přidat další get* metody.

>>> parser = ConfigParser(converters={'list': [item.strip() for item in value.split() if item.strip()]})    
>>> parser.read_string("""[section]
... value = a b c d""")
>>> parser.get('section', 'value')
'a b c d'
>>> parser.getlist('section', 'value')
['a', 'b', 'c', 'd']

Pár zajímavých věcí bylo přepsáno do céčka. Například OrderedDict či lru_cache. A spoustu dalších optimalizací přes všechny releasy, jako třeba zrychlení načtení interpretu, rychlejší dumpování všeho druhu (pickle, marshall, json), rychlejší volání get property, optimalizace podmínky s výčtem (tedy lepší psát if x in {a, b, c}), …

Mne nejvíce potěšilo…

  • Vždy přítomný pip a pyvenv
  • Možnost občas hintit typy
  • Asynchronní aplikace s AsyncIO
  • Jednoduše mergovat slovníky {**first, **second}
  • Rozbalování tuplů s hvězdičkou (a, *rest, b) = range(5)
  • Možnost předat funkcím min a max defaultní hodnotu
  • Všude iterátory
  • Cachování s lru_cache
  • Práce s cestami s pathlib

Takže… taky byste nejradši hned zahodili současný codebase a použili Python 3.5? :-)

EuroPython 2015 – poznámky

Logování

Stejně tak jsem začínal i minulé poznámky. Tentokrát jsem se však dozvěděl víc. A to to, že stále neexistuje žádný pořádný tool. Resp. existuje jich spoustu a každý umí stejnou věc trochu jinak. V základu jde o to, že není potřeba otevírat logy. Automaticky jsou shromažďovány na jednom místě a analyzují se. Vyhledávají se chyby a jiné užitečné „události“. Například pomalé odpovědi, warningy atp. Tyto události se groupují a zobrazují v hezké podobě s grafem četností výskytu. Také s možností se podívat kterým lidem událost nastála a kdy se objevila poprvé, případně naposledy.

Jenže stále neexistuje nic, co by si člověk mohl nainstalovat u sebe. Dostupné tooly fungují jako služby, což v mnoha případech není možno použít z důvodu citlivých dat. Takže tu zůstává ELK (Elastic + Logstash + Kibana), což ale „jen“ graficky zobrazí logy v prohlížeči s možností filtrovat. Tedy nutno si udělat v takovém případě vlastní řešení.

Každopádně je důležité si uvědomit, že aktuální situace na zpracování logů je stále nedostačující. Pokud nemáte problém posílat data cizí službě, běžte do toho (seznam různých možností). Pokud máte, investujte čas minimálně do ELK. Věřte mi. :-)

Type Hinty

S novým Pythonem 3.5 přijde PEP 484 – type hinty. Není divu, že o nich bylo hned několik přednášek. Ale nic velkolepého. Mohlo se slyšet o obhajobě, proč něco takového se do Pythonu vůbec zavádí. Jak to vlastně vypadá. Proč to je takové… ošklivé. A tak.

Osobně mi takové diskuze přišli zbytečné. Jasně, že type hinty jsou fajn. Však to známe z jiných jazyků. A jelikož Python je nezavádí povinně a ani na ně nebude defaultně reagovat, není ani potřeba nic řešit. Naopak spoustu starostí odpadne. Třeba nebude potřeba psát asserty. Pylint nebude mít problémy. A hlavně, což je ze všeho nejdůležitější, editory budou schopné lépe napovídat. Například PyCharm přijde s plnou podporou někdy na podzim. Pylint zase příští rok v totálně přepracované verzi 2.

OK, type hinty jsou fajn, jenže my jedeme stále na Pythonu 2.7… Za prvé, není potřeba se stydět. Za druhé, je možné psát tzv. stub files už dnes. :-)

AsyncIO

Dalším velkým tématem bylo asyncio. Přeci jen se stále jedná o novinku.

Pokud vám jde opravdu o výkon, nejvýkonnější asynchronní aplikaci napíšete ve Scale. Ale zdroják není tak pěkný. Hned v závěsu se drží Pythoní Tornádo s asyncio. A nejhůře dopadla Node.js aplikace. Podrobnosti v přednášce Better asynchronous with Tornado and Python 3.

Už kdysi jsem si hrál s asyncio v Pythonu 3.3, což je backportnutý balík z 3.4. Tak nějak mne vůbec nenapadlo, že by mohl existovat port i na nižší verzi Pythonu. U trojky mi to přišlo zbytečné a na dvojku nemožné. Ale existuje – balík trollius. Sice nemá příliš podpory ze strany knihoven, ale za zmínku stojí opět podpora Tornáda.

Sice s asyncio vypadá asynchronní kód jako synchronní, i tak potřebuje trochu změn v testech. Na což pro můj oblíbený pytest existuje plugin pytest-asyncio. Není to jediná knihovna využívající asyncio, od vydání Python 3.4 vzniklo spoustu užitečných knihoven na napojení všemožných databází atp.

Testování

Narazil jsem na velmi zajímavý tool na vylepšení pytestu – po změne kódu či testu automaticky spustit jen ty testy, kterých se změna týká. Zní to opravdu skvěle a vypadá ještě lépe. Ale jedná se o beta verzi a u nás v práci jsme to zatím nerozchodili kvůli závislostem. Počin to je i tak obdivuhodný. Balík se jmenuje pytest-testmon.

V programu jsem zahlédl ještě jednu zajímavou předášku o testování pro machine learning. Bohužel zajímavá byla pouze na papíře. Než jsme se prokousali přes úvodní slajdy, co je vlastně machine learning, nezbyl pořádně žádný čas na to, jak je možné takové programy testovat. Jen že numpy má pár vychytaných assertů. Tak i to se hodí vědět, i když žádný velký zázrak.

Balíčkování

Neustálý boj, jak vlastně distribuovat aplikaci. Buď jednoduše jako Git repozitář. Nebo přes Python balíček. Či jako skutečnou aplikaci jako debianí (či jiný OS) balíček. Jenže při debianím balíčku těžko dáme závislost na pypi. Ale opět, jako vždy, vítězí poslední možnost. Do Pythoního balíčku prostě celá aplikace nepatří. Tečka. Nesnažte se to dělat.

Naopak Pythoní balíček pro knihovny a další tooly je jako dělané. A umí spoustu věcí, o kterých pravděpodobně ani netušíte.

Na balíčkování jsem navštívil ještě jednu přednášku o pluggy. To je totiž způsob, jak funguje pytest a pluginy pro něj. Většinou nic takového nikdo nepotřebuje, ale když na to přijde… je už funkční hezké řešení. Teda, pokud nepočítám, že se jedná zatím o alpha verzi a ještě nemá ani dokumentaci. Ale to přijde! Zatím aspoň slidy.

Terminal Whispering

Jedna z mála přednášek, které se mi opravdu, ale opravdu líbily, byla Terminal Whispering. Bylo v ní totiž několik užitečných věcí:

  • Znáte pdb? Používáte? Taky znám a moc nepoužívám. Existuje vylepšenější, visuální, pudb.
  • Terminál podporuje spoustu escape sequences. Pro mne bylo novinkou možnost vstoupit do full-screen módu. Je to vidět u spoustu programů, ale stejně mne nenapadlo, že to je vlastně děsně jednoduché. A s knihovnou blessed o to víc!
  • Mimochodem zajímavá myšlenka je optimalizovat weby pro konzole. Tedy pokud přijdu na web přes telnet, mohu posílat i escape sekvence a ono to bude fungovat. Nic překvapivého ani nového, ba naopak. Ale kdo si to dnes uvědomuje? :-) Schválně zkuste telnet termcast.org.
  • Zadávání hesel se dá vyřešit pomocí shelového příkazu stty -echo. Aby to bylo v Pythonu hezčí, existuje ve standardní knihovně getpass.

Více v celé přednášce.

Transducers

Styl funkcionálního programování se mi líbí a velmi zajímá. Takže jsem se zašel podívat na workshop s transducery.

V jedné věte s big data dnes často uslyšíte napříkad Hadoop. Což jsou map-reduce joby přes několik serverů. Transducer je technika (představená teprve nedávno v Clojure), jak naopak map a reduce spojit do jednoho průchodu. Není to ale hlavní myšlenka. Důležitější je, jak jsou data zpracovávány. Zpracování dat je úplně odděleno od toho, jak se data dostávají dovnitř a ven. Pak kód na zpracování zůstává nezměnný i když data přicházejí třeba asynchronně.

Workshop začal cvičením, že funkce map a filter v Pythonu vlastně nejsou potřeba. Oboje lze zapsat pomocí funkce reduce. Na tom to celé stojí. Zbytek už jsou postupné hrátky až k finálnímu řešení, což je knihovna transducer. I přesto, že výsledek není těžké pochopit, napsat si vlastní řešení není zrovna jednoduché cvičení. Tedy za tři hodiny jsme se dostali sotva do poloviny. Naštěstí mi to stačilo na pochopení konceptu. Vám doporučuju spíš přečíst sérii článků o tomto tématu od stejného člověka.

O funkcionálním programování bylo více témat. Například blázinec zvaný Mochi, představená knihovna pyrsistent a další.


Poznámek mám víc, ale už to jsou jen takové drobnosti. A na spoustě přednášek jsem nebyl. Takže pokud chcete, podívejte se na přednášky sami. Všechny se nahrávaly. :-) A rozhodně stojí za to se podívat i na některé z Montréalu.