DRY (Don't Repeat Yourself) — un principiu fundamental al dezvoltării formulat de Andy Hunt și Dave Thomas în cartea „The Pragmatic Programmer”. Acesta spune: fiecare parte a cunoașterii dintr-un sistem trebuie să aibă o reprezentare unică, fără ambiguitate, autoritară. Conform The Pragmatic Programmer, 20th Anniversary Edition, încălcarea DRY duce la situația în care modificarea unui element necesită corecții în zeci de locuri, iar fiecare fragment omis devine o sursă de eroare.
Principalele puncte
DRY (Don't Repeat Yourself) — un principiu de dezvoltare care cere stocarea unică a fiecărui element de cunoaștere în proiect. Aceasta înseamnă că orice logică, configurație sau metadate trebuie să existe exact într-un singur loc.
Termenul a fost introdus de Andy Hunt și Dave Thomas în 1999 în cartea „The Pragmatic Programmer”. Autorii au definit DRY ca „fiecare parte a cunoașterii trebuie să aibă o reprezentare unică, coerentă în sistem”. Opusul DRY — abordarea WET (Write Everything Twice), unde duplicarea este considerată normă.
Conform cercetării University of California, Davis (2019), proiectele cu un nivel ridicat de duplicare a codului petrec cu 42% mai mult timp pentru remedierea erorilor. Motivul este că dezvoltatorul trebuie să găsească și să modifice toate copiile aceluiași fragment — iar la căutarea manuală, omisiunile sunt inevitabile.
Aplică DRY ca criteriu al calității codului. Dacă observi că același model apare în proiect de trei ori — extrage-l într-o abstractizare, fără a aștepta a patra repetare.
Single Responsibility Principle (SRP) din SOLID afirmă că o clasă trebuie să aibă un singur motiv pentru a fi modificată. DRY este mai larg: acoperă nu doar clasele, ci și datele, configurația, documentația și chiar regulile de afaceri. SRP este despre limitele responsabilității, DRY — despre inadmisibilitatea copierii.
În dezvoltarea mobilă, această diferență este deosebit de vizibilă. Dacă aceeași regulă de afaceri (calculul taxei, formatarea datei) se repetă în părțile Android și iOS — este o încălcare a DRY, deși SRP este respectat formal în cadrul fiecărei platforme. Soluția — extragerea logicii comune într-un modul partajat (KMM, C++).
Conform raportului Google Android Architecture Guidelines (2023), echipele care folosesc module comune pentru logica de afaceri reduc numărul de erori la modificarea cerințelor cu 37% comparativ cu proiectele cu duplicarea logicii între platforme.
Duplicarea — principala sursă a datoriei tehnice în proiectele mobile. Fiecare copie a codului creează o dependență ascunsă: pentru a modifica comportamentul, trebuie găsite și actualizate toate copiile. Omiterea chiar și a uneia înseamnă o eroare.
Să considerăm o situație clasică: într-o aplicație Android, formatarea datei este realizată în trei Activity-uri diferite. La trecerea la un format nou (de exemplu, ISO 8601), dezvoltatorul corectează două fișiere, uită de al treilea — iar utilizatorul vede data în format vechi. Evaluarea utilizatorilor aplicației scade, iar găsirea erorii durează de două ori mai mult.
Cercetarea Google Research (2020) a arătat: 68% dintre erorile critice în aplicațiile mobile sunt legate de modificarea nesincronizată a codului duplicat. Costul remedierii unei astfel de erori în production este de 4,5 ori mai mare decât dacă codul ar fi fost unitar de la început.
Folosește un analizor static (Detekt, SwiftLint) cu reguli care interzic detectarea copy-paste. Configurează CI astfel încât pull-request-urile cu duplicare de peste N linii să nu treacă de review fără justificare.
Un anti-pattern tipic — copierea adaptorului RecyclerView cu modificări minore. În loc de un adaptor universal cu configurație, dezvoltatorii creează o clasă separată pentru fiecare ecran. Refactorizarea cu extragerea unei clase de bază comune scurtează codul cu 30–50%.
// Duplicare: doi adaptori separați
class UserAdapter {
fun bind(item: User) { /* ... */ }
}
class ProductAdapter {
fun bind(item: Product) { /* ... */ }
}
// Refactorizare DRY: clasă de bază comună
abstract class BaseAdapter<T> {
abstract fun bind(item: T)
}
class UserAdapter : BaseAdapter<User>() { /* ... */ }
class ProductAdapter : BaseAdapter<Product>() { /* ... */ }
În primul exemplu, fiecare adaptor implementează din nou mecanismul bind. La adăugarea unei noi logici (analitică, logare) ar trebui modificate toate fișierele. Clasa de bază elimină această duplicare: logica comună trăiește într-un singur loc, iar cea specifică — în clasele derivate.
În proiectele iOS se duplică adesea configurația URLSession — antete, timeout-uri, gestionarea erorilor. Fiecare serviciu își creează propria sesiune cu setări repetitive.
// Duplicare: fiecare serviciu configurează sesiunea de la zero
class UserService {
let session = URLSession(configuration: {
let cfg = URLSessionConfiguration.default
cfg.timeoutIntervalForRequest = 30
cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
return cfg
}())
}
// DRY: fabrică unică de sesiuni
struct NetworkConfig {
static var session: URLSession {
let cfg = URLSessionConfiguration.default
cfg.timeoutIntervalForRequest = 30
cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
return URLSession(configuration: cfg)
}
}
Extragerea configurației într-un NetworkConfig unitar garantează că toate serviciile folosesc aceleași antete și timeout-uri. Modificarea într-un singur loc se aplică automat tuturor cererilor — aceasta reduce riscul de erori la schimbarea cheii API sau a versiunii protocolului.
Moștenirea — modul natural de eliminare a duplicării: logica comună este extrasă într-o clasă de bază, iar cea specifică — în clasele derivate. Totuși, în dezvoltarea mobilă, abuzul de moștenire creează ierarhii rigide care sunt greu de întreținut. Compoziția (injecția dependențelor) — o alternativă mai flexibilă.
Analiza Google I/O 2023: Modern Android Architecture a arătat că 76% dintre echipele Google preferă compoziția în locul moștenirii pentru eliminarea duplicării. În loc de BaseViewModel cu zece metode, se recomandă extragerea unor clase UseCase separate pentru fiecare operațiune de afaceri și injectarea lor acolo unde sunt necesare.
Alege compoziția în toate cazurile, cu excepția relațiilor „este-un”. Dacă clasa A este o specializare a clasei B — moștenirea este potrivită. Dacă A doar folosește funcționalitatea lui B — folosește compoziția.
Clasele utilitare (Extensions, Helpers) — cel mai simplu mod de a evita duplicarea. Candidați tipici: formatarea datelor, validarea email-urilor, conversia unităților, lucrul cu SharedPreferences/UserDefaults.
// DRY: funcție unică de formatare a datei
fun Date.toDisplayFormat(): String {
val sdf = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
return sdf.format(this)
}
// Utilizare în orice parte a aplicației
textView.text = Date().toDisplayFormat()
Extensia Date.toDisplayFormat() este declarată o dată și accesibilă în întregul proiect. Dacă trebuie schimbat formatul din „dd.MM.yyyy” în „yyyy-MM-dd” — corecția se face într-un singur fișier, nu în fiecare Activity sau Fragment unde apare formatarea. Aceasta este esența DRY.
Proiectele Android multi-modul duplică adesea versiunile dependențelor în fiecare build.gradle. Soluția — version catalog (libs.versions.toml), care centralizează toate versiunile într-un singur fișier.
Conform Android Developer Documentation (2024), migrarea la version catalog reduce conflictele de dependențe cu 52% și accelerează construcția datorită unui punct unic de corecții.
Implementează version catalog la începutul proiectului sau la prima reorganizare a modulelor. Dacă proiectul are deja duplicare — alocă o zi pentru migrare: se va amortiza la următoarea actualizare a bibliotecilor.
Abstractizarea prematură — cea mai frecventă greșeală a începătorilor. Dezvoltatorul vede două linii de cod similare și le extrage imediat într-o funcție comună. După o lună, cerințele se schimbă, iar funcția comună se umple de parametri și flag-uri — devine mai complexă decât duplicarea inițială. Rule of Three protejează tocmai de aceasta: nu abstractiza ceea ce a apărut o-dată sau de două ori.
Martin Fowler în cartea Refactoring (2019) recomandă: „Duplicarea codului nu este întotdeauna rea. Duplicarea cunoașterii este rea”. Dacă două linii coincid întâmplător, dar exprimă concepte diferite — nu este duplicare, ci coincidență. Rule of Three ajută să deosebim coincidența întâmplătoare de duplicarea sistematică.
Înainte de a abstractiza, evaluează semantica. Codul copiat cu același sens — încălcare a DRY. Codul cu sens diferit, dar sintaxă similară — coincidență care nu necesită abstractizare.
Parametrizarea excesivă apare atunci când o singură funcție încearcă să acopere toate scenariile posibile prin flag-uri și parametri booleeni. Un astfel de cod încalcă SRP și devine ilizibil. Simptom: dacă funcția are mai mult de doi parametri booleeni — acesta este un miros de cod (code smell) al abstractizării excesive.
În loc de o funcție cu flag-ul useCache: Boolean, este mai bine să creezi două funcții separate cu nume clare: fetchFromNetwork() și fetchFromCache(). Explicitarea este mai importantă decât abstractizarea uscată — aceasta se corelează cu principiul KISS.
Refactorizează parametrizarea excesivă atunci când funcția atinge 3+ parametri booleeni. Împarte în funcții separate cu nume clare — fiecare apel va deveni auto-documentat.
Întrebări frecvente
DRY (Don't Repeat Yourself) — principiul care cere stocarea fiecărei unități logice într-un singur loc. Dacă același cod apare în mai multe părți ale proiectului — este o încălcare a DRY. Remedierea: extrage logica repetată într-o funcție, clasă sau modul separat.
WET (Write Everything Twice) — antiteza DRY, în care duplicarea este considerată acceptabilă. În proiectele WET, același fragment de cod poate exista în cinci copii, iar la schimbarea cerințelor, dezvoltatorul corectează fiecare copie separat. WET crește riscul de erori și încetinește dezvoltarea.
DRY dăunează la abstractizarea prematură: când două fragmente de cod similare, dar semantic diferite, sunt combinate forțat într-o singură funcție. Aceasta generează cod complex, supraîncărcat cu parametri. Rule of Three ajută la evitarea acestei greșeli: abstractizează doar după a treia repetare.
În Android, DRY se aplică prin version catalog (libs.versions.toml), clase de bază comune pentru adaptoare, fabrici ViewModel și extensii utilitare Kotlin. Se recomandă extragerea logicii de afaceri în module partajate (KMM) și utilizarea View Binding pentru eliminarea duplicării findViewById.
În iOS, DRY se atinge prin protocoale cu implementare implicită, configurații de rețea comune (NetworkConfig), fabrici de celule UICollectionView și pachete SPM cu logică de afaceri comună. Extensions ale tipurilor standard (Date, String, URL) reduc duplicarea formatării și validării.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și