DRY (Don't Repeat Yourself) — základní princip vývoje formulovaný Andym Huntem a Davem Thomasem v knize „The Pragmatic Programmer”. Říká: každá část znalosti v systému musí mít jedinečnou, jednoznačnou, autoritativní reprezentaci. Podle údajů The Pragmatic Programmer, 20th Anniversary Edition vede porušení DRY k tomu, že změna jednoho prvku vyžaduje opravy na desítkách míst a každý vynechaný fragment se stává zdrojem chyby.
Hlavní body
DRY (Don't Repeat Yourself) — princip vývoje vyžadující jednorázové uložení každého prvku znalosti v projektu. To znamená, že každá logika, konfigurace nebo metadata musí existovat přesně na jednom místě.
Termín zavedli Andy Hunt a Dave Thomas v roce 1999 v knize „The Pragmatic Programmer”. Autoři definovali DRY jako „každá část znalosti musí mít jedinečnou, konzistentní reprezentaci v systému”. Opak DRY — přístup WET (Write Everything Twice), kde je duplicita považována za normu.
Podle výzkumu University of California, Davis (2019) projekty s vysokou úrovní duplicity kódu tráví o 42% více času opravou chyb. Důvodem je, že vývojář musí najít a změnit všechny kopie stejného fragmentu — a při ručním hledání jsou opomenutí nevyhnutelná.
Aplikujte DRY jako kritérium kvality kódu. Pokud si všimnete, že se stejný vzor v projektu objevuje třikrát — vydělte jej do abstrakce, aniž byste čekali na čtvrté opakování.
Single Responsibility Principle (SRP) ze SOLID říká, že třída by měla mít jeden důvod ke změně. DRY je širší: zahrnuje nejen třídy, ale také data, konfiguraci, dokumentaci a dokonce obchodní pravidla. SRP je o hranicích odpovědnosti, DRY — o nepřípustnosti kopírování.
V mobilním vývoji je tento rozdíl obzvláště patrný. Pokud se stejné obchodní pravidlo (výpočet daně, formátování data) opakuje v částech Android a iOS — je to porušení DRY, i když je SRP formálně dodržen v rámci každé platformy. Řešení — vydělení společné logiky do sdíleného modulu (KMM, C++).
Podle zprávy Google Android Architecture Guidelines (2023) týmy používající sdílené moduly pro obchodní logiku snižují počet chyb při změně požadavků o 37% ve srovnání s projekty s duplicitou logiky napříč platformami.
Duplicita — hlavní zdroj technického dluhu v mobilních projektech. Každá kopie kódu vytváří skrytou závislost: pro změnu chování je třeba najít a aktualizovat všechny kopie. Vynechání byť jen jedné znamená chybu.
Zvažme klasickou situaci: v aplikaci pro Android se formátování data provádí ve třech různých Activity. Při přechodu na nový formát (např. ISO 8601) vývojář opraví dva soubory, zapomene na třetí — a uživatel vidí datum ve starém formátu. Hodnocení uživatelů aplikace klesá a nalezení chyby trvá dvakrát déle.
Výzkum Google Research (2020) ukázal: 68% kritických chyb v mobilních aplikacích souvisí s nesynchronní změnou duplicitního kódu. Náklady na opravu takové chyby v produkci jsou 4,5krát vyšší, než kdyby byl kód od začátku jednotný.
Používejte statický analyzátor (Detekt, SwiftLint) s pravidly zakazujícími detekci copy-paste. Nakonfigurujte CI tak, aby pull requesty s duplicitou větší než N řádků neprošly review bez odůvodnění.
Typický anti-pattern — kopírování adaptéru RecyclerView s malými změnami. Místo jednoho univerzálního adaptéru s konfigurací vytvářejí vývojáři samostatnou třídu pro každou obrazovku. Refaktorování s vydělením společné základní třídy zkracuje kód o 30–50%.
// Duplicita: dva samostatné adaptéry
class UserAdapter {
fun bind(item: User) { /* ... */ }
}
class ProductAdapter {
fun bind(item: Product) { /* ... */ }
}
// DRY-refaktorování: společná základní třída
abstract class BaseAdapter<T> {
abstract fun bind(item: T)
}
class UserAdapter : BaseAdapter<User>() { /* ... */ }
class ProductAdapter : BaseAdapter<Product>() { /* ... */ }
V prvním příkladu každý adaptér znovu implementuje mechanismus bind. Při přidávání nové logiky (analytika, logování) by se musel měnit každý soubor. Základní třída tuto duplicitu eliminuje: společná logika žije na jednom místě, specifická — v odvozených třídách.
V iOS projektech se často duplikuje konfigurace URLSession — hlavičky, časové limity, zpracování chyb. Každá služba vytváří vlastní relaci s opakujícími se nastaveními.
// Duplicita: každá služba konfiguruje relaci znovu
class UserService {
let session = URLSession(configuration: {
let cfg = URLSessionConfiguration.default
cfg.timeoutIntervalForRequest = 30
cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
return cfg
}())
}
// DRY: jednotná továrna relací
struct NetworkConfig {
static var session: URLSession {
let cfg = URLSessionConfiguration.default
cfg.timeoutIntervalForRequest = 30
cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
return URLSession(configuration: cfg)
}
}
Vydělení konfigurace do jednotného NetworkConfig zaručuje, že všechny služby používají stejné hlavičky a časové limity. Změna na jednom místě se automaticky aplikuje na všechny požadavky — to snižuje riziko chyb při změně API klíče nebo verze protokolu.
Dědičnost — přirozený způsob eliminace duplicity: společná logika je vydělena do základní třídy a specifická do odvozených tříd. V mobilním vývoji však zneužívání dědičnosti vytváří rigidní hierarchie, které jsou obtížně udržovatelné. Kompozice (vkládání závislostí) — flexibilnější alternativa.
Analýza Google I/O 2023: Modern Android Architecture ukázala, že 76% týmů Google preferuje kompozici před dědičností pro eliminaci duplicity. Místo BaseViewModel s deseti metodami se doporučuje vydělovat samostatné třídy UseCase pro každou obchodní operaci a vkládat je tam, kde jsou potřeba.
Vybírejte kompozici ve všech případech kromě vztahů „je”. Pokud je třída A specializací třídy B — dědičnost je vhodná. Pokud A pouze používá funkcionalitu B — použijte kompozici.
Užitkové třídy (Extensions, Helpers) — nejjednodušší způsob, jak se vyhnout duplicitě. Typickí kandidáti: formátování dat, validace emailu, převod jednotek, práce s SharedPreferences/UserDefaults.
// DRY: jednotná funkce formátování data
fun Date.toDisplayFormat(): String {
val sdf = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
return sdf.format(this)
}
// Použití v libovolné části aplikace
textView.text = Date().toDisplayFormat()
Rozšíření Date.toDisplayFormat() je deklarováno jednou a je dostupné v celém projektu. Pokud je třeba změnit formát z „dd.MM.yyyy” na „yyyy-MM-dd” — oprava v jednom souboru, ne v každé Activity nebo Fragmentu, kde se formátování vyskytuje. To je podstata DRY.
Vícemodulové Android projekty často duplikují verze závislostí v každém build.gradle. Řešení — version catalog (libs.versions.toml), centralizující všechny verze do jednoho souboru.
Podle Android Developer Documentation (2024) migrace na version catalog snižuje konflikty závislostí o 52% a urychluje sestavení díky jedinému bodu oprav.
Zaveďte version catalog na začátku projektu nebo při první reorganizaci modulů. Pokud projekt již obsahuje duplicitu — vyhraďte jeden den na migraci: vrátí se to při příští aktualizaci knihoven.
Předčasná abstrakce — nejčastější chyba začátečníků. Vývojář vidí dva podobné řádky kódu a okamžitě je vydělí do společné funkce. Po měsíci se požadavky změní a společná funkce zaroste parametry a příznaky — stane se složitější než původní duplicita. Rule of Three chrání právě před tímto: neabstrahujte to, co se objevilo jednou nebo dvakrát.
Martin Fowler v knize Refactoring (2019) doporučuje: „Duplicita kódu není vždy zlo. Duplicita znalostí je zlo”. Pokud se dva řádky náhodou shodují, ale vyjadřují různé koncepty — není to duplicita, ale náhoda. Rule of Three pomáhá odlišit náhodnou shodu od systematické duplicity.
Před abstrakcí zhodnoťte sémantiku. Zkopírovaný kód se stejným významem — porušení DRY. Kód s různým významem, ale podobnou syntaxí — náhoda nevyžadující abstrakci.
Nadměrná parametrizace vzniká, když se jedna funkce snaží pokrýt všechny možné scénáře pomocí příznaků a booleovských parametrů. Takový kód porušuje SRP a stává se nečitelným. Příznak: pokud má funkce více než dva booleovské parametry — je to pachuť kódu (code smell) nadměrné abstrakce.
Místo jedné funkce s příznakem useCache: Boolean je lepší vytvořit dvě samostatné funkce s jasnými názvy: fetchFromNetwork() a fetchFromCache(). Explicitnost je důležitější než suchá abstrakce — to koresponduje s principem KISS.
Refaktorujte nadměrnou parametrizaci, když funkce dosáhne 3+ booleovských parametrů. Rozdělte na samostatné funkce s jasnými názvy — každé volání se stane samodokumentující.
Často kladené otázky
DRY (Don't Repeat Yourself) — princip vyžadující ukládání každé logické jednotky na jednom místě. Pokud se stejný kód objevuje v několika částech projektu — je to porušení DRY. Náprava: přeneste opakující se logiku do samostatné funkce, třídy nebo modulu.
WET (Write Everything Twice) — opak DRY, při kterém je duplicita považována za přípustnou. V WET projektech může stejný fragment kódu existovat v pěti kopiích a při změně požadavků vývojář opravuje každou kopii zvlášť. WET zvyšuje riziko chyb a zpomaluje vývoj.
DRY škodí při předčasné abstrakci: když jsou dva podobné, ale sémanticky odlišné úseky kódu násilně spojeny do jedné funkce. To vytváří složitý, parametry přetížený kód. Rule of Three pomáhá vyhnout se této chybě: abstrahujte až po třetím opakování.
V Android se DRY aplikuje prostřednictvím version catalog (libs.versions.toml), společných základních tříd pro adaptéry, ViewModel továren a užitečných Kotlin rozšíření. Doporučuje se vydělovat obchodní logiku do sdílených modulů (KMM) a používat View Binding k eliminaci duplicity findViewById.
V iOS se DRY dosahuje pomocí protokolů s výchozí implementací, sdílených síťových konfigurací (NetworkConfig), továren na buňky UICollectionView a SPM balíčků se sdílenou obchodní logikou. Extensions standardních typů (Date, String, URL) snižují duplicitu formátování a validace.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také