Zamyšlení nad tvorbou programátorské dokumentace

Aktuálně ve Forrestu revidujeme způsob vytváření dokumentace, nastavení standardů a bavíme se o tom, co a jak změnit.

Motiv je jasný - nejsme spokojeni se současným stavem a v některých případech dokonce dost zásadně. Všichni známe to staré rčení "nejlepší dokumentace je zdrojový kód", které pochází kdoví odkud (tipnul bych si, že za ním stojí eXtreme Programming, ale zdroj jsem vážně nenašel) - jenže je to omyl. Správná dokumentace může mít dost zásadní vliv na výslednou použitelnost / publicitu vašeho produktu / knihovny mezi programátory.

Kvalitní (systém) dokumentace má podle mého názoru zásadní pozitivní vliv na rozšíření např. jQuery nebo Springu. Naopak negativně se musela dokumentace podepsat na adopci Groovy. Přestože se jedná o skvělý jazyk, dokumentace je na tom, co se týká přehlednosti a detailnosti, bídně (můj subjektivní dojem).

Nuže - berme, že naším cílem je tvorba dokumentace pro další programátory (tj. nikoliv zadávací, akceptační nebo uživatelská dokumentace). Jak by měla taková dokumentace vypadat, aby byla skutečně funkční? Stačí nabrat inspiraci na Wikipedii:

Tématická

O této se my bavíme jako o slohové dokumentaci - po té sáhne nejspíš úplný nováček, který chce pochopit principy skryté za konkrétní funkcionalitou knihovny (lepší příklad tohoto typu dokumentace, než je ve Springu, jsem nikde ve své praxi nepotkal).

Bez tohoto typu dokumentace lze možná žít, ale ztěžujeme tak ostatním programátorům rychlý a správný začátek používání knihovny. Lecos je možné si odvodit z dalších dvou typů dokumentace, ale vývojářům může chybět porozumění proč dělají to, co dělají (a to je z dlouhodobého hlediska dost nebezpečná záležitost).

Tutorialy

Tento typ dokumentace nazýváme jako funkční příklady. Tj. reálná ukázka použití vaší knihovny nejlépe ve spustitelném tvaru, který si může čtenář ihned vyzkoušet (ještě lépe s ním mít možnost experimentovat). Příklad by měl být samozřejmě okomentovaný a jednoduše zkopírovatelný uživatelem. Protože to je to, co budou čtenáři dělat - kopírovat a upravovat vaše příklady. Urychlíte jim start, zjednodušíte práci a zároveň víte, že stavějí na zdravém základu, za kterým stojíte vy jako autoři. Pro ukázkový příklad bych použil služby, které na podobný účel orientují: jsFiddle pro JavaScript, Groovy Web Console a další. Pro příklad uvedu jQuery - třeba: http://api.jquery.com/last/, kde spojují tutorial s referenční dokumentací výborným způsobem (mohou si to dovolit, všechny příklady jsou velmi jednoduché).

Referenční

Referenční dokumentace opěrný bod, každého uživatele - bude ji používat úplný začátečník stejně jako zkušený uživatel (nikdo nezná všechno a je to i zbytečné). Referenční dokumentace by měla být úplná a vždy aktuální, měla by být přehledná a dobře strukturovaná. Musí být orientovaná na cílové čtenáře - tj. Java vývojářům odpovídá JavaDoc, JavaScript programátoři uvítají refereční dokumentaci v podobě, jakou má např. jQuery nebo jakou generuje jsDoc (ukázka) atp. Aby byly splněny výše uvedené podmínky, je ideální, aby byla tato dokumentace generovaná z aktuálního zdrojového kódu. Referenční dokumentace by měla pokrývat jen a pouze veřejné API knihovny.

Nyní, když jsme si rozebrali, jak by měla dokumentace vypadat, podívejme se, s čím se na cestě za dokonalostí velmi pravděpodobně setkáme:

Hrozby

Níže se snažím zachytit nejčastější vady dokumentace a zamýšlím se nad jejich možnými příčinami.

Neúplná dokumentace

Nejčastěji se setkáme s neúplnou dokumentací (nedej bože, neexistující dokumentací) - tj. dokumentací, kde některé části úplně chybí, nebo jsou nedostatečně popsané. Důvody takového stavu vám obhájí každý vývojář daného projektu - nejčastějším z nich je nedostatek času. Všichni se pachtíme za implementací fíčur a čas na dokumentaci, která žádné nové vlastnosti nepřináší, prostě není. Nikdo v rámci sprintu nezaplánoval čas na tvorbu / aktualizaci dokumentace a / nebo ji zákazník nechce zaplatit. Často také není jasně definované, kdo je vlastně za dokumentaci odpovědný (jasně, že celý tým) nebo nejsou dány jasné mantinely, aby se člověk mohl soustředit na to, CO dokumentovat a ne JAK dokumentovat (tj. bootstrap tvorby dokumentace je velmi náročný, protože daný člověk musí vymyslet celý "ekosystém").

Neaktuální dokumentace

Jako důvody neaktuální / neudržované dokumentace mne napadají: složitost vytváření dokumentace a nízká motivace vývojářů pro její aktualizaci či neautomatizované vytváření dokumentace (nebo nefunkčnost automatického procesu). Všichni si uvědomujeme, že psaní dokumentace bude vždy zátěž, která nepřináší okamžitý benefit. Tj. abychom udrželi dokumentaci douhodobě aktuální musí motivace a okamžité benefity z ní plynoucí převýšit náklady na její tvorbu. Čím víc opičí práce je v procesu dokumentace potřebný, tím výše si zvedáme laťku pro motivaci týmu.

Chybná dokumentace

Horší než chybějící dokumentace je dokumentace chybná nebo zavádějící. Často může být tento stav paradoxně zapříčiněn tím, že ji tvoříme příliš brzy - ve chvíli, kdy si systém ještě pořádně nesedl a dodatečné modifikace, refaktorizaci kódu již do existující dokumentace zpětně nepromítneme. Možná také za líné vývojáře píše dokumentaci někdo jiný, kdo není autorem algoritmů a základních principů zakotvených v aplikaci a tudíž nemá v hlavě ten správný obraz, který je potřeba ke správné dokumentaci. Dalším možným důvodem je, že vývojáři píšící dokumentaci nemají správné vyjadřovací schopnosti a jejich výstup není dostatečně srozumitelný (svěřili byste ale takovému člověku třeba komunikaci se zákazníkem?).

Nepřehledná / přebujelá dokumentace

Firmy / projekty, které si nestěžují na nedostatek dokumentace mohou mít paradoxně úplně jiný problém. Dokumentace sice existuje, ale je jí tolik nebo je tak nepřehledná, že se v podstatě nedá použít. Dřív nebo později tak začne jejich dokumentace zastarávat, protože přidávat další a další části do nepřehledné dokumentace situaci jenom zhorší a motivace k jejímu psaní se sníží pod kritické minimum. Důvodem jsou špatně nastavené procesy pro dokumentaci, strukturování dokumentace, nebo špatné technické zázemí pro její tvorbu. Nechvalně známým příkladem budiž dokumentační "šablony" některých známých českých bank, po jejichž vyplnění nemůže být čtenář o moc moudřejší, než byl na začátku (dokumentace aplikace o 10 jednoduchých pagích na 90 stránkách dokumentace - WTF! - zajímalo by mě, kolik stránek má dokumentace takového internetového bankovnictví).

Eliminace příčin vadné dokumentace

Nyní, když jsem se rozepsal, jaké špatné konce nás mohou v souvislosti s dokumentací potkat, je na čase zamyslet se, jestli a jak se dá proti jednotlivým hrozbám bojovat. Nuže, odteď jsou to již jen moje domněnky, protože jak jsem již uvedl - zatím to u nás zrovna ideální není. Snažím se tedy najít cestu, která vede podle mého názoru tudy:

Nedostatek času na psaní dokumentace

Tenhle faktor hraje jednu z nejzásadnějších rolí a je těžké s ním bojovat. Podle mého názoru není vhodné dokumentovat, pokud se nám nestabilizovalo API. S refaktorizací metod / tříd totiž v podstatě přicházíme o veškerou dokumentaci, která k nim byla vytvořená - to může vést pouze ke dvěma špatným volbám: nerefaktorizovat nebo nedokumentovat. Lépe tedy: dokumentovat ale až stabilní API.

Tím se nám tedy dokumentace posouvá na konec realizace. Aby se skutečně provedla je nutné ji PLÁNOVAT a vyhradit na ni čas už na úrovni projektového řízení. Líp se nám bude plánovat, když minimalizujeme čas potřebný na její vytvoření (využít co největší možné automatizace a vytěžení existujících dat) a zajistíme další vedlejší přínosy z tohoto procesu (viz. další kapitoly).

Složitost psaní dokumentace

Se složitostí se bojovat dá. Psát / udržovat dokumentaci je na obtíž každému, a proto stačí minimální překážka, která se postaví do cesty a výrazně snížíme motivaci k jejímu psaní. Doložím na příkladech - představte si, že pokud chcete zdokumentovat svůj kód musíte:

  • najít na sdíleném disku textový dokument, vyhledat potřebnou kapitolu a doplnit nové informace
  • otevřít analytický nástroj, doplnit a zdokumentovat patřičné modely (popř. požádat analytika o doplnění příslušných informací)
  • otevřít Wiki (nebo jinou dokumentační stránku jako je třeba Confluence), přihlásit se, najít odpovídající stránku a tu zaktualizovat

Se všemi těmito příklady jsem se osobně v praxi setkal a můžu odpovědně říct, že vedou k podvědomému odkládání povinnosti dokumentovat. Z toho důvodu docházím k závěru, že dokumentace (má-li být psaná a udržovaná) se musí nacházet co nejblíž vlastnímu kódu, ne-li přímo v něm. Ideální se mi tedy zdá pro dokumentační účely využít v co největší míře JavaDocu a zdrojů umístěných přímo v projektovém adresáři (HTML, APT atp.). Tj. vývojář by neměl mít potřebu opustit své IDE aby vytvořil nebo aktualizoval dokumentaci - pokud je k tomu nucen, je to pro něj mentální blok, který bude muset překonat (a řada jej bez přinucení nepřekoná).

S publikací dokumentace nesmí být spojené žádné další ruční úkony. Formát / umístění dokumentace a proces publikace musí být jasně daný a vývojář nesmí být nucen přemýšlet o něčem dalším, než je vlastní dokumentace kódu. Musí stačit pouze napsat odstavec v souboru projektu (JavaDoc v Java class, paragraf v HTML v konkrétním projektovém adresáři atp.) a commit do VCS.

Informace, které jsou jednoduše odvoditelné z výkonné části nesmí být potřeba opisovat znovu do jiné části dokumentace. Musí se posbírat automaticky. Uvedu příklad:

Mějme knihovnu JSP tagů - po přidání nového tagu by nemělo být nutné někde jinde v dokumentaci duplikovat tuto informaci a zavádět nějaký nový odkaz na tento tag apod. Dokumentační proces by měl být schopný přečíst TLD dodávané s projektem a vysát z něj dokumentaci, seznam vlastností atd. (buď přímo z XML nebo z JavaDocu odkazované třídy). Tj. programátor pouze zavede nový tag TLD, což z hlediska funkcionality stejně musí a zdokumentuje třídu pomocí JavaDoc. Tato informace se následně promítne i do generované dokumentace.

I v případě líného programátora se tak dokumentace drží aktuální, protože čerpá přímo z produkčního kódu. Zcela zásadně se musíme držet principu DRY, jinak to nebude fungovat.

Nízká motivace k psaní dokumentace

Nemyslím si, že je možné motivaci dlouhodobě udržet nějakými pohrůžkami nebo odměnami. Motivaci ovšem mohou zdvihnout další využití vytvořené dokumentace. Nad dokumentovanými tutoriály / příklady je možné postavit sadu testů, které zvýší kvalitu kódu mezi releasy knihovny. S drobnou prací navíc je tak možné získat i hodnotné integrační testy, které mohou výrazně snížit chybovost základních podporovaných use-case.

Důležitou roli také hraje "komunita" vývojářů. Jednak, pokud evidentně nějaká část dokumentace chybí, je třeba aby vyvíjeli tlak na autora kódu - popřípadě měli jednoduchou možnost dokumentaci sami doplnit nebo navrhnout doplnění. Dokumentace by neměla být tedy pouze v pasivním formátu, ale měla by být integrována někam, kde je možné vkládat příspěvky do diskuse, odeslat autorovi kódu návrh nového odstavce do dokumentace či možnost vytvořit vlastní ukázkové příklady použití (ideálně s testy).

Další důležitou věcí je, aby se dokumentace používala. Jenom u často používané dokumentace je šance, že se udrží aktuální, vychytají se nepřesnosti a chyby a bude nějaká motivace autorů / komunity ji udržovat a rozvíjet. Z toho důvodu musí být dokumentace rychle po ruce (ideálně z místa, kde budou uživatelé funkcionality knihovny používat, by se měli jedním kliknutím dostat k odpovídající dokumentaci).

Chyby v dokumentaci

Chybám se nedá úplně vyhnout nikde - v dokumentaci taky budou. Tím spíš u interních knihoven, kde nemáme takových čtenářů, jako má třeba Spring. Chyby jsou dvojího druhu:

  • dokumentace nereflektuje aktuální stav (zastaralá)
  • dokumentace je nedostatečná
  • dokumentace má logické chyby

Zastarávání dokumentace se lze vyhnout pouze tak, že dokumentaci aktualizujeme spolu s kódem na jednom místě. Tj. pokud upravuji kus veřejného API a vidím, že je v dokumentaci popsána původní funkcionalita (o pár řádek výš), přirozeně mi to nedá, abych spolu s kódem neupravil také dokumentaci. Prostě to bije do očí a většina lidí to tak nenechá být.

Někteří lidé jsou struční a těžko s tím něco uděláme. Tady musí zafungovat "komunitní" prvek a musí přijít někdo další, koho to bude rozčilovat a navrhne doplnění dokumentace. Takovému dobrovolníkovi nesmíme házet žádné klacky do cesty - měl by mít možnost doplnit dokumentaci jednoduše, ideálně kontaktovat rovnou původního autora a mít možnost mu poslat (e-mail by měl stačit) doplněnou dokumentaci k revizi. Jakmile navážou osobní kontakt, už se nestane, že by odvedená práce vyšla vniveč. Navíc bude mít původní autor možnost revidovat logickou správnost navrhované dokumentace a bude vidět, že jeho standardní úroveň dokumentace pro čtenáře nestačí a bude motivován ke zlepšování.

Myslím, že vývojář, který je schopný navrhovat kvalitní API, musí být schopný vyplodit i kvalitní dokumentaci k němu. Podle mého názoru to jde ruku v ruce - člověk, který neumí vyjádřit své myšlenky, těžko dokáže navrhnout použitelné API (polemizujte se mnou :-) ). K chybám tedy často dochází proto, že dokumentaci píše někdo jiný, než původní autor dokumentace, který v hlavě nenosí ten správný obraz a logické souvislosti. Vím, že si odporuji s předchozím odstavcem - proto se tam snažím vtlačit proces revize navrhované dokumentace autorem. Tady chci říct jen toto - nikdo z nás není takový lumen, aby pro něj byla podřadná nějaká práce (jako je třeba psaní dokumentace). Neexistuje podřadná práce a i ta největší esa by se měla věnovat psaní dokumentace stejně jako ti nejposlednější z týmu.

Jako závěrečný bod této kapitoly jsem si nechal verzování dokumentace. V referenční dokumentaci si můžeme pomocí nějakými anotačními nástroji (např. @since v JavaDoc) ale ve slohové dokumentaci / tutorialech je toto verzování daleko problematičtější. Historicky jsme to řešili poznámkami "na okraj", že tato pasáž "platí od verze XY" - ale celkově to vede pouze ke zhoršení čitelnosti dokumentace (pokud zrovna nejedete na poslední verzi, musíte v hlavě složitě odfiltrovávat všechny pasáže, které se vás netýkají). Z tohoto pekla jsou pouze dvě cesty - buď při releasech knihovny aktuální dokumentaci vystavit na unikátní (neměnnou) URL, nebo ji ukládat přímo dovnitř artefaktů, které jsou součástí releasu. Programátor, který potom používá konkrétní verzi knihovny použije dokumentaci z konkrétního URL (nebo přímo zevnitř knihovny) ve verzi, kterou používá. Nebude tak nutné nic odfiltrovávat, protože v dokumentaci logicky nebudou zdokumentované fíčurky, které ještě neexistují. Jediný problém, který je s tímto spojený, je ten - že někdy dojde k uvolnění nových vlastností, které se nestihnou (i při dobré vůli) zdokumentovat. Do zamrazených verzí dokumentace je potom zpětně už těžké dokumentaci doplňovat - je prostě nutné akceptovat, že dokumentace se prostě objeví třeba až v některých dalších verzích knihovny, i když reálně je daná fíčura dostupná už dříve (tady nás může zachránit automaticky generovaná referenční dokumentace, čerpající z produkčního kódu - i když ta často nemusí být dostatečná).

Špatně strukturovaná dokumentace

Tohle je místo, kde se to všechno může zvrtnout. Můžeme vyhodit desítky, ne-li stovky hodin práce na něčem, co ve výsledku nebude fungovat. V hlavě mám představu nějakého jednoduché aplikační nadstavby, která bude agregovat dokumentaci z konkrétních knihoven tak, aby autoři dokumentace už nemuseli myslet na to jak, ale co dokumentovat. Pravidla pro ně by měla být opravdu jen jednoduchá: pište JavaDoc, odkazované obrázky / dokumenty ukládejte v projektovém adresáři sem a odkazujte relativně, slohovou dokumentaci dávejte tuhle a hlavně - tady připravte příklady pro základní use-case, které svým kódem řešíte (samozřejmě s patřičnými integračními testy např. pomocí Selenia). Kašlete na styly - používejte základní HTML tagy (nebo něco jako APT), aby vás to nelákalo, hrát si s formátováním.

Ty kousky dokumentace, které takto vzniknou, se pak zpřístupní v centralizované dokumentaci, kde se na jednom místě setkají tématická i referenční dokumentace s příklady. V tomto centrálním místě by mělo být možné nad libovolnou kapitolou diskutovat, aby zapůsobil komunitní prvek při řešení problémů s konkrétními funkcionalitami (každý příspěvek v diskusi by šel e-mailem na původního autora dané kapitoly). U každé kapitoly by měl být také formulář (link otvírající e-mail klienta), který umožní komukoliv napsat návrhy na změny v kapitole dokumentace / příkladu atp. původnímu autorovi.

Funkční příklady by měly kombinovat jak interaktivní ukázku dané fíčurky, tak náhledy na důležité části kódu nebo konfigurace, která příklad představuje. Ideálně pokud by měl čtenář nějakou možnost si s kódem v sandboxu pohrát a experimentovat s jeho modifikacemi.

Dokumentace by měla "žít" - tj. mělo by v ní jít fulltextově vyhledávat, nejčastěji navštěvované části dokumentace by měly být někde vysvícené (feedback pro původní autory kódu), stejně tak by měl být přehled o nejčastěji diskutovaných fíčurkách. Příspěvky do diskusí by mělo být možné hodnotit, aby se vyselektovaly nejhodnotnější odpovědi na případné problémy (princip, který stojí za úspěchem StackOverflow).

Pokud budeme držet požadavky na vlastní dokumentaci na přirozené úrovni a minimalizujeme "omáčku", budeme mít i do budoucna trošku volnější ruce k restrukturalizaci dokumentace, pokud se nám strukturování nepovede hned na poprvé. Změny by se měly týkat pouze toho pojícího systému, ale původní dokumentace autorů by mohla zůstat (s troškou štěstí) bez nutnosti změny.

Závěr

To jsem se zase rozepsal, že? Pravda je, že jsem po našem brainstormingu nabitý nápady, které potřebují jít na papír, protože jejich realizace určitě zabere několik měsíců (už jen proto, že dokumentace je vždy až na druhé koleji). Navíc jsem si potřeboval utřídit myšlenky a psaní mi v tom pomáhá (zkuste to někdy taky ;-) ).

Z toho všeho balastu na závěr (i pro sebe) vybírám základní pravidla, které jsou podle mého názoru zásadní:

  1. dokumentace musí vznikat v IDE, přímo u kódu
  2. DRY!!! co je vytěžitelné reflexí / analýzou produkčního kódu se dokumentuje "samo"
  3. systém dokumentace musí být dán zvenčí a musí být přirozený - programátor by se měl věnovat jen lokální dokumenaci kódu, jak to dělal vždycky
  4. dokumentování musí mít vedlejší motivátory - např. jednoduché doplnění integračních testů zvedajících o řád kvalitu releasů nových verzí knihovny, možnost využití nápovědy přímo v IDE, využití sandboxovaného příkladu nejen uživateli ale i autory původního kódu k experimentování
  5. podpora komunitního efektu - navázání kontaktu uživatelů s autory, podpora kontribuce v maximální možné míře
  6. dokumentace dosažitelná na jediné kliknutí (jedinou klávesovou kombinaci)
  7. verzovaná dokumentace - nejlépe pomocí prostředků VCS a standardního release procesu
  8. jednoduché a striktní oddělení veřejného a priváního API i na úrovni dokumentace (abychom čtenáře nezahltili nepodstatnými informacemi)
  9. zprovozněná suite integračních testů, kam stačí jednoduše doplnit další
  10. sandbox pro experimentování
  11. živá dokumentace - automatizovaná detekce "toho kde to žije"
  12. dokumentují se až dokončené fíčury, vyzkoušené praxí

Části naznačeného řešení jsou již zrealizované a sbíráme zkušenosti s jejich provozem. Plno toho ovšem hotového není a celkový obrázek, jak uvedená pravidla fungují v praxi nemám. Z technologického hlediska máme většinu pravidel pokrytých (tj. víme jak na to), ale teprve život ukáže, jestli to byla správná cesta a správný způsob realizace nebo ne. Rád bych na tento článek v budoucnu navázal a popsal jak technologickou stránku věci, tak i zkušenosti, které s tím budeme mít.