DRY (Don't Repeat Yourself) is a fundamental development principle formulated by Andy Hunt and Dave Thomas in the book “The Pragmatic Programmer.” It states: every piece of knowledge in a system must have a single, unambiguous, authoritative representation. According to The Pragmatic Programmer, 20th Anniversary Edition, violating DRY means that changing one element requires edits in dozens of places, and every missed fragment becomes a source of bugs.
Key Takeaways
DRY (Don't Repeat Yourself) is a development principle that requires storing each knowledge element in a project exactly once. This means that any logic, configuration, or metadata should exist in precisely one place.
The term was introduced by Andy Hunt and Dave Thomas in 1999 in the book “The Pragmatic Programmer.” The authors defined DRY as “every piece of knowledge must have a single, unambiguous, authoritative representation within a system.” The opposite of DRY is the WET (Write Everything Twice) approach, where duplication is considered normal.
According to a University of California, Davis (2019) study, projects with high levels of code duplication spend 42% more time fixing bugs. The reason is that developers must find and change all copies of the same fragment — and manual searching inevitably leads to misses.
Apply DRY as a code quality criterion. If you notice the same pattern appearing three times in a project — extract it into an abstraction without waiting for a fourth repetition.
Single Responsibility Principle (SRP) from SOLID states that a class should have one reason to change. DRY is broader: it covers not only classes but also data, configuration, documentation, and even business rules. SRP is about responsibility boundaries; DRY is about preventing copying.
In mobile development, this distinction is especially noticeable. If the same business rule (tax calculation, date formatting) repeats in both Android and iOS parts of the project — that's a DRY violation, even though SRP is formally observed within each platform. The solution is to extract common logic into a shared module (KMM, C++).
According to the Google Android Architecture Guidelines (2023) report, teams using shared modules for business logic reduce the number of bugs when requirements change by 37% compared to projects with logic duplicated across platforms.
Duplication is the main source of technical debt in mobile projects. Each code copy creates a hidden dependency: to change behavior, you need to find and update all copies. Missing even one means a bug.
Consider a classic scenario: in an Android app, date formatting is done in three different Activities. When switching to a new format (e.g., ISO 8601), the developer fixes two files, forgets the third — and the user sees dates in the old format. The app rating drops, and finding the bug takes twice as long.
A Google Research (2020) study showed that 68% of critical bugs in mobile applications are related to unsynchronized changes in duplicated code. Moreover, fixing such a bug in production costs 4.5 times more than if the code had been unified from the start.
Use static analyzers (Detekt, SwiftLint) with rules that flag copy-paste detection. Configure CI so that pull requests with more than N lines of duplication don't pass review without justification.
A typical anti-pattern is copying a RecyclerView adapter with minor modifications. Instead of one universal adapter with configuration, developers create a separate class for each screen. Refactoring by extracting a common base class reduces code by 30–50%.
// Duplication: two separate adapters
class UserAdapter {
fun bind(item: User) { /* ... */ }
}
class ProductAdapter {
fun bind(item: Product) { /* ... */ }
}
// DRY refactoring: common base class
abstract class BaseAdapter<T> {
abstract fun bind(item: T)
}
class UserAdapter : BaseAdapter<User>() { /* ... */ }
class ProductAdapter : BaseAdapter<Product>() { /* ... */ }
In the first example, each adapter reimplements the bind mechanism from scratch. When adding new logic (analytics, logging), every file would need to be changed. A base class eliminates this duplication: common logic lives in one place, specific logic in subclasses.
In iOS projects, URLSession configuration — headers, timeouts, error handling — is often duplicated. Each service creates its own session with repeated settings.
// Duplication: each service configures the session anew
class UserService {
let session = URLSession(configuration: {
let cfg = URLSessionConfiguration.default
cfg.timeoutIntervalForRequest = 30
cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
return cfg
}())
}
// DRY: unified session factory
struct NetworkConfig {
static var session: URLSession {
let cfg = URLSessionConfiguration.default
cfg.timeoutIntervalForRequest = 30
cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
return URLSession(configuration: cfg)
}
}
Extracting configuration into a unified NetworkConfig ensures all services use the same headers and timeouts. A change in one place automatically applies to all requests — this reduces the risk of errors when changing API keys or protocol versions.
Inheritance is a natural way to eliminate duplication: common logic is moved to a base class, and specific logic to subclasses. However, in mobile development, overusing inheritance creates rigid hierarchies that are hard to maintain. Composition (dependency injection) is a more flexible alternative.
An analysis from Google I/O 2023: Modern Android Architecture showed that 76% of Google teams prefer composition over inheritance for eliminating duplication. Instead of a BaseViewModel with a dozen methods, it's recommended to extract separate UseCase classes for each business operation and inject them where needed.
Choose composition in all cases except “is-a” relationships. If class A is a specialization of class B — inheritance is appropriate. If A simply uses B's functionality — use composition.
Utility classes (Extensions, Helpers) are the simplest way to avoid duplication. Typical candidates: date formatting, email validation, unit conversion, working with SharedPreferences/UserDefaults.
// DRY: unified date formatting function
fun Date.toDisplayFormat(): String {
val sdf = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
return sdf.format(this)
}
// Usage anywhere in the application
textView.text = Date().toDisplayFormat()
The Date.toDisplayFormat() extension is declared once and is available throughout the project. If the format needs to change from “dd.MM.yyyy” to “yyyy-MM-dd” — the fix is in one file, not in every Activity or Fragment where formatting occurs. This is the essence of DRY.
Multi-module Android projects often duplicate dependency versions in each build.gradle. The solution is a version catalog (libs.versions.toml) that centralizes all versions in a single file.
According to Android Developer Documentation (2024), migrating to a version catalog reduces dependency conflicts by 52% and speeds up builds through a single point of edits.
Implement a version catalog at project start or during the first module reorganization. If the project already has duplication — set aside one day for migration: it will pay off at the next library update.
Premature abstraction is the most common mistake of beginners. A developer sees two similar lines of code and immediately extracts them into a common function. A month later, requirements change, and the common function becomes cluttered with parameters and flags — more complex than the original duplication. The Rule of Three protects against exactly this: don't abstract something that has appeared only once or twice.
Martin Fowler in his book Refactoring (2019) recommends: “Code duplication is not always evil. Knowledge duplication is evil.” If two lines coincidentally match but express different concepts — that's not duplication, it's coincidence. The Rule of Three helps distinguish accidental coincidence from systematic duplication.
Before abstracting, assess the semantics. Copied code with the same meaning — a DRY violation. Code with different meaning but similar syntax — a coincidence that doesn't require abstraction.
Excessive parameterization occurs when a single function tries to cover all possible scenarios through flags and boolean parameters. Such code violates SRP and becomes unreadable. Symptom: if a function has more than two boolean parameters — it's a code smell of excessive abstraction.
Instead of one function with a useCache: Boolean flag, it's better to create two separate functions with clear names: fetchFromNetwork() and fetchFromCache(). Clarity is more important than a dry abstraction — this echoes the KISS principle.
Refactor excessive parameterization when a function reaches 3+ boolean parameters. Split into separate functions with clear names — each call will become self-documenting.
Frequently Asked Questions
DRY (Don't Repeat Yourself) is a principle that requires storing every logical unit in a single place. If the same code appears in multiple parts of a project — it's a DRY violation. Fix: extract the repeating logic into a separate function, class, or module.
WET (Write Everything Twice) is the opposite of DRY, where duplication is considered acceptable. In WET projects, the same code fragment can exist in five copies, and when requirements change, the developer fixes each copy separately. WET increases the risk of bugs and slows down development.
DRY is harmful when it leads to premature abstraction: when two similar but semantically different code sections are forcibly merged into one function. This creates complex, overloaded code. The Rule of Three helps avoid this mistake: only abstract after the third repetition.
In Android, DRY is applied through version catalogs (libs.versions.toml), common base classes for adapters, ViewModel factories, and utility Kotlin extensions. It's recommended to extract business logic into shared modules (KMM) and use View Binding to eliminate findViewById duplication.
In iOS, DRY is achieved through protocols with default implementations, shared network configurations (NetworkConfig), UICollectionView cell factories, and SPM packages with common business logic. Extensions of standard types (Date, String, URL) reduce duplication in formatting and validation.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also