Принцип WET
Принцип WET — это неформальный антипаттерн в разработке программного обеспечения, который заключается в избыточном дублировании кода, данных или логики. Аббревиатура WET расшифровывается как «Write Everything Twice» (пиши всё дважды) или, в более ироничной форме, «We Enjoy Typing» (нам нравится печатать). Принцип WET является противоположностью принципу DRY (Don’t Repeat Yourself), который предписывает избегать повторений и выносить общую функциональность в единое место. Нарушение принципа DRY приводит к появлению WET-кода, что увеличивает сложность поддержки, повышает риск ошибок и замедляет разработку.
История и происхождение
Термин WET возник как шуточная антономасия к принципу DRY, впервые сформулированному Эндрю Хантом и Дэвидом Томасом в книге «The Pragmatic Programmer» (1999). В сообществе разработчиков быстро заметили, что на практике многие проекты не следуют рекомендациям DRY, и для описания таких ситуаций стали использовать аббревиатуру WET. Первое задокументированное использование термина в публичном обсуждении датируется началом 2000-х годов, когда на форумах и в блогах обсуждались последствия копирования кода. С тех пор понятие прочно вошло в лексикон программистов, особенно в контексте рефакторинга и code review.
Основные проявления WET
WET-код может проявляться в различных формах, от простого копирования строк до дублирования целых модулей.
Копирование и вставка (Copy-Paste)
Самая распространённая форма WET — когда разработчик копирует блок кода из одного места в другое, внося минимальные изменения. Например, в веб-приложении может быть несколько страниц, на которых отображается таблица с данными, и для каждой страницы написан отдельный HTML-шаблон, хотя структура таблицы идентична. При необходимости изменить внешний вид таблицы придётся править каждый шаблон по отдельности, что чревато пропуском одного из них.
Дублирование логики
Более сложный случай — когда одна и та же бизнес-логика реализована в разных частях системы. Например, расчёт налоговой скидки может быть прописан и в контроллере, и в представлении, и в хранимой процедуре базы данных. Если правила расчёта изменятся, разработчику придётся синхронизировать изменения во всех трёх местах, что увеличивает вероятность ошибки.
Дублирование данных
WET-принцип распространяется не только на код, но и на данные. В базах данных это может выражаться в хранении одной и той же информации в нескольких таблицах без нормализации. Например, адрес клиента может дублироваться в таблицах заказов и контактов, что приводит к аномалиям обновления и несогласованности данных.
Причины возникновения WET
Разработчики редко сознательно стремятся к созданию WET-кода. Обычно это происходит из-за ряда объективных и субъективных факторов.
Срочность и давление сроков
В условиях жёстких дедлайнов программист может предпочесть быструю вставку готового кода вместо рефакторинга и выделения общей абстракции. Такой подход даёт немедленный результат, но создаёт технический долг, который приходится погашать позже.
Недостаток знаний или опыта
Младшие разработчики могут не осознавать вред от дублирования или не знать, как правильно организовать код для его повторного использования. В результате они интуитивно копируют то, что уже работает, вместо того чтобы проектировать общие модули.
Страх изменений
В больших проектах с плохой архитектурой разработчики могут опасаться, что изменение существующего кода сломает другие части системы. Поэтому они предпочитают написать новый, похожий код, не трогая старый, даже если это приводит к дублированию.
Отсутствие code review
Если в команде не принято проверять код коллег, дублирование может оставаться незамеченным долгое время. Code review помогает выявлять WET-паттерны на ранней стадии и предлагать рефакторинг.
Последствия WET для проекта
Дублирование кода и данных влечёт за собой ряд негативных последствий, которые усугубляются по мере роста проекта.
Увеличение стоимости сопровождения
Каждое дублированное место требует отдельного внимания при внесении изменений. Чем больше копий, тем выше трудозатраты на поддержку. Исследования показывают, что стоимость исправления ошибки в WET-коде может быть в несколько раз выше, чем в DRY-коде, из-за необходимости синхронизации правок.
Рост вероятности ошибок
При ручном копировании легко пропустить строку или забыть изменить переменную. Кроме того, если одно из дублированных мест не будет обновлено при изменении логики, система начнёт работать некорректно. Такие ошибки часто трудно обнаружить, так как они проявляются не во всех сценариях.
Увеличение объёма кода
WET-код раздувает кодобазу, что замедляет компиляцию, увеличивает время загрузки и усложняет навигацию по проекту. Новым разработчикам сложнее разобраться в системе, где много повторяющихся фрагментов.
Снижение производительности команды
Разработчики тратят время не на создание новой функциональности, а на поиск и исправление ошибок, вызванных дублированием. Это снижает общую скорость разработки и демотивирует команду.
Способы борьбы с WET
Основной метод борьбы с WET — следование принципу DRY, но на практике требуется комплексный подход.
Рефакторинг
Выявление дублированного кода и его замена на общие функции, классы или модули. Например, если в нескольких местах встречается один и тот же цикл обработки данных, его можно вынести в отдельный метод. В объектно-ориентированном программировании для этого часто используют наследование или композицию.
Использование шаблонов проектирования
Применение шаблонов, таких как «Фабричный метод» (Factory Method), «Стратегия» (Strategy) или «Шаблонный метод» (Template Method), позволяет избежать дублирования за счёт вынесения общей логики в базовые классы или интерфейсы.
Автоматизация проверок
Статические анализаторы кода (например, SonarQube, ESLint, Pylint) могут автоматически выявлять дублированные фрагменты и предупреждать разработчика. В некоторых системах контроля версий (например, Git) можно настроить хуки, которые блокируют коммит, если обнаружен дубликат.
Культура code review
Регулярные ревью кода помогают команде совместно выявлять WET-паттерны и обсуждать лучшие способы их устранения. В процессе ревью можно предложить альтернативные решения, которые будут более эффективными.
Документирование архитектуры
Чёткая документация о том, какие части кода отвечают за какую функциональность, снижает риск случайного дублирования. Разработчики, зная, что уже существует готовая функция для расчёта скидки, не будут писать её заново.
Критика и ограничения принципа DRY
Несмотря на очевидные преимущества DRY, слепое следование этому принципу может привести к обратным проблемам. Чрезмерная абстракция, когда разработчик пытается устранить любое, даже малозначительное дублирование, порождает сложный, трудночитаемый код. Такой подход иногда называют «преждевременной абстракцией» или «DRY-абсолютизмом».
В некоторых случаях дублирование оправдано. Например, если два фрагмента кода выглядят одинаково, но решают разные задачи и могут меняться независимо, их объединение в одну функцию приведёт к усложнению. В веб-разработке часто дублируют CSS-стили для разных компонентов, чтобы избежать каскадных конфликтов. В базах данных денормализация (намеренное дублирование данных) может быть оправдана для повышения производительности чтения.
Таким образом, принцип WET не является абсолютным злом, а скорее индикатором того, что в проекте отсутствует баланс между абстракцией и простотой. Задача разработчика — оценить, когда дублирование действительно вредно, а когда оно является разумным компромиссом.
Примеры из практики
Пример 1: Веб-приложение на PHP
На сайте интернет-магазина есть три страницы: каталог товаров, корзина и страница оформления заказа. На каждой странице отображается блок «Рекомендуемые товары». Разработчик скопировал код для отображения этого блока на каждую страницу. Когда потребовалось изменить логику рекомендаций (например, добавить фильтр по цене), пришлось править три файла. После рефакторинга код блока был вынесен в отдельную функцию, которая вызывается на всех страницах.
Пример 2: Микросервисная архитектура
В двух микросервисах, отвечающих за обработку заказов и управление пользователями, дублируется логика валидации email-адреса. Если регуляторное требование изменится (например, добавятся новые домены), обновлять придётся оба сервиса. Решением может быть вынесение валидации в общую библиотеку, которая подключается как зависимость.
Пример 3: Конфигурационные файлы
В проекте на Python используется несколько конфигурационных файлов для разных окружений (development, staging, production). В каждом файле дублируются общие параметры, такие как адрес базы данных или ключи API. При смене пароля базы данных нужно менять его во всех файлах. Использование переменных окружения и базового конфигурационного файла с наследованием решает эту проблему.
Источники
- Хант Э., Томас Д. «Программист-прагматик. Путь от подмастерья к мастеру». — М.: Лори, 2004.
- Фаулер М. «Рефакторинг. Улучшение существующего кода». — СПб.: Символ-Плюс, 2003.
- Мартин Р. «Чистый код. Создание, анализ и рефакторинг». — СПб.: Питер, 2010.
- Сборник статей по принципам DRY и WET на портале Habr (2015–2023).
- Документация статического анализатора SonarQube по обнаружению дубликатов кода.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →