Blind trust in best practices

5 min

Až příliš často slýchám programátory říkat něco jako: „Musíme udělat X, protože X splňuje best practices.“

Konkrétně třeba:

  • Zvolme tuto variantu, protože splňuje single responsibility princip
  • Logika do controlleru nepatří, protože to není v souladu s MVC
  • Musíme psát více unit testů, protože **ukazuje na obrázek** takhle vypadá testovací pyramida
  • Nesmíme použít singleton, protože je to antipattern
  • Musíme dělat retrospektivu, protože to říká Scrum

Programátorů, kteří používají „best practices“ tímto způsobem bez hlubšího zamyšlení, je neuvěřitelně mnoho. A nejsou to jen junioři – právě naopak: často jde o seniorní programátory, kteří mají pocit, že nastudovali mnoho knih a článků, a mají tedy právo používat „best practices“ jako argument pro svůj názor.

Proč jsou best practices problém?

Programování je složité a programátoři často hledají jednoduchý návod, který jim řekne, co mají dělat. Problém je, že existuje jen velmi málo univerzálních pravidel a best practices, které lze aplikovat vždy a všude. Technologie se navíc neustále vyvíjejí a to, co jste se naučili před pěti lety, může být dnes zastaralé.

Pro ukázku představím tři best practices, které nejsou tak užitečné, jak si mnozí myslí:

  1. Testovací pyramida - není univerzální, je špatně definovaná a mnoho lidí s ní nesouhlasí
  2. Single responsibility principle - je nejasně definovaný a i sám autor musel svou definici upřesnit
  3. Growing Object-Oriented Software Guided by Tests – sice nejde o jedinou best practice, ale o knihu, která inspirovala mnoho lidí ke zhoršení jejich kódu

Všechny tyto body rozeberu do hloubky na konci článku. Teď je ale důležité následující:

Jak správně používat best practices?

Best practices mají své místo a mohou být užitečné, ale jsou spíše vodítkem než pravidlem. Vždy je potřeba zhodnotit konkrétní situaci a posoudit výhody i nevýhody daného přístupu.

Obecně byste se měli vyhnout argumentu typu „udělejme X, protože to říkají best practices“, protože tím nepředkládáte žádné skutečné argumenty a pouze se dopouštíte argumentační faulu – apel na autoritu.

Diskuse dvou programátorů

Ukážeme si diskusi dvou programátorů – jednu s argumentačním faulem a druhou konstruktivní.

Programátor A napíše následující kód:

public class UserService
{
  public void RegisterUser(User user)
  {
    // logika pro registraci uživatele
    Logger.LogInfo("User registered: " + user.Name);
  }
}

Programátor B se na to podívá a řekne: „Takhle nemůžeme používat Logger. Logger je singleton a singleton je antipattern. Musíme použít dependency injection.“

Programátor B nepředložil žádné reálné argumenty, pouze se odvolal na best practice. Aby byla diskuse konstruktivní, musí programátor B přijít s konkrétními důvody, proč je lepší použít dependency injection, například:

  • Singleton nemůžeme v testech snadno nahradit (mockovat).
  • Dependency injection zviditelňuje, s jakými závislostmi objekt pracuje; singleton je prakticky skrytá závislost.

Programátor A se pak může bránit a diskuse se stává věcnou.

Proč jsou best practices problém?

Pojďme se podívat na několik „best practices“, které jsou mnohem zavádějící nebo komplikovanější, než si většina programátorů uvědomuje.

1. Testovací pyramida

Testovací pyramida má naznačovat, jaký poměr unit testů, integračních testů a UI testů bychom měli v aplikaci mít. Na internetu najdete nespočet článků a referencí, které na ni odkazují.

Testovací pyramida ale není tak užitečná, jak se často tvrdí, a to z několika důvodů:

  • Není přesně definovaná.
  • V mnohých situacích prostě neplatí.
  • V posledních letech ji nahrazují jiné modely.

Nepřesná definice

Testovací pyramidu poprvé prezentoval Mike Cohn v knize Succeeding with Agile. Originální pyramida vypadala takto:

test pyramid original
test pyramid original

Vy ji ale pravděpodobně znáte takto:

test pyramid
test pyramid

Pokud máte hlubší znalosti testování, okamžitě vás napadnou otázky:

  • Je rozdíl mezi Service tests v originální pyramidě a integračními testy ve „standardní“ verzi?
  • Integrační testy i unit testy jsou samy o sobě pověstně špatně definované. Testuje integrační test více tříd bez DB? Nebo jednu mikroservisu? Nebo více mikroservis?
  • Unit testy jsou také nejednoznačně definované – testují jednu metodu a všechny závislosti mockují? Nebo mohou testovat více metod naráz a mockují jen externí služby?

Všimněte si, že testování více tříd naráz může být pro jednoho integrační test a pro jiného unit test. Tato rozdílná interpretace vede k rozdílnému výkladu celé pyramidy.

(Ne)univerzálnost testovací pyramidy

Snadno najdeme aplikace, kde testovací pyramida nedává smysl. Obvykle jde o systémy, které jen přesouvají data z jednoho místa na druhé a neobsahují složitou logiku.

Příkladem mohou být IFTTT platformy (If This Then That), které pomocí jednoduchých pravidel propojují různé služby a aplikace. Například: když přijde e-mail s předmětem „meeting“, vytvoř událost v kalendáři. Primárním účelem těchto platforem je integrace, a tu je potřeba otestovat integračními testy.

IFTTT není jediný příklad. Obecně existuje mnoho aplikací, které pouze přesouvají data a neobsahují logiku, kterou by dávalo smysl testovat unit testy.

Moderní varianty testovací pyramidy

Programátoři ve Spotify tvrdí, že testovací pyramida není vhodná pro mikroservisy, a navrhují „testovací úl“:

test honeycomb
test honeycomb

Na frontendu Kent C. Dodds představuje „testovací pohár“ jako náhradu:

test trophy
test trophy

Martin Fowler pak usměrňuje tuto diskusi článkem Many shapes of tests, kde tvrdí, že všechny tyto varianty jsou v podstatě totéž a liší se pouze definicí unit a integračního testu.

Nejsem si jistý, zda s Martinem Fowlerem zcela souhlasím, ale pro účely tohoto článku to není podstatné.

Testovací pyramida jako best practice

Jak vidíte, kolem testovací pyramidy panuje mnoho nejasností, nepřesných definic a různých interpretací.

Nemá tedy smysl říkat: „Testovací pyramida je best practice a musíme se jí držet.“

2. Single responsibility principle

V minulosti jsem napsal celý článek o tom, jak je Single Responsibility Principle nejasně definovaný a přináší více problémů než užitku.

Programátoři jej běžně používají jako argument, ale většinou neznají jeho správnou – moderní – definici, což vede k naprosto chybnému použití.

3. Growing Object-Oriented Software Guided by Tests

Možná jste slyšeli o relativně populární knize Growing Object-Oriented Software, Guided by Tests od Stevea Freemana a Nat Pryce. Na Amazonu má hodnocení 4,5 z 5 a skoro 300 recenzí. Možná vás tedy překvapí, když řeknu, že jde o jednu z horších knih o programování.

Vladimir Khorikov má skvělý rozbor této knihy na svém blogu.

Velmi stručně shrnuto: autoři v knize prezentují praktiky, které mohou přímo vést ke zhoršení kódu. Osobně mi kniha trochu připomíná Enterprise Hello World a programování v Javě kolem roku 2005, kdy nebylo možné napsat jediný řádek kódu bez komplikovaného patternu.

Mnoho lidí si tuto knihu přečetlo a poté hlásalo „best practices“, které v ní našli.

Další příklady

Mohl bych pokračovat dál a dál, ale myslím, že tyto tři příklady stačí k tomu, abyste si uvědomili, že best practices nejsou univerzální a často mají plusy i mínusy.

Závěr

  • Vyhněte se slepé důvěře v best practices a vždy zvažte jejich výhody a nevýhody v kontextu vašich projektů.
  • Vyhýbejte se argumentaci typu „protože to říkají best practices“ – místo toho předkládejte konkrétní, věcné důvody.