Когда стоит намочить ваш код: почему слепое следование DRY вредит проекту
Принцип DRY (Don’t Repeat Yourself) - пожалуй, одно из первых правил, которые мы усваиваем как разработчики. Его идея кажется безупречной: не повторяй код, не дублируй знания, всё, что повторяется, вынеси в общее место.На практике это означает: если кусок логики повторяется в нескольких местах, его нужно сделать общим - в виде функции, класса, модуля или компонента.Так проект становится чище, поддерживать его проще, а изменения - безопаснее. Исправил ошибку в одном месте - она исчезла повсюду.
В бизнес-логике, особенно на backend, DRY работает великолепно.К примеру, валидация данных, расчёт скидок или правила авторизации - это те самые повторяющиеся знания, которые должны быть централизованы. Когда подобная логика разбросана по разным сервисам, ошибки неизбежны. В таких случаях DRY экономит месяцы жизни, делает систему предсказуемой и облегчает рефакторинг.
Но мой личный опыт - а я в основном работаю со стартапами и быстро меняющимися фронтенд-проектами - показал, что этот принцип, если применять его догматично, способен сильно навредить.Когда требования меняются буквально каждую неделю, а дизайн живёт своей жизнью, следование DRY превращается из средства чистоты кода в тормоз развития продукта. Чем «зрелее» проект, тем «суше» он может быть. Но на ранних стадиях чрезмерная сухость губительна.
DRY в теории: сильные стороны и изначальная задумка
DRY появился не как борьба с повторением кода ради эстетики, а как борьба с повторением знания.Авторы принципа - Эндрю Хант и Дэвид Томас в книге The Pragmatic Programmer - объясняли: если в коде повторяется не просто синтаксис, а одно и то же бизнес-правило, это признак ошибки в архитектуре.
Суть проста:
- Любое знание должно существовать только в одном месте.
- Изменение этого знания должно потребовать изменения только одного фрагмента кода.
Это обеспечивает согласованность, снижает риск ошибок и упрощает тестирование.DRY делает код устойчивым и прозрачным, если речь идёт о повторяющихся данных, формулах, бизнес-правилах, вычислениях или константах.
Где DRY действительно работает
Всё, что касается backend-логики, - там DRY незаменим.Например:
- общие функции работы с базой данных,
- централизованная обработка ошибок,
- единые правила расчёта цен и скидок,
- повторяющиеся модели данных и их валидация.
В таких областях дублирование логики может привести к расхождениям и багам. Там DRY помогает не просто сэкономить строки кода, а сохранить смысловую целостность проекта.
Когда DRY превращается в ловушку
Риск чрезмерной абстракции и падение читаемости
Главная ошибка - применять DRY автоматически, не глядя на контекст. Желание «собрать всё в одно место» часто рождает монструозные абстракции. Разработчик объединяет несколько похожих кусков кода и в итоге создает функцию с кучей условий, параметров и флагов, которая делает всё сразу - но уже непонятно что именно.Такие универсальные модули превращаются в черные ящики: изменить их сложно, отлаживать больно, а новый разработчик тратит часы, чтобы понять, как всё работает.
Когда-то я участвовал в проекте, где нужно было просто поменять цвет кнопки на одной странице. Но компонент кнопки был настолько «высушен» - общая фабрика, десятки пропсов, глобальные стили - что разобраться заняло около четырёх часов. Ирония в том, что весь интерфейс содержал всего десять таких кнопок. Это был классический случай, когда желание следовать DRY во что бы то ни стало обернулось катастрофой.
Повышенная связность и хрупкий дизайн
Когда всё объединено в один общий модуль, любая мелкая правка превращается в минное поле.Изменил что-то для одной страницы - и вдруг что-то сломалось в другом месте.Так рождается жесткая связность (tight coupling), при которой независимые части системы становятся заложниками общей логики.
Парадоксально, но аргумент «всё исправляется в одном месте» работает и наоборот: ошибка, добавленная в одно место, мгновенно распространяется повсюду. В результате проект превращается в хрупкий механизм, где тронешь одно - посыплется всё.
Преждевременная абстракция - главный враг гибкости
DRY изначально задумывался не как борьба с повтором кода, а как борьба с повтором знания. Но часто разработчики объединяют куски, которые просто похожи, а не эквивалентны.Поначалу это кажется логичным: «зачем писать одно и то же дважды?»А потом выясняется, что эти куски развиваются в разные стороны, и в результате абстракция начинает мешать.
Я часто сталкивался с этим в стартапах, где продукт быстро эволюционирует. Требования меняются каждую неделю, дизайн - каждый день. В таких условиях преждевременная абстракция только тормозит процесс: приходится постоянно добавлять исключения, новые параметры и ветвления, чтобы не нарушить общий код.Намного проще - повторить небольшой кусок кода, дождаться, пока функционал стабилизируется, и лишь потом вынести общие части. Это соответствует правилу «трёх повторов»: если ты написал одно и то же трижды - тогда пора задуматься об абстракции.
Архитектурные ловушки и «распределённый монолит»
В микросервисах принцип DRY особенно опасен. Разработчики часто создают общие библиотеки, чтобы «не дублировать код». На практике это выливается в распределённый монолит - систему, где все сервисы зависят от одной общей зависимости.В итоге независимость микросервисов теряется: обновить библиотеку можно только одновременно во всех сервисах, а любая мелочь может поломать десятки компонентов.
С течением времени такие общие «commons» превращаются в свалку мусора: туда складывают всё подряд, но никто не рискует ничего удалить. Так вместо чистоты и порядка DRY рождает хаос и технический долг.
Особенно часто это происходит во фронтенд-командах, где общие утилиты и компоненты перерастают в неуправляемые «UI-библиотеки», переполненные старыми функциями, которые страшно трогать. Всё вроде бы «сухо», но никто уже не понимает, как оно работает.
Когда DRY противоречит здравому смыслу
В реальной жизни мы не создаем идеальные симметричные системы.Например, во фронтенд-проектах я часто вижу, как универсальные компоненты интерфейса превращаются в чудовищ: один «мега-компонент» кнопки принимает десятки пропсов, поддерживает десятки вариантов, а потом всё равно приходится клонировать его, чтобы сделать «кнопку со скругленными краями и другим hover».
Когда дизайнер внезапно решает, что теперь у нас будут три формы кнопок, сорок оттенков цвета и разные реакции на наведение - весь замысел DRY рушится.Иногда проще иметь три независимых, но понятных компонента, чем один гибрид, который никто не может поддерживать.
В молодом проекте, где всё постоянно меняется, универсальные абстракции не дают ускорения - они создают инерцию. Там, где важно быстро пробовать, менять и адаптироваться, дублирование оказывается гораздо дешевле и безопаснее.
Когда стоит «намочить» DRY
Иногда дублирование кода - осознанное решение.Если похожие куски выполняют разные задачи, развиваются независимо и меняются по-разному - их стоит оставить раздельными.Такой подход даже получил собственное название - WET (Write Everything Twice).
Это не призыв к хаосу, а признание того, что иногда дублирование дешевле, чем неправильная абстракция.Особенно это актуально во фронтенде и молодых продуктах, где требования меняются быстрее, чем успевают стабилизироваться архитектурные решения.Для бизнес-логики и бекенда DRY действительно спасает - например, при работе с расчётами, валидацией, запросами к базе данных. Но в пользовательском интерфейсе и на ранних этапах развития продукта - прагматизм должен побеждать догматизм.
Заключение
DRY - замечательный принцип, если применять его осознанно.Он помогает поддерживать порядок, но легко превращается в источник проблем, когда из правила делают религию.
Особенно на фронтенде и в молодых проектах догматичный DRY приносит больше вреда, чем пользы.Чем динамичнее проект, тем важнее гибкость, независимость и простота.Пусть код немного повторяется - зато он живёт своей жизнью, развивается независимо и легко адаптируется к новым требованиям.
В конце концов, программирование - это не борьба с повтором, а поиск баланса между чистотой, скоростью и здравым смыслом.