Princip DRY (Don't Repeat Yourself)
Princip DRY (Don't Repeat Yourself) vyjadřuje obecný princip neopakování se. Princip se dá aplikovat v mnoha oborech lidské činnosti. Z pohledu informačních systémů dostáváme definici:
Každý poznatek systému musí mít jedinou, jednoznačnou a určující implementaci.
Princip DRY nebo také DIE (Duplication Is Evil - Duplikace je Zlo) a jeho dodržování patří mezi základní hygienické zásady dobrého programátora. Nedodržování tohoto principu vede ke kódu typu WET (We Edit Terribly | Too much) - Editujeme strašně | příliš mnoho. V některých systémech a technologiích je porušování DRY běžné - HTML stránky, kód unit testů. Přepisování tohoto kódu podle principy DRY by bylo v tomto případě pracné a málo užitečné. V případě objektového programování je však dodržování principu DRY nezbytné a z dlouhodobého pohledu kriticky důležité.
V tomto článku si ukážeme, jaké zhoubné důsledky může porušování DRY principu přinášet. Podíváme se také na typické příčiny porušování a na techniky, které nám naopak jeho dodržování usnadní.
Důsledky porušení principu DRY
Každý z níže uvedených důsledků znamená navýšení pracnosti a nákladů projektu, vystresování programátora a obvykle i útok na vývojářovo lybido.
Zvýšený výskyt programových chyb. Nedodržení jednoznačnosti při implementaci jedné a té samé znalosti v systému vede ke množení podobného kódu a tím pádem i k nárůstu počtu chyb. Pokud duplikujete implementaci, je dosti pravděpodobné, že jste zduplikovali i programové chyby. Sémantické programové chyby se objevují rády při použití nulových a hraničních hodnot vstupních argumentů, v případě netradičních postupů a případů užití. V okamžiku, kdy se chyba projeví (a doufejme, že ji objevíte vy, případně tester, ale nedostane se až do produkčního prostředí), začnete s tradičním procesem ladění. Většinu chyb se v konečném čase podaří odladit. Ale v duplikovaném kódu musíte ladit na více místech a může se stát, že na některou z mnoha implementací stejné záležitosti stejně zapomenete. A to si pište, že se každá neodladěná chyba projeví v tu nejméně vhodnou dobu.
Pokud píšete jednotkové a integrační testy, jste nuceni duplikovat také kód testovacích tříd.
Problematická optimalizace a hledání úzkých hrdel systému. Nejen programové chyby ztěžují vývojářům život. Problematický návrh a implementace se projeví v neschopnosti dodržet výkonnostní požadavky na systém. Představte si situaci, kdy máte v programu tři metody, které implementují neefektivně identickou logiku. Vnější pohled na systém indikuje pomalost a vy chcete najít úzké místo - bottleneck. Použijete profiler a dostáváte statistiky volání jednotlivých metod. Počet vyvolání a celkový čas, převedený na procentuální podíl v běhu ke zbytku systému. Naše tři metody jednotlivě nefigurují v hitparádě pomalosti úplně nahoře. Ale v případě, že byste jejich logiku sloučili do jedné metody, rázem by byla favoritem na nejvyšší příčky. Tímto způsobem došlo k rozmělnění informací a jejich ukrytí. Optimalizace aplikace, které porušuje DRY může být hodně problematická.
Snížení čitelnosti kódu. Čitelný kód se lépe udržuje a ladí. DRY princip napomáhá zvýšení čitelnosti kódu. WET jej naopak toxikuje. Změna programátora starajícího se o příslušný subsystém napsaný s dodržením zásady DRY není kritická. Pokud si firma opečovává "senior" programátora, který jediný rozumí tomu, jak je stěžejní funkce systému implementována, je dost pravděpodobné, že tento programátor produkuje nesrozumitelný WET kód. V tomto případě by mělo být s dotyčným zahájeno kárné řízení a kód by se měl zavčasu přepracovat.
Problematická refaktorizace. Refaktorizace je denní chleba každého vývojáře. Pokud někdo říká, že nepotřebuje refaktorizovat je buď geniální programátor, lže nebo neví, co refaktorizace znamená. Pak je tu možná ještě jedna smutná varianta - používá IDE, které refaktorizovat neumí (bohužel znám z vlastní zkušenosti :-). Například jedna z refaktorizačních technik umožňuje z jednoho místa přejmenovat vlastnost třídy. Její název neodpovídal přesně jejímu významu, proto jste použili refaktorizaci a všechny reference na tuto vlastnost se nám automaticky upravily. Pokud jste nedodrželi DRY zůstalo Vám několik míst v kódu, kde se refaktorizace logicky projevit nemohla.
Snížení robustnosti systému. Robustností systému se v tomto případě rozumí stabilita systému v případě pozdějších zásahů do jeho implementace. Možná máte kus kódu typu pandořina skříňka, do kterého se bojíte zasáhnout, protože absolutně netušíte, kde všude se může chyba projevit. Možná Váš kód porušuje DRY a zřejmě i další principy dobrého návrhu kódu. Pokud například duplikujete logiku pro vyhodnocování oprávnění přístupu uživatele k nějaké entitě systému (např. bankovní účet) dostáváte se při budoucích úpravách do nepříjemných situacích. Ztrácíte pevnou půdu pod nohama a je otázkou času, kdy se stane něco hodně nepříjemného přímo v produkčním prostředí.
Příčiny porušení principu DRY
"Urychlující" programovací techniky označované jako Clone And Modify Programming nebo ekvivalenty Cut And Paste Programming, Copy And Paste Programming, Snarf And Barf Programming, RogueTile, Rape And Paste Programming. Pokud je na programátora kladen jako nejzásadnější požadavek rychlý vývoj, méně zkušení programátoři podléhají panice a uchylují se k těmto technikám. Místo jednoznačné parametrické implementace ve třídě, která by za implementaci měla mít zodpovědnost, vytváří implementační klony, které pouze mírně zmodifikují. Nárůst pracnosti je však v blízké budoucnosti výrazně vyšší, viz. důsledky.
Špatná komunikace ve vývojovém týmu. Pokud vývojáři a návrháři nedokáží mezi sebou efektivně komunikovat, dochází k duplicitám z důvodu neochoty hledat společné řešení.
Neexistující nebo špatná vývojářská dokumentace. Důsledkem je horší orientace vývojářů ve struktuře systému a neznalost existujícího aplikačního frameworku. I přes snahu dodržet všechny zásady dobrého návrhu v rozsahu působnosti jednoho vývojáře dochází k neúmyslné duplikaci funkcionality tříd systému přes více subsystémů spravovaných více vývojáři.
Nezkušenost. Vývoj software je o zkušenostech, které získáváte po celou dobu Vaší praxe. I absolvent s červeným IT diplomem při nasazení na první reálný projekt neprodukuje optimální kód. Problematické však je, pokud WET kód produkuje programátor s dlouhou praxí. Na to platí pouze zlaté pravidlo "poučit se z vlastních chyb".
Preventivní techniky
Návrhové vzory. Návrhové vzory jsou reakcí na potřebu standardizovat implementaci typických problémů. Znalost návrhových vzorů by měla být součástí vzdělání každého profesionálního objektového vývojáře. Vzory Vám pomohou v případě vytváření instancí tříd (Creational Patterns), definici vzájemných vztahů tříd (Structural Patterns), pravidel jejich chování (Behavioral Patterns) a v mnoha dalších. Návrh by měl předcházet vlastní implementaci. V případě dobrého návrhu minimalizujete následné riziko duplicit v kódu.
Refaktorizace. Zjistili jste, že se Vám v kódu vícekrát objevuje podobný blok kódu? Chyťte příležitost za pačesy a odseparujte opakující se kód do samostatné metody. Máte pocit, že jste třídu nebo jejího člena pojmenovali nevhodným způsobem, který klienta této třídy zmate a dojde k nepochopení pravé logiky? Ihned jej přejmenujte. Napsali jste třídu nebo metodu, která porušuje pravidlo jedné zodpovědnosti - dělá více věcí najednou? Refaktorujte ji na více menších tříd nebo metod.
Revize kódu (Code Review). Tato technika je zaměřena na kontrolu již existujícího kódu. Obvykle se provádí nejpozději před samotným vložením vyvíjeného kódu do produkčního kódu. Pro aplikaci této techniky musíte být alespoň dva. Autor kódu a ten, který kód reviduje - připomínkuje. Autor kódu by měl kódem provázet a vysvětlovat, proč implementoval problém právě takto. Revizor pak upozorňuje na problémová místa. Je běžné, že autorovi kódu začnou některé problémy samy docházet už jenom tím, že je popisuje nahlas někomu jinému. To je dobrá varianta. Horší je, pokud nikdo z účastníků problém neobjeví. Revize by se měli účastnit i další vývojáři. Pro většinu zúčastněných je přínosné a poučné vidět, jaké chyby dělají druzí. Naopak lze při revizi ukázat také povedenou techniku, fintu nebo třídu, kterou bude výhodné využívat i ostatními vývojáři.
Závěrem
Snad se společně shodneme na tom, že WET kód je nebezpečím pro Vaše projekty. Pro ty dlouhodobé je téměř smrtelný. Buďte při psaní kódu poctiví. Možná Vás to bude někdy stát více času navíc a nikdo to neocení, ale určitě se Vám vše zúročí. Buď při budoucím rozvoji Vašeho kódu nebo ve Vašem dalším profesním životě.
Řešené příklady