DRY (Don't Repeat Yourself) — egy alapvető fejlesztési elv, amelyet Andy Hunt és Dave Thomas fogalmazott meg a „The Pragmatic Programmer” című könyvben. Kimondja: a rendszerben minden tudásrésznek egyedi, egyértelmű, hiteles reprezentációval kell rendelkeznie. A The Pragmatic Programmer, 20th Anniversary Edition adatai szerint a DRY megsértése oda vezet, hogy egy elem megváltoztatása több tucat helyen igényel javításokat, és minden kihagyott részlet hibák forrásává válik.
Főbb pontok
DRY (Don't Repeat Yourself) — egy fejlesztési elv, amely megköveteli az egyes ismeretelemek egyszeri tárolását a projektben. Ez azt jelenti, hogy minden logikának, konfigurációnak vagy metaadatnak pontosan egy helyen kell léteznie.
A kifejezést Andy Hunt és Dave Thomas vezette be 1999-ben a „The Pragmatic Programmer” című könyvben. A szerzők a DRY-t úgy határozták meg, hogy „minden tudásrésznek egyedi, konzisztens reprezentációval kell rendelkeznie a rendszerben”. A DRY ellentéte — a WET (Write Everything Twice) megközelítés, ahol az ismétlés normának számít.
A University of California, Davis (2019) kutatása szerint a magas szintű kódismétléssel rendelkező projektek 42%-kal több időt töltenek a hibák javításával. Az ok az, hogy a fejlesztőnek meg kell találnia és módosítania kell ugyanazon részlet összes másolatát — és kézi keresésnél a kihagyások elkerülhetetlenek.
Alkalmazza a DRY-t a kódminőség kritériumaként. Ha észreveszi, hogy ugyanaz a minta háromszor jelenik meg a projektben — emelje ki absztrakcióba anélkül, hogy megvárná a negyedik ismétlést.
A Single Responsibility Principle (SRP) a SOLID-ból kimondja, hogy egy osztálynak egy okból kell változnia. A DRY tágabb: nemcsak az osztályokat, hanem az adatokat, konfigurációt, dokumentációt és még az üzleti szabályokat is lefedi. Az SRP a felelősségi határokról szól, a DRY — a másolás megengedhetetlenségéről.
A mobilfejlesztésben ez a különbség különösen szembetűnő. Ha ugyanaz az üzleti szabály (adószámítás, dátumformázás) ismétlődik az Android és iOS részekben — az a DRY megsértése, még akkor is, ha az SRP formálisan minden platformon belül teljesül. Megoldás — a közös logika kiemelése egy megosztott modulba (KMM, C++).
A Google Android Architecture Guidelines (2023) jelentése szerint a közös modulokat használó csapatok 37%-kal csökkentik a hibák számát a követelmények változásakor a platformok közötti logikaismétléssel rendelkező projektekhez képest.
Ismétlés — a technikai adósság fő forrása a mobil projektekben. Minden kódmásolat rejtett függőséget hoz létre: a viselkedés megváltoztatásához meg kell találni és frissíteni kell az összes másolatot. Már egyetlen kihagyása is hibát jelent.
Tekintsünk egy klasszikus helyzetet: egy Android alkalmazásban a dátum formázása három különböző Activity-ben történik. Új formátumra (pl. ISO 8601) való áttéréskor a fejlesztő két fájlt javít, a harmadikat elfelejti — és a felhasználó a dátumot régi formátumban látja. Az alkalmazás értékelése csökken, és a hiba megtalálása kétszer annyi időt vesz igénybe.
A Google Research (2020) kutatása kimutatta: a mobilalkalmazások kritikus hibáinak 68%-a az ismétlődő kód nem szinkron módosításához kapcsolódik. Egy ilyen hiba kijavításának költsége élesben 4,5-szer magasabb, mintha a kód kezdettől fogva egységes lett volna.
Használjon statikus elemzőt (Detekt, SwiftLint) olyan szabályokkal, amelyek tiltják a copy-paste észlelését. Konfigurálja a CI-t úgy, hogy az N sornál nagyobb ismétléssel rendelkező pull-requestek indoklás nélkül ne menjenek át a review-n.
Tipikus anti-pattern — a RecyclerView adapter másolása kisebb változtatásokkal. Egy univerzális, konfigurációval rendelkező adapter helyett a fejlesztők minden képernyőhöz külön osztályt hoznak létre. A közös alaposztály kiemelésével végzett refaktorálás 30–50%-kal rövidíti le a kódot.
// Ismétlődés: két külön adapter
class UserAdapter {
fun bind(item: User) { /* ... */ }
}
class ProductAdapter {
fun bind(item: Product) { /* ... */ }
}
// DRY-refaktorálás: közös alaposztály
abstract class BaseAdapter<T> {
abstract fun bind(item: T)
}
class UserAdapter : BaseAdapter<User>() { /* ... */ }
class ProductAdapter : BaseAdapter<Product>() { /* ... */ }
Az első példában minden adapter újra implementálja a bind mechanizmust. Új logika (analitika, naplózás) hozzáadásakor minden fájlt módosítani kellene. Az alaposztály kiküszöböli ezt az ismétlést: a közös logika egy helyen él, a specifikus logika a származtatott osztályokban.
Az iOS projektekben gyakran ismétlődik az URLSession konfigurációja — fejlécek, időtúllépések, hibakezelés. Minden szolgáltatás saját munkamenetet hoz létre ismétlődő beállításokkal.
// Ismétlődés: minden szolgáltatás újra konfigurálja a munkamenetet
class UserService {
let session = URLSession(configuration: {
let cfg = URLSessionConfiguration.default
cfg.timeoutIntervalForRequest = 30
cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
return cfg
}())
}
// DRY: egységes munkamenet-gyár
struct NetworkConfig {
static var session: URLSession {
let cfg = URLSessionConfiguration.default
cfg.timeoutIntervalForRequest = 30
cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
return URLSession(configuration: cfg)
}
}
A konfiguráció egységes NetworkConfig-be történő kiemelése garantálja, hogy minden szolgáltatás ugyanazokat a fejléceket és időtúllépéseket használja. Az egy helyen történő módosítás automatikusan érvényesül az összes kérésre — ez csökkenti a hibák kockázatát az API-kulcs vagy protokollverzió változásakor.
Öröklődés — az ismétlés kiküszöbölésének természetes módja: a közös logika egy alaposztályba kerül, a specifikus logika a származtatott osztályokba. A mobilfejlesztésben azonban az öröklődés visszaélése merev hierarchiákat hoz létre, amelyeket nehéz karbantartani. Kompozíció (függőséginjektálás) — rugalmasabb alternatíva.
A Google I/O 2023: Modern Android Architecture elemzése kimutatta, hogy a Google csapatainak 76%-a a kompozíciót részesíti előnyben az öröklődéssel szemben az ismétlés kiküszöbölésére. A tíz metódust tartalmazó BaseViewModel helyett ajánlott külön UseCase osztályokat létrehozni minden üzleti művelethez, és azokat oda injektálni, ahol szükség van rájuk.
Válassza a kompozíciót minden esetben, kivéve az „egyfajta” kapcsolatokat. Ha az A osztály a B osztály specializációja — az öröklődés megfelelő. Ha A csak B funkcionalitását használja — alkalmazza a kompozíciót.
Segédosztályok (Extensions, Helpers) — a legegyszerűbb módja az ismétlés elkerülésének. Tipikus jelöltek: dátumformázás, e-mail érvényesítés, mértékegység-átváltás, SharedPreferences/UserDefaults használat.
// DRY: egységes dátumformázó függvény
fun Date.toDisplayFormat(): String {
val sdf = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
return sdf.format(this)
}
// Használat az alkalmazás bármely részén
textView.text = Date().toDisplayFormat()
A Date.toDisplayFormat() kiterjesztés egyszer van deklarálva, és az egész projektben elérhető. Ha a formátumot „dd.MM.yyyy”-ről „yyyy-MM-dd”-re kell változtatni — egy fájlban történő javítás, nem pedig minden Activity-ben vagy Fragment-ben, ahol formázás előfordul. Ez a DRY lényege.
A többmodulos Android projektek gyakran ismétlik a függőségi verziókat minden build.gradle fájlban. Megoldás — version catalog (libs.versions.toml), amely az összes verziót egy fájlba centralizálja.
A Android Developer Documentation (2024) szerint a version catalog-ra való migrálás 52%-kal csökkenti a függőségi konfliktusokat és felgyorsítja a build-et az egységes javítási pontnak köszönhetően.
Vezesse be a version catalog-ot a projekt elején vagy a modulok első átszervezésekor. Ha a projekt már tartalmaz ismétlést — szánjon egy napot a migrációra: ez megtérül a következő könyvtárfrissítéskor.
Korai absztrakció — a kezdők leggyakoribb hibája. A fejlesztő két hasonló kódsort lát, és azonnal kiemeli őket egy közös függvénybe. Egy hónap múlva a követelmények megváltoznak, és a közös függvény tele lesz paraméterekkel és zászlókkal — bonyolultabb lesz, mint az eredeti ismétlés. A Rule of Three pontosan ez ellen véd: ne absztraktálja azt, ami csak egyszer-kétszer fordul elő.
Martin Fowler a Refactoring (2019) című könyvében azt ajánlja: „A kód ismétlődése nem mindig rossz. A tudás ismétlődése rossz”. Ha két sor véletlenül egyezik, de különböző fogalmakat fejez ki — az nem ismétlés, hanem véletlen egybeesés. A Rule of Three segít megkülönböztetni a véletlen egybeesést a rendszerszerű ismétléstől.
Az absztrakció előtt értékelje a szemantikát. Az azonos jelentéssel bemásolt kód — a DRY megsértése. A különböző jelentéssel, de hasonló szintaxissal rendelkező kód — véletlen egybeesés, amely nem igényel absztrakciót.
Túlzott paraméterezés akkor fordul elő, amikor egy függvény zászlókon és logikai paramétereken keresztül próbálja lefedni az összes lehetséges forgatókönyvet. Az ilyen kód megsérti az SRP-t és olvashatatlanná válik. Tünet: ha egy függvényben kettőnél több logikai paraméter van — az a túlzott absztrakció kódszagát (code smell) jelzi.
Egy useCache: Boolean zászlós függvény helyett jobb két külön függvényt létrehozni egyértelmű nevekkel: fetchFromNetwork() és fetchFromCache(). Az egyértelműség fontosabb, mint a száraz absztrakció — ez összhangban van a KISS elvvel.
Refaktorálja a túlzott paraméterezést, amikor a függvény eléri a 3+ logikai paramétert. Ossza fel külön függvényekre egyértelmű nevekkel — minden hívás öndokumentálóvá válik.
Gyakori kérdések
DRY (Don't Repeat Yourself) — elv, amely megköveteli minden logikai egység egy helyen történő tárolását. Ha ugyanaz a kód a projekt több részében is megjelenik — az a DRY megsértése. Javítás: emelje ki az ismétlődő logikát egy külön függvénybe, osztályba vagy modulba.
WET (Write Everything Twice) — a DRY ellentéte, ahol az ismétlés elfogadhatónak tekinthető. A WET projektekben ugyanaz a kódrészlet öt másolatban is létezhet, és a követelmények változásakor a fejlesztő minden másolatot külön javít. A WET növeli a hibák kockázatát és lassítja a fejlesztést.
A DRY korai absztrakció esetén káros: amikor két hasonló, de szemantikailag eltérő kódrészletet erőszakkal egyetlen függvénybe vonnak össze. Ez összetett, paraméterekkel túlterhelt kódot hoz létre. A Rule of Three segít elkerülni ezt a hibát: csak a harmadik ismétlés után absztraktáljon.
Android-ban a DRY-t version catalog (libs.versions.toml), az adapterek közös alaposztályai, ViewModel gyárak és hasznos Kotlin kiterjesztések segítségével alkalmazzuk. Ajánlott az üzleti logika kiemelése megosztott modulokba (KMM) és a View Binding használata a findViewById ismétlésének kiküszöbölésére.
iOS-ben a DRY alapértelmezett implementációval rendelkező protokollokkal, közös hálózati konfigurációkkal (NetworkConfig), UICollectionView cellagyárakkal és közös üzleti logikával rendelkező SPM csomagokkal érhető el. A szabványos típusok (Date, String, URL) Extensions csökkentik a formázás és érvényesítés ismétlődését.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is