Дублирование дешевле неправильной абстракции
Разработчик A замечает дублирование кода, извлекает его в новую абстракцию и тут же понимает, что решил проблему. Разработчик B получает новое требование, которое почти подходит существующей абстракции. Чтобы сохранить её, B добавляет параметр и условную логику. Затем приходит требование C, потом D. Конечная абстракция обрастает условными ветками, становится непонятной и ломкой, каждое новое изменение рискует сломать весь механизм.
Вместо попытки спасти усложнившуюся абстракцию через укол новых параметров, Sandi Metz рекомендует развернуться назад: разворошить абстракцию обратно на дублирование, дать каждому вызывающему коду только нужные ему части. Это удаляет условия и возвращает ясность. Затем, глядя на полученное дублирование, можно увидеть, какие новые правильные абстракции действительно нужны. Сложность и сроки давления часто сбивают разработчиков инвестировать в спасение неправильной абстракции вместо того, чтобы её заменить.
Ключевые факты
- Дублирование код дешевле неправильной абстракции, которая со временем обрастает условной логикой.
- Когда абстракция требует всё больше параметров и условных веток, это сигнал, что она перестала быть правильной.
- Решение: развернуть абстракцию обратно на дублирование, дать каждому месту только нужный код, потом извлечь новые, правильные абстракции.
- Ошибка падение уходить от неправильной абстракции часто вызвано предубеждением (sunk cost fallacy) про затраты на её создание.
- Разработчикам помогает смена фокуса: «Этот код когда-то был правильным, но теперь мы многое узнали. Давайте пересмотрим» вместо «Надо спасти вложения».
Почему это важно
Неправильные абстракции, один из самых дорогих багов в рефакторинге. Когда абстракция, которая когда-то решала проблему, становится граблями с условиями и параметрами, она замораживает кодовую базу. Каждое новое требование требует новую ветку в условной логике. Разработчики начинают бояться трогать такой код, что замедляет доставку фич. Мец показывает, что в этот момент лучше стратегический шаг назад: разворшить абстракцию, чем продолжить её усложнение.
Кому это важно
Программистам и архитекторам, которые поддерживают кодовые базы больше полугода и видят, как требования расходятся с исходным дизайном. Лидам команд, которые занимаются оценкой стоимости добавления фич в старый код и кажется, что всё дороже. Начинающим разработчикам, которые думают, что абстракция всегда хороша и что дублирование, враг.
Как это применить
Когда видишь, что в общей функции накапливается условная логика и параметры перестали быть простыми, остановись. Напиши каждого вызывающего клиента отдельно, используя только нужные ему части. Посмотри, какое дублирование появилось. Потом, если видишь, что в разных копиях есть общий паттерн, извлеки правильную абстракцию. Это не отступление, это переобучение на свежих данных. Часто это займёт меньше времени, чем возня с параметрами.
Можно ли доверять
Мец, автор нескольких книг по объектно-ориентированному дизайну и лектор RailsConf. Идею выдвинула уже в 2014 году, и за 12 лет она получила поддержку в сообществе. Статья предлагает конкретный, проверенный паттерн, а не умозрительное рассуждение. Сама рекомендация консервативна и безопасна.
Риски и подводные камни
Легко впасть в другую крайность и дублировать код везде, боясь всяких абстракций. Истина посередине. Также нужен опыт, чтобы различить, где абстракция перестала быть правильной, а где просто сложное требование. И имеет смысл этот рефакторинг делать, когда в коде появляется новое требование, не в самом начале, иначе рискуешь рефакторить то, что не сломалось.
«Дублирование дешевле неправильной абстракции»
— Sandi Metz, 'The Wrong Abstraction'