čtvrtek 10. října 2013

Časté chyby při logování - chybějící kontext a hint

Logování (logging) a jeho výstup je mnohdy jediným prostředkem k diagnostikovávání problémů, které vznikají za běhu aplikace. Jednou z chyb, které se často dopouštíme, je chybějící kontext, který umožňuje i bez znalosti zdrojového kódu určit k čemu mohlo dojít. Budu to vysvětlovat na účelově sestrojeném kousku kódu s nákupním košíkem.

public class ShoppingCart {
  private List items;

  public void addItem(Object o) {
    if(o instanceof Item) {
      items.add(o);
    } else {
      LOGGER.warn("Object is not of type Item");
    }
  }
}

Problém té logovací hlášky je v tom, že říká jenom to co se stalo, ale to je informace, která je vám užitečná pouze pokud máte zdrojový kód a chápete důsledky toho k čemu došlo. Pokud dojde k nějakému problému, typicky o několik pater abstrakce výše, těžko se vám bude hledat příčina. Správně by ta logovací hláška měla říkat nejenom to k čemu došlo, ale i jaký to má dopad.


LOGGER.warn("Cannot add item {} to shopping basket because is not of type Item.", o);

Kromě původní informace nám do logovací zprávy přibylo vysvětlení k čemu došlo (není možné přidat položku), ze kterého plyne jasný důsledek (v košíku nebude). Pokud například víme, jak k takové situaci, došlo je dobré to rovněž zalogovat. Může to být hint, který ušetří spoustu práce.


LOGGER.warn("Cannot add item {} to shopping basket because is not of type Item. It may be caused by using an old version of client. Please check the log, version 2.0 or higher is required by add item operation.", o);

Pokud hrozí zanesení logu těmito logovacími zprávami, a vy potřebujete ušetřit místo, lze přidat vysvětlení ve formě odkazu ať již klíčem do slovníku logovacích událostí a nebo na konkrétní stránku, kde lze získat ten samý kontext.


LOGGER.warn("Cannot add item {} to shopping basket because is not of type Item. See WARN-123", o);

LOGGER.warn("Cannot add item {} to shopping basket because is not of type Item. See http://bit.ly/1g3eFoK", o);

S trochou snahy se dá velmi jednoduše vytvořit kontext, pomocí kterého i člověk neznalý zdrojového kódu pochopí k čemu došlo, jaký to má dopad a ideálně jak k tomu mohlo dojít. Nepodceňujte logování ani pokud máte vždy zdrojové kódy k dispozici. V našem modelovém případě nám hint slouží jako permanentní vysvětlení nějakého externí podmínky, kterou bychom si po nějakém čase už těžko vybavili - není přímo zřejmá z kódu vlastní třídy.


Starší články na téma logování: Pár tipů na lepší logy

pondělí 7. října 2013

Znovupoužitelnost vs. agilita

Původně jsem chtěl psát o tom, jak je důležité vizualizovat cokoliv, na čem děláte a jaký efekt měla instalace TV resp. operační dashboard s naší produkcí, ale pak mi běh událostí připomněl téma, které nosím v hlavě delší dobu. Téma souvisí to s naším inženýrsko-programátorským přístupem k znovupoužitelnosti. Tenhle článek nebude o znovupoužitelnosti kódu, lépe řečeno nejenom o něm, ale raději o znovupoužitelnosti a jejím vztahu k agilitě. O tom, že od určité velikosti organizace působí znovupoužitelnost proti agilitě. Příkladem, na kterém to chci ilustrovat je 5 různých frameworků, které používáme k testování REST API.

Zní to strašidelně, když vám řeknu, že máme 5 frameworků, každý v různé fázi užití, které používáme pro testování našeho veřejného a interního REST API. Asi je na místě vysvětlení, jak jsme se do tohoto stavu dostali. Historicky byla velká část code base napsaná v Perlu a tomu odpovídalo, že i testovací framework byl v Perlu. Nevím jestli tehdy neexistoval nějaký open source framework, a dneska je to i jedno, ale s tímhle frameworkem jsme žili od pradávna. Když jsme přibrali další jazyky, Javu a Erlang, začalo tichá revolta proti použití našeho vlastního testovacího frameworku notabene v Perlu. V programátorském světě existuje jenom málo jistot, ale jedna naprosto neotřesitelná je, že nechcete používat jiný programovací jazyk než ten váš. Jinými slovy, Perlista raději obětuje malíček, než aby napsal něco v Jave a naopak. Je to věc náboženství a přes to nejede vlak. Můžete to lidem nařídit, ale jediné čeho dosáhnete, budou v uvozovkách sabotáže a vedení svatých válek. U nás vedla tato neochota k slabému pokrytí testy.

Paradoxně nám v této situaci pomohl růst firmy, kdy se zněkolikanásobil počet vývojářů. Kromě organizačních změn musely být provedené změny v architektuře aplikace směrem k službám. V novém rozložení sil získaly týmy autonomii a bylo plně v jejich kompetenci, jakým způsobem zajistí kvalitu dodávaných služeb. Efektivně přestalo platit omezení, že je tu jedná technologie, kterou musejí všichni používat na testování, ale místo toho začalo platit pragmatické use right tools for right things. Různé týmy začaly pracovat na vlastní strategii pro testování. Tím jsme se dostali do stavu, kdy sice máme několik testovacích frameworků, ale výrazně se zvýšilo pokrytí automatickými testy a dokonce ochota ty testy psát.

Je na místě otázka proč to celé nekoordinovat, proč neudělat jeden testovací framework, který by vyhovoval všem a ten znovupoužít. Kromě dogmatického odmítání cizích jazyků, o kterém jsme už psal, tu jsou i čistě pragmatické důvody. Jak dlouho by trvalo vytvoření takového frameworku a jak vůbec zajistit, aby vyhovoval všem? Odpovím protiotázkou, je lepší mít 5 testovacích frameworků vzájemně si duplikujících část funkcionality s 50% pokrytím testy a nebo strávit půl roku návrhem a implementací univerzálního frameworku s 5% navýšením pokrytí testy? Osobně si myslím, že první možnost není sice optimální, ale daleko lepší než ta druhá.

Podle mých zkušeností nefungují infrastrukturní projekty, které se designují od zeleného stolu. Možná je to tím, že ty týmy neumí spolupracovat agilně a zaměřují se na detailní specifikace, které jsou nekompletní. Každopádně výsledkem bývá frustrace všech zainteresovaných. Na druhou stranu: protože jsem ještě neviděl černou labuť, neznamená to, že neexistuje.

Vývoji software se nejlépe daří v podmínkách kopírujících pravidla volného trhu. Dejte lidem svobodu - nesvazujte je pokud možno regulacemi - a dopřejte jim možnost volby - odpovědnost spojená s možností dělat rozhodnutí. V takových podmínkách vznikají řešení, která si sice mohou vzájemně konkurovat, ale dříve nebo později vyplavou na povrch ty nejlepší. Proto věřím, že těch našich pět frameworků se postupně setřese na dva hlavní, které se stanou mainstreamem pro zbytek firmy. Obrovskou výhodou tohoto přístupu je fakt, že vzniká ze spodu od reálných uživatelů (mimochodem jeden z rysů Agile vývoje) přirozeným výběrem, nikoliv Big Up Front Designem. Agilita, i za cenu určité neefektivity, by měla mít přednost před předčasnou optimalizací v podobě zavádění znovupoužitelných One Size Fits All řešení.