21. listopadu 2012

Nesouvislé rozjímání programátorovo

TL;DR: Tak takhle to dopadne, když shrnete nesourodé osobní poznámky o vlastní profesi do jednoho blogpostu. Asi by stálo za to některá z témat rozvést do detailu a zmenšit tak riziko nepochopení, ale to bych se dopustil seriálu. A to by nešlo.

Jazyková konvergence

Ve vývoji programovacích jazyků je možno vypozorovat určité vzory a módní vlny. Tak, jak každý jazyk svého času musel převzít prvky OOP, v posledních letech jazyky povinně přejímají funkcionální prvky, pokud už rovnou nejsou jako důsledně funkcionální navrhovány. Naopak mluvit o OOP je už dnes více než nemoderní.
Postupem času je díky tomuto sbližování vlastně skoro jedno, v jakém jazyce právě programujeme. Nedostatečné pohodlí, jež bylo vždy důvodem k přechodu na modernější jazyk, postupně ztrácí svou motivační sílu.

Oslavujeme návrat C++. Podporou lambda funkcí, přidáním for_each a dalších mnoha syntaktických sladidel se z C++11 stal opět atraktivní a vysoce efektivní nástroj, k němuž není ostuda se vrátit.
Nelze ignorovat ani současnou velkou emancipaci JavaScriptu coby univerzálního jazyka -- V8, Node.js a desítky nových javascriptových knihoven a frameworků tvoří životaschopný ekosystém. Tento trend je bohužel provázen snížením zájmu o klasické skriptovací jazyky. A tak možná časem, velice zvolna, opustíme Ruby ve prospěch Coffeescriptu, podobně, jako jsme před mnoha lety opustili Perl ve prospěch Ruby.

Jednoduchost

Ne, nemám teď na mysli minimalismus v návrhu UI, jednoduchost UX ani jiných vnějších aspektů softwaru. To, co mne zajímá, je redukce vnitřní složitosti systému.
Kdo se touto problematikou někdy zabýval, ví, že není snadné se shodnout na tom, co je složité a co není, natožpak na tom, jak složitost měřit a jak se s ní vyrovnat. Dle mého názoru lze lokální složitost na úrovni zdrojového kódu odhadnout jednoduše podle počtu prvků na dané úrovni hierarchie AST. Mnoho řádků či příliš úrovní vnoření v metodě? Metoda je složitá a vyžaduje rozdělení do dvou či více jednoduchých metod. Příliš metod ve třídě? Třída je složitá a měli bychom ji rozložit. Atd. Samozřejmě, že takto vnímaná jednoduchost jde občas proti výkonnosti.

Stále více se přesvědčujeme o tom, jakou sílu má stručnost. Počet chyb je úměrný množství napsaného kódu, proto je důležité psát kódu co nejméně, být co nejvíce DRY, používat knihovny, frameworky, obecně pak jakékoliv páky (leverage) usnadňující vývoj. Práce programátora dnes stále více vyžaduje hledání (těchto pák a jejich nejlepších kombinací) a méně vlastního psaní kódu. Mnozí si toto téma uvědomují.

Cena frameworku

Frameworky nepochybně usnadňují programátorům život. Avšak nic není zadarmo. Zvládnutí nového frameworku vyžaduje pochopit nové koncepty, naučit se významy mnoha symbolů. Objevuje se nový typ chyb -- mylné předpoklady programátora o frameworku a mylné předpoklady tvůrců framevorku o potřebách aplikačních programátorů: Pokud děláme to, co si tvůrci frameworku představovali, že budeme dělat, je vše v pořádku a vývoj je rapidní. Problém nastane, jakmile potřebujeme udělat něco netypického, což je časté u netriviálních projektů. To vede k frustraci a neelegantním řešením.

Příkladem je Ruby on Rails. Svého času elegantní framework, jenž znamenal revoluci ve vývoji webových aplikací a inspiroval řadu následovníků, potkala známá nemoc úspěšných projektů -- nabobtnání funkcemi (feature bloat) a přílišný politický důraz na defaultní konvence. Alternativu sliboval Merb, ten byl ale vlastními tvůrci obětován právě ve jménu povzbuzení poněkud upadající popularity Rails. Nyní se použitelnou náhradou -- pokud chceme zůstat u Ruby -- jeví Sinatra či Padrino. Na dveře ale klepou nové frameworky napsané v JavaScriptu (např. Tower.js).  

Ideologie vs. pragmatismus

Moderní metody SW vývoje urazily dlouhou cestu. Extrémní programování bylo svého času vnímáno jako příliš extrémní. Nálepku agilní už dnes projektoví manažeři strávit dokážou, přestože jde vlastně stále o ty samé techniky. Největším přínosem, kromě průběžné integrace, je důraz na testování (TDD/BDD) a společné vlastinctví kódu (ať už párově naprogramovaného nebo efektivněji zrevidovaného kolegou).

Ohledně metod vývoje v týmu se stále vedou svaté války. Např. oponenti TDD argumentují tím, že psaní automatických testů stojí čas, aniž by si uvědomovali, že díky němu vzniká robustní kód hned od samého začátku a redukuje se tak odstraňování chyb v pozdějších fázích vývoje. Na druhou stranu ale nelze brát na lehkou váhu argument o často obtížném izolování (decoupling, mocking) testovaného kódu od okolního světa. Čím výše ve vrstvách systému se nacházíme, tím dražší je vytváření unit testů.

Pravidla programátorům pomáhají, ale mohou i škodit. Zaslepený důraz na dodržování jednou přijatých metod je pošetilé. Každý projekt má své specifické požadavky, svět kolem nás se rychle mění a není rozumné rigidně trvat na stejných pravidlech vždy a všude. Setkáte-li se s argumentem, že se "to tak přece dělat," je dobré se zeptat, proč vlastně.  

Vnější motivace

Programování nás buď žíví nebo baví, nejlépe obojí. Vnější motivace je pro každého programátora nesmírně důležitá: Náš software používají lidé, kvůli nim ho píšeme. O úspěchu každého projektu nakonec rozhodne výsledek vnímaný okolím, nikoliv elegance kódu či neotřelost použitých technologií.
Komerční vývoj navíc klade zásadní důraz na efektivitu vývoje a využívání existujících řešení. Každá hodina programátora se počítá a někdo ji nakonec zaplatí. To v důsledku vede k tomu, že dlouhodobé projekty jsou z principu "neplánovatelné." Jakýkoliv časový odhad doby práce např. nad tři měsíce vede automaticky k tomu, že se každý normální stakeholder osype, jakmile si spočítá celkovou cenu vývoje. Projekt musí být hotov ještě včera a není vůbec důležité, že ještě ani přesně nevíme, co vlastně chceme vytvořit. Obrana vývojářů je pak jednoduchá: Definují první fázi tak, aby jejich -- jakkoliv zjednodušený -- výstup spatřil světlo světa za týden a potvrdil zadavatelům, že "je to celé možné napsat." Co naplat, že vývoj pak trvá ještě další dva měsíce navíc, což je daň za nedostatečnou up-front analýzu. Důležitá je vazba mezi vykonavateli a zadavateli (vzájemná důvěra), jež vzniká jedině agilními iteracemi. Že je tato inkrementální cesta "mnoha sprinty k cíli" často pomalejší než trasa pro poctivé maratonce, pak nakonec nikoho nezajímá.

Za zvláštní zmínku stojí časové odhady, k nimž jsou vývojáři nuceni. Schopnost odhadovat nároky se s rostoucími zkušenostmi programátora zlepšuje, zároveň ale často roste i jeho nechuť k provozování tohoto věštění z kávové sedliny ("Kdy? Až to bude hotové"). Tento problém má hlubší příčiny: Čím menší je přínos projektu, tím větší je snaha o jeho kontrolu.

Vnitřní motivace

Programujeme často i tehdy, když to po nás nikdo nevyžaduje. V tom případě máme vlastní důvody, proč trávit nad editorem dlouhé hodiny -- především se učíme novým technologiím, jazykům a knihovnám stylem hands on. Nebo si ověřujeme předpoklady, píšeme pilotní experimenty, chceme udělat někomu radost, předvést, co dovedeme, přispět open source komunitě, chceme změnit svět pomocí vlastního startupu, atd. Nebo jen proto, že se nám chce.

Zvláštní je, že pod vlivem vnější motivace často narůstá i motivace vnitřní. Možná tak kompenzujeme svou potřebu "dělat si věci po svém," jestliže tato zůstává nenaplněna. Není nám líto refaktorovat kód k naprosté dokonalosti, nejsme líní hledat chyby v cizí knihovně či trasovat framework jen proto, abychom ho pochopili. Vniřní kvality systému, jako jsou jednoduchost, elegance a konzistence, jsou pro nás zásadní, když si to můžeme dovolit. Můžeme si dovolit i "neefektivní" metody vývoje. Můžeme si dovolit být nekompromisní. Můžeme si dovolit sledovat dlouhodobé cíle.

A můžeme se přitom královsky bavit.