DRY в мобильной разработке — что это, принцип и почему дублирование вредно

Автор: IT Sectr Опубликовано: 2026-05-12 Время чтения: 8 мин

DRY (Don't Repeat Yourself) — фундаментальный принцип разработки, сформулированный Энди Хантом и Дэйвом Томасом в книге «The Pragmatic Programmer». Он гласит: каждая часть знания в системе должна иметь единственное, однозначное, авторитетное представление. По данным The Pragmatic Programmer, 20th Anniversary Edition, нарушение DRY приводит к тому, что изменение одного элемента требует правок в десятках мест, и каждый пропущенный фрагмент становится источником бага.

Главное

  • DRY — принцип однократного хранения каждого знания в системе, исключающий дублирование кода и данных.
  • Дублирование увеличивает стоимость поддержки: изменение в одном месте требует синхронных правок во всех копиях.
  • Copy-paste — главный враг DRY: скопированный код быстро расходится, и разработчик забывает, где ещё нужно вносить правки.
  • Абстракция — основной инструмент DRY: выделение повторяющихся фрагментов в функции, классы или модули.
  • Rule of Three — практическое правило: если код повторяется в трёх местах, пришло время для абстракции.

Что такое DRY?

DRY (Don't Repeat Yourself) — принцип разработки, требующий однократного хранения каждого элемента знания в проекте. Это означает, что любая логика, конфигурация или метаданные должны существовать ровно в одном месте.

Термин введён Энди Хантом и Дэйвом Томасом в 1999 году в книге «The Pragmatic Programmer». Авторы определили DRY как «каждая часть знания должна иметь единственное, непротиворечивое представление в системе». Противоположность DRY — подход WET (Write Everything Twice), где дублирование считается нормой.

По данным исследования University of California, Davis (2019), проекты с высоким уровнем дублирования кода тратят на 42% больше времени на исправление багов. Причина в том, что разработчик должен найти и изменить все копии одного и того же фрагмента — а при ручном поиске пропуски неизбежны.

Применяйте DRY как критерий качества кода. Если вы замечаете, что один и тот же паттерн встречается в проекте трижды — выделите его в абстракцию, не дожидаясь четвёртого повторения.

Отличие DRY от принципа единственной ответственности

Single Responsibility Principle (SRP) из SOLID утверждает, что у класса должна быть одна причина для изменения. DRY шире: он охватывает не только классы, но и данные, конфигурацию, документацию и даже бизнес-правила. SRP — о границах ответственности, DRY — о недопустимости копирования.

В мобильной разработке это различие особенно заметно. Если одно и то же бизнес-правило (расчёт налога, форматирование даты) повторяется в Android и iOS частях проекта — это нарушение DRY, хотя SRP формально соблюдён внутри каждой платформы. Решение — выносить общую логику в shared-модуль (KMM, C++).

По данным отчёта Google Android Architecture Guidelines (2023), команды, использующие общие модули для бизнес-логики, сокращают количество багов при изменении требований на 37% по сравнению с проектами с дублированием логики по платформам.

Почему дублирование кода опасно?

Дублирование — главный источник технического долга в мобильных проектах. Каждая копия кода создаёт скрытую зависимость: чтобы изменить поведение, нужно найти и обновить все копии. Пропуск хотя бы одной означает баг.

Рассмотрим классическую ситуацию: в Android-приложении форматирование даты выполняется в трёх разных Activity. При переходе на новый формат (например, ISO 8601) разработчик исправляет два файла, забывает о третьем — и пользователь видит дату в старом формате. Пользовательский рейтинг приложения падает, а на поиск бага уходит в два раза больше времени.

Исследование Google Research (2020) показало: 68% критических багов в мобильных приложениях связаны с несинхронным изменением дублированного кода. При этом стоимость исправления такого бага в production в 4,5 раза выше, чем если бы код был единым изначально.

Используйте статический анализатор (Detekt, SwiftLint) с правилами, запрещающими copy-paste детекшн. Настройте CI, чтобы пулл-реквесты с дублированием более N строк не проходили ревью без обоснования.

DRY в мобильной разработке: практические примеры

Дублирование UI-логики в Android

Типичный anti-pattern — копирование адаптера RecyclerView с незначительными изменениями. Вместо одного универсального адаптера с конфигурацией разработчики создают отдельный класс для каждого экрана. Рефакторинг с выделением общего базового класса сокращает код на 30–50%.

kotlin
// Дублирование: два отдельных адаптера
class UserAdapter {
    fun bind(item: User) { /* ... */ }
}
class ProductAdapter {
    fun bind(item: Product) { /* ... */ }
}

// DRY-рефакторинг: общий базовый класс
abstract class BaseAdapter<T> {
    abstract fun bind(item: T)
}
class UserAdapter : BaseAdapter<User>() { /* ... */ }
class ProductAdapter : BaseAdapter<Product>() { /* ... */ }

В первом примере каждый адаптер заново реализует механизм bind. При добавлении новой логики (аналитика, логирование) пришлось бы менять каждый файл. Базовый класс устраняет это дублирование: общая логика живёт в одном месте, специфичная — в наследниках.

Дублирование сетевых запросов в iOS

В iOS-проектах часто дублируется конфигурация URLSession — заголовки, таймауты, обработка ошибок. Каждый сервис создаёт собственную сессию с повторяющимися настройками.

swift
// Дублирование: каждый сервис настраивает сессию заново
class UserService {
    let session = URLSession(configuration: {
        let cfg = URLSessionConfiguration.default
        cfg.timeoutIntervalForRequest = 30
        cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
        return cfg
    }())
}

// DRY: единая фабрика сессий
struct NetworkConfig {
    static var session: URLSession {
        let cfg = URLSessionConfiguration.default
        cfg.timeoutIntervalForRequest = 30
        cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
        return URLSession(configuration: cfg)
    }
}

Вынос конфигурации в единый NetworkConfig гарантирует, что все сервисы используют одинаковые заголовки и таймауты. Изменение в одном месте автоматически применяется ко всем запросам — это снижает риск ошибок при смене API-ключа или версии протокола.

Как применять DRY в Android и iOS?

DRY через наследование и композицию

Наследование — естественный способ устранения дублирования: общая логика выносится в базовый класс, а специфичная — в наследники. Однако в мобильной разработке злоупотребление наследованием порождает жёсткие иерархии, которые трудно поддерживать. Композиция (внедрение зависимости) — более гибкая альтернатива.

Анализ Google I/O 2023: Modern Android Architecture показал, что 76% команд Google предпочитают композицию наследованию для устранения дублирования. Вместо BaseViewModel с десятком методов рекомендуется выделять отдельные UseCase-классы для каждой бизнес-операции и внедрять их туда, где они нужны.

Выбирайте композицию во всех случаях, кроме «is-a» отношений. Если класс A — это специализация класса B — наследование уместно. Если A просто использует функциональность B — используйте композицию.

DRY через утилитарные классы

Утилитарные классы (Extensions, Helpers) — простейший способ избежать дублирования. Типичные кандидаты: форматирование дат, валидация email, конвертация единиц, работа с SharedPreferences/UserDefaults.

kotlin
// DRY: единая функция форматирования даты
fun Date.toDisplayFormat(): String {
    val sdf = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
    return sdf.format(this)
}

// Использование в любом месте приложения
textView.text = Date().toDisplayFormat()

Расширение Date.toDisplayFormat() объявлено один раз и доступно во всём проекте. Если потребуется изменить формат с «dd.MM.yyyy» на «yyyy-MM-dd» — правка в одном файле, а не в каждом Activity или Fragment, где встречается форматирование. Это и есть суть DRY.

DRY в конфигурации Gradle (Android)

Многомодульные проекты Android часто дублируют версии зависимостей в каждом build.gradle. Решение — version catalog (libs.versions.toml), централизующий все версии в одном файле.

Согласно Android Developer Documentation (2024), миграция на version catalog сокращает конфликты зависимостей на 52% и ускоряет сборку за счёт единой точки правок.

Внедрите version catalog на старте проекта или при первой реорганизации модулей. Если проект уже содержит дублирование — выделите один день на миграцию: это окупится при следующем обновлении библиотек.

Типичные ошибки при следовании DRY

Преждевременная абстракция

Преждевременная абстракция — самая частая ошибка новичков. Разработчик видит две похожие строки кода и сразу выносит их в общую функцию. Через месяц требования меняются, и общая функция обрастает параметрами и флагами — становится сложнее, чем исходное дублирование. Rule of Three защищает именно от этого: не абстрагируйте то, что встретилось один-два раза.

Мартин Фаулер в книге Refactoring (2019) рекомендует: «Дублирование кода — не всегда зло. Дублирование знания — зло». Если две строки случайно совпадают, но выражают разные концепции — это не дублирование, а совпадение. Rule of Three помогает отличить случайное совпадение от системного дублирования.

Прежде чем абстрагировать, оцените семантику. Скопированный код с одинаковым смыслом — нарушение DRY. Код с разным смыслом, но похожим синтаксисом — совпадение, не требующее абстракции.

Избыточная параметризация

Избыточная параметризация возникает, когда одна функция пытается покрыть все возможные сценарии через флаги и булевы параметры. Такой код нарушает SRP и становится нечитаемым. Симптом: если в функции больше двух булевых параметров — это запах (code smell) избыточной абстракции.

Вместо одной функции с флагом useCache: Boolean лучше создать две отдельные функции с понятными именами: fetchFromNetwork() и fetchFromCache(). Явность важнее сухой абстракции — это перекликается с принципом KISS.

Рефакторите избыточную параметризацию, когда функция достигает 3+ булевых параметров. Разделите на отдельные функции с чёткими именами — каждый вызов станет самодокументируемым.

Часто задаваемые вопросы

Что такое DRY простыми словами?

DRY (Don't Repeat Yourself) — принцип, требующий хранить каждую логическую единицу в единственном месте. Если один и тот же код встречается в нескольких частях проекта — это нарушение DRY. Исправление: вынести повторяющуюся логику в отдельную функцию, класс или модуль.

Чем отличается DRY от WET?

WET (Write Everything Twice) — антипод DRY, при котором дублирование считается допустимым. В WET-проектах один и тот же фрагмент кода может существовать в пяти копиях, и при изменении требований разработчик правит каждую копию отдельно. WET увеличивает риск багов и замедляет разработку.

Когда DRY может навредить?

DRY вредит при преждевременной абстракции: когда два похожих, но семантически разных участка кода насильно объединяют в одну функцию. Это порождает сложный, перегруженный параметрами код. Rule of Three помогает избежать этой ошибки: абстрагируйте только после третьего повторения.

Как применять DRY в Android-проектах?

В Android DRY применяется через version catalog (libs.versions.toml), общие базовые классы для адаптеров, ViewModel фабрики и утилитарные расширения Kotlin. Рекомендуется выносить бизнес-логику в shared-модули (KMM) и использовать View Binding для устранения дублирования findViewById.

Как применять DRY в iOS-проектах?

В iOS DRY достигается через протоколы с default implementation, общие сетевые конфигурации (NetworkConfig), фабрики ячеек UICollectionView и SPM-пакеты с общей бизнес-логикой. Extensions стандартных типов (Date, String, URL) сокращают дублирование форматирования и валидации.

Итоги

  • DRY (Don't Repeat Yourself) — принцип однократного хранения каждого знания в системе, сформулированный в книге «The Pragmatic Programmer».
  • Дублирование кода — главный источник технического долга, увеличивающий стоимость изменений и риск багов.
  • Copy-paste без рефакторинг приводит к расхождению копий и несинхронным правкам при изменении требований.
  • Rule of Three — практическое правило: абстрагируйте код только после того, как он встретился в трёх местах.
  • Композиция предпочтительнее наследования для устранения дублирования в мобильных проектах.
  • Version catalog (libs.versions.toml) централизует управление зависимостями в Android и сокращает конфликты на 52%.
  • Преждевременная абстракция вреднее дублирования — не абстрагируйте случайные синтаксические совпадения, отличайте их от системного дублирования знания.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также