Návrhové principy: DRY

Návrhový princip DRY (Don’t Repeat Yourself) nám sděluje jednoduchou myšlenku: Neopakujte se! Patří k principům z kategorie „to je přece jasné“, ale bývá často aplikován nesprávně. Pokud je ale použit dobře a s rozmyslem, ve výsledku nám pomáhá vytvářet kvalitnější kód a ušetří práci při jeho údržbě.

Seriál: Principy objektově orientovaného návrhu (12 dílů)

  1. Návrhové principy: SOLID 9.5.2012
  2. Návrhové principy: Deméteřin zákon 18.5.2012
  3. Návrhové principy: DRY 30.5.2012
  4. GRASP – 1 – Úvod a Protected variations 20.6.2012
  5. GRASP – 2 – High cohesion 2.7.2012
  6. GRASP – 3 – Low coupling 16.7.2012
  7. GRASP – 4 – Polymorphism, Pure fabrication a Indirection 30.7.2012
  8. GRASP – 5 – Information expert a Creator 15.8.2012
  9. GRASP – 6 – Controller a jak GRASP používat 17.9.2012
  10. GRASP – 7– Modelové příklady 15.10.2012
  11. Návrhové principy: Tvorba balíčků (1/2) – Soudržnost 14.11.2012
  12. Návrhové principy: Tvorba balíčků (2/2) – Závislosti a provázanost 14.1.2013

Neopakujte se! (Don’t Repeat Yourself – DRY)

Princip DRY (někdy označovaný i jako Single Source Of Truth – SSoT) tak, jak jej formulovali Andrew Hunt a David Thomas v knize Programátor pragmatik, nám říká:

Každá dílčí znalost musí mít v systému jedinou, jednoznačnou, směrodatnou reprezentaci.

Pokud se v systému nějaká informace vyskytuje na různých úrovních abstrakce nebo v různých artefaktech mělo by jedno z těchto míst být jednoznačně určeno jako směrodatné a ostatní by se od něj měly odvozovat.

Princip DRY zahrnuje všechny zdroje informací v systému od zdrojového kódu, přes datové schéma po dokumentaci. Nezahrnuje tedy pouze duplikace ve zdrojovém kódu, ale veškeré informace v celém projektu.

Protože se jedná o různé způsoby prezentace informací, je obvykle nutné pro dodržení DRY nutné investovat do nástrojů, které zajistí přenos těchto informací. Rozšířeným případem takového nástroje jsou nástroje pro tvorbu dokumentace generované ze zdrojového kódu. Zdrojový kód je zde směrodatnou reprezentací, podle které je sestavována dokumentace. Podobným způsobem se používají nástroje pro generování kódu, které například z definice SQL schématu vytvoří příslušné datové struktury.

DRY se vztahuje pouze na primární zdroje informací, které upravují lidé. Pokud je tedy například informace o struktuře databáze prezentována ve výsledném zdrojovém kódu na více místech, ale všechny tyto výskyty se automaticky odvozují z jediného konfiguračního souboru, nejde o porušení DRY.

Jako jeho protiklad DRY se používá označení WET (Write Everything Twice, We Enjoy Typing nebo We Edit Too much).

Motivace

Každý řádek kódu, který se dostane do aplikace, musí být udržován a je potenciálním zdrojem chyb v budoucnosti.

Nedodržování DRY vede k řadě problémů. Hlavní z nich je zvýšený výskyt programových chyb. Pokud programujeme stylem copy-paste-edit, je velice pravděpodobné, že původní chyby rozneseme na mnoho míst v kódu. Při odhalení těchto chyb na jednom místě a následných opravách pak můžeme některé z těchto dalších výskytů přehlédnout.

Ze stejného důvodu je kód nedodržující DRY obtížně upravitelný. Pokud se znalost prezentovaná kódem změní, musí vývojář najít všechny její výskyty a ty upravit. To je velice pracné, a pokud nějaké přehlédne, zanáší do systému nové chyby.

Dva výše uvedené problémy se pak nejvíce projeví v případě, že jste původní kód nepsali vy nebo jste jej psali již před delší dobou. V takovém případě je pravděpodobnost přehlédnutí nějaké souvislosti opravdu vysoká.

Jedním z prostředků, které jsou k dodržování DRY nezbytné, je také vytváření znovupoužitelného kódu. Snaha o dodržování DRY nás tedy vede i k tomuto.

Ne každá duplikace je porušením DRY

Důležité je upozornit, že ne každé dva úseky kódu, které jsou shodné, jsou porušením DRY. V mnoha případech může být jejich podobnost dílem náhody. 

Pokud použijeme (trochu extrémní) příklad, tak si můžeme představit, že v kódu máme úsek převádějící centimetry na metry a úsek převádějící číselnou hodnotu na procenta. V obou případech bude daný úsek kódu (téměř) identický, ale očividně byla by chyba jej extrahovat do jedné metody. V tomto příkladu je očividné, že jde o logicky nesouvisející věci. Často ale narazíme na případy, kdy to tak očividné není, což může být zdrojem neúmyslných chyb.

Podstatným hlediskem pro posuzování zda nějaká duplikace je porušením DRY je, zda dané úseky kódu spolu logicky souvisejí – zda vyjadřují stejnou informaci. Vždy se musíme zamyslet, zda podobnost úseků je dílem logické spojitosti nebo pouze aktuální situace či náhodné podobnosti.

Při snaze vyhovět DRY tak můžeme někdy mít jako nežádoucí vedlejší efekt zvyšování provázanosti. Mohlo by dojít ke spojení částí kódu, které nemají vnitřní souvislost, do jedné. Tím by vznikl problém v okamžiku, kdy by jejich náhodná podobnost přestala platit.

Dalším jednoduchým příkladem může být například používání jazykových hodnot ve vícejazyčném softwaru. Pokud použiju stejnou jazykovou hodnotu „right“ jako hodnotu pro tlačítko posunu doprava a pro označení správné odpovědi, tak v okamžiku, kdy budeme software překládat do jiného jazyka, narazíme na problém.

Ne vždy je DRY nutné/možné dodržet

Jako u ostatních principů, ani tento princip není nikdy možné dodržet zcela dokonale bez zbytečných investic. Vždy musíme pamatovat na to, že návrhové principy jsou tu od toho, aby nám ušetřily práci (s údržbou kódu). Jejich striktní a formální dodržování nám ale může více práce přidat než ušetřit. Vše je tedy nutné aplikovat s mírou. Principy dodržujte do té míry, do jaké vám pomáhají psát lepší kód, který se snadněji udržuje – ani více ani méně.

Používání generátorů kódu, které silně propagují autoři DRY Andrew Hunt a David Thomas, má smysl pouze v případech, kdy čas strávený tvorbou generátoru kódu bude menší než (předpokládaný) čas strávený případnými ručními úpravami. Jde o investici do budoucna, která má smysl pouze, pokud přinese rozumnou návratovou hodnotu. Zkušenost nám ale říká, že obvykle kód v budoucnu budeme udržovat více, než čekáme. V úvahu bychom také měli vzít fakt, že pokud investujeme do generátoru kódu, snížíme tím v budoucnosti pravděpodobnost vzniku chyb.

V některých případech (např. HTML šablony, Unit testy) je porušování DRY obecně tolerováno vzhledem k tomu, že úsilí nutné pro jejich vytvoření tak, aby DRY splňovaly, by vyžadovalo neúměrné množství práce.

V některých systémech je porušení DRY přímo vynuceno použitým jazykem. Typickým příkladem je v jazyce C nutnost duplikovat signaturu funkcí v .h a .c souborech.

Souvislosti

Hlavní myšlenky DRY je obsažena v řadě dalších návrhových principů.

Princip Once and only once  (známý z eXtrémního Programování)  je podmnožinou DRY principu. Tento princip nám říká, že:

Ve zdrojovém kódu musí být vše potřebné vyjádřeno jednou a právě jednou.

Princip Once and only once se ale na rozdíl od DRY vztahuje pouze na zdrojový kód.

Princip abstrakce (abstraction principle) je v podstatě jen jinou formulací Once and only once, která nám říká, že pokud se v kódu vyskytuje stejná nebo podobná implementace stejné funkcionality v různých částech, mělo by dojít ke vzniku abstrakce těchto částí.

Single responsibility principle zmíněný v jednom z předchozích dílů ve formulaci „Třídy by měly mít jediný důvod ke změně“ není možné splnit, pokud není dodržován princip DRY. Pokud je DRY porušeno, moduly se musí měnit i v případě, že se změní informace, kterou opakují.

Mnoho návrhových vzorů má jako hlavní cíl omezit nebo odstranit duplicity v logice aplikace. Například pokud objekt vyžaduje nějaký konkrétní postup inicializace, je vhodné toho dosáhnout použitím továrny (Abstract Factory, Factory Method) a ne tuto inicializaci opakovat. Pokud chování objektu může nabývat různých podob, je výhodnější použít Strategy, než vytvářet opakující se podmíněné bloky v jeho kódu.

Závěr

Princip DRY je založen na jednoduché myšlence. Patří sice k principům z kategorie „to je přeci jasné“, přesto bývá často porušován nebo aplikován neprávně. Jeho porušení je obvykle buď neúmyslné (nevíme, že to je již někde uvedeno) nebo vychází ze spěchu/lenosti (teď bude jednodušší to zkopírovat). Přehnaná aplikace DRY naopak může vést ke vzniku nežádoucí provázanosti částí systému.

Plný potenciál DRY je v jeho aplikaci na všechny části systému jako je například tvorba dokumentace, databázového schéma, instalačních scriptů, atd. Takovýto přístup však vyžaduje investice do nástrojů, které zajistí převod informací mezi jejich odlišnými reprezentacemi.

Pokud je princip DRY aplikován správně, nemělo by při žádné změně v systému být nutné provádět změny v jeho dalších (logicky nesouvisejících) částech. Ve výsledku nám tak správná aplikace DRY ušetří práci při údržbě a rozšiřování systému v budoucnosti.

Zdroje a další informace

Martin Jonáš pracuje jako projektový manažer v GrowJOB institute. Vystudoval Informační systémy na Fakultě informačních technologií VUT.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 5

Přehled komentářů

Martin Nuda...
Rax Re: Nuda...
maio Re: Nuda...
Jakub Vrbas Re: Nuda? Jak pro koho
Petr Vynikající
Zdroj: https://www.zdrojak.cz/?p=3663