Support us

«Этот код выглядит ужасно, но работает». Что чинить первым, а что лучше не трогать

«Худшая стратегическая ошибка, какую может совершить софтверная компания», — так в апреле 2000 года Джоэл Спольски, сооснователь Fog Creek Software, назвал решение Netscape переписать код с нуля. С выхода версии 4.0 прошло почти три года, а версии 5.0 так и не случилось. Соблазн снести «ужасный» модуль знаком каждому, кто открывал чужой код ради мелкой правки.

Оставить комментарий
«Этот код выглядит ужасно, но работает». Что чинить первым, а что лучше не трогать

«Худшая стратегическая ошибка, какую может совершить софтверная компания», — так в апреле 2000 года Джоэл Спольски, сооснователь Fog Creek Software, назвал решение Netscape переписать код с нуля. С выхода версии 4.0 прошло почти три года, а версии 5.0 так и не случилось. Соблазн снести «ужасный» модуль знаком каждому, кто открывал чужой код ради мелкой правки.

Примечание Adviser

В статье есть ссылки партнеров. Это значит, что если вы что-то покупаете с нашей помощью — вы также поддерживаете dev.by. (Вот другой способ).

При этом редакция и авторы независимы в выборе темы, концепции материала, фокуса описания, подхода к услугам или товарам. Прежде чем что-то советовать, мы много читаем и смотрим по теме, говорим с экспертами.

Редакция может выражать свое мнение и пробовать всё на себе.

Если рекомендательный материал обновляется, мы указываем, что и когда поменялось, в самом начале.

Почему код, который так бесит, не всегда стоит спринта

Опасно оценивать масштаб техдолга на глаз. Код сам по себе статичен, а пометки «тут неаккуратно» и «здесь длинный метод» ничего не говорят о том, как живёт система: что в ней меняют и что годами работает без правок.

О риске судят по поведению кода. Консультант Майкл Фезерс в книге «Working Effectively with Legacy Code» называет легаси-кодом просто код без тестов.

Аккуратный по всем правилам модуль без тестов — пороховая бочка: любая правка рискует что-нибудь сломать. А «уродливый», зато покрытый тестами и изолированный модуль может годами работать и никому не мешать.

Техдолг к тому же бывает разным. Мартин Фаулер, автор книги «Рефакторинг», делит его по двум критериям.

  • Намеренный или непреднамеренный. Команда либо берёт долг сознательно, например чтобы успеть к релизу, либо обнаруживает его позже, когда узнаёт больше и видит, как можно было сделать лучше.
  • Обдуманный или безрассудный. Обдуманный компромисс ради релиза иногда и гасить не стоит, если проценты по нему невелики. Безрассудный долг берут без веской причины.

Бороться с некрасивым кодом, не разобравшись, откуда он взялся и как себя ведёт, значит превратить работу в бесконечный косметический ремонт.

А цена вопроса может быть немалая. По опросу Stripe и Harris Poll 2018 года (разработчики и руководители из США, Великобритании, Франции, Германии и Сингапура) разработчики оценивают, что из 41 часа недели около 17 уходит на отладку, рефакторинг, плохой код и техдолг. Четыре часа на «плохой код» Stripe оценивает почти в $85 млрд упущенной выгоды в год.

По данным CISQ за 2022 год, накопленный техдолг в США достиг примерно $1,52 трлн.

Ресурсов на всё не хватит, поэтому нужен способ отделить настоящие риски от мнимых.

По какому правилу выбирать, что чинить первым

Чтобы спор о техдолге опирался на данные, можно взять простую формулу:

Приоритет = Цена отказа (Cost of Failure / Risk) × Частота касания (Git Churn)

В ней две составляющие.

Частота касания (Git Churn). Правки в кодовой базе обычно распределены неравномерно: у этого распределения длинный хвост (long tail), и большинство файлов в репозитории почти не меняются. Если код неидеален, но его редко трогают, рефакторинг не окупится. Смысл есть там, где код меняют регулярно.

Цена отказа (Cost of Failure / Risk). Эта ось отвечает на вопрос, что будет, если модуль сломается. Её определяют вероятность падения продакшена и его цена, то, насколько код тормозит команду, и метрики сложности: показатель Code Health (метрика CodeScene), цикломатическая сложность по Маккейбу (число независимых путей выполнения), плотность дефектов.

Хотспоты, где они пересекаются. Если наложить частоту изменений на сложность, получатся хотспоты (hotspots). По словам Адама Торнхилла, основателя CodeScene, в докладе на SREcon 2024, они занимают всего 2–4% кодовой базы, но притягивают 20–70% всей активности разработки.

Как это выглядит на практике, Торнхилл показал в статье Prioritizing Technical Debt in React: он разобрал в CodeScene открытый демо-проект на кодовой базе React, около 130 000 строк. Главным хотспотом оказался файл ReactFiberBeginWork.js: больше 3000 строк, показатель Code Health за год упал с 4 до 2,41 (по шкале, где 10 лучший).

Переписывать такой файл целиком слишком рискованно, поэтому Торнхилл применил метод X-Ray, разбор хотспотов на уровне отдельных функций. Первым кандидатом на рефакторинг оказалась функция beginWork: она сложна, часто меняется, и сложность растёт.

Что чинить, а что лучше оставить в покое

Частота правок и риск дают четыре зоны, и для каждой свое решение.

  • Часто правят, и код рискованный: хотспот. Сложный, нестабильный код, который постоянно трогают. Чинить первым: отдача здесь выше всего. Проблемы в хотспоте, по словам Торнхилла, обходятся дороже всего: это долг с высокими процентами.
  • Часто правят, но код простой. Понятный код, в который регулярно добавляют фичи. Глубокий рефакторинг тут не нужен, хватит автотестов и проверок качества в CI/CD.
  • Правят редко, но код страшный. Сложный, «уродливый» legacy-код, который работает без правок. Лучше не трогать: менять такой код рискованно, а выгоды нет.
  • Правят редко, и код простой. Простые модули, которые почти не обновляются. Про них можно забыть.

Этот же вопрос обсуждают разработчики на Reddit тот же вопрос: когда код поддерживают, когда рефакторят, а когда переписывают

How to determine when to maintain, refactor or rewrite an application?
by u/MossRock42 in ExperiencedDevs

И немного о «замороженном» коде. Возьмём условный пример: модуль нарушает все паттерны, но пять лет работает без сбоев и доработок не требует. Любая правка тут рискует сломать работающую систему.

Сейчас соблазн снести такой модуль стал сильнее: кажется, что нейросеть перепишет его за вечер. Голо Роден, основатель и технический директор компании the native web, пишет в колонке на heise (май 2026 года): «Печатать — не то, что будет выматывать команды в ближайшие годы. Читать — вот что». Впрочем, Спольски сформулировал закон ещё в 2000 году: читать код труднее, чем писать. Там было сказано, что в старом коде многие баги уже найдены и исправлены.

То же с компонентами, которые выводят из эксплуатации (System End-of-Life): если сервис заменят через полгода, чинить долг сервиса нет смысла.

Когда в сложный legacy-модуль всё же нужно добавить фичу, но переписывать целиком опасно, Фезерс описывает для этого два приёма, у каждого по два варианта:

  • Sprout Method / Sprout Class: новую логику пишут в новом методе или классе, которые вызывает старый код.
  • Wrap Method / Wrap Class: старый метод или класс оборачивают новым, который добавляет поведение и передаёт вызов старому.

Как найти хотспоты без дорогих инструментов

Для начала хватит данных, которые уже есть в системе контроля версий: Git хранит бесплатный поведенческий лог того, как команда работает с кодом. Частоту изменений можно выгрузить из истории коммитов стандартными командами git log.

Инструменты с открытым кодом:

  • Skunk считает для Ruby-кода показатель SkunkScore по сложности, запахам кода и покрытию тестами и показывает самые проблемные модули.
  • Detective работает с TypeScript-проектами: находит по истории git хотспоты и change coupling, то есть неочевидную связанность файлов.
  • RubyCritic собирает отчёт о качестве Ruby-кода на основе статических анализаторов Reek, Flay и Flog.

Баг-трекер. Частоту правок стоит наложить на журнал инцидентов: алерты P1/P2, тикеты поддержки. Модуль, где и правок много, и баги находят регулярно, и есть хотспот номер один.

Как договориться с менеджером, которому не до рефакторинга

Матрица хотспотов хорошо работает на уровне отдельных модулей. Мелкие правки делают вместе с текущими задачами: автотесты и локальный рефакторинг, без отдельного времени на «уборку». Крупные изменения, вроде распила монолита на микросервисы или переезда на другой фреймворк, считают вместе с владельцем продукта: что они дадут бизнесу и когда.

О том, как вносить такой долг в план, когда дорожной картой управляет продукт, тоже спорят на Reddit.

How do you get tech debt into a sprint when product owns the roadmap?
by u/Evening_Meringue8414 in ExperiencedDevs

Что почитать и пройти, если хочется копнуть глубже

Вот три материала, по одному на задачу.

Если нужно безопасно менять код без тестов

  • Книга Working Effectively with Legacy Code (Michael Feathers). Книга Фезерса о том, как менять системы без тестов: каталог приёмов разрыва зависимостей, чтобы код можно было покрыть тестами.

Если нужно находить проблемные места по истории git

  • Книга Software Design X-Rays: Fix Technical Debt with Behavioral Code Analysis (Adam Tornhill). Торнхилл показывает, как опираться на данные, которые уже есть в системе контроля версий: находить хотспоты и change coupling, следить за трендами сложности. Серебряной пули, по словам автора, метод не даёт.

Если нужны основы чистого кода и приёмов рефакторинга

  • Курс Clean Code and Refactoring Techniques (Coursera). Начальный курс от Edureka, примеры на Python: как находить запахи кода (code smells), рефакторить функции, условия и классы и безопасно менять унаследованный код с помощью автотестов.

С чего начать рефакторинг

Если коротко, порядок такой:

  • Не чините код только потому, что он бесит. Уродливый модуль, который стоит без правок и без багов, работает на вас.
  • Выгрузите из Git частоту изменений и наложите на карту инцидентов.
  • Начните с хотспотов.
Читайте также
Фатальная интеграция: почему умные руководители принимают наихудшие решения. Бесплатный воркшоп от Стратоплана
Фатальная интеграция: почему умные руководители принимают наихудшие решения. Бесплатный воркшоп от Стратоплана
Фатальная интеграция: почему умные руководители принимают наихудшие решения. Бесплатный воркшоп от Стратоплана
В спокойной обстановке, читая книги и статьи по менеджменту, вы прекрасно знаете, как поступать правильно: нужно делегировать, давать развивающий фидбек и говорить с бизнесом на языке экономики. Но когда случается реальный факап — горит релиз, заказчик требует результатов, а команда на взводе — теории испаряются. В стрессе вы не поднимаетесь до уровня своих ожиданий, а падаете до уровня автоматизмов.
Объяснение на страницу: почему не читают документацию и что исправить в первую очередь
Объяснение на страницу: почему не читают документацию и что исправить в первую очередь
Объяснение на страницу: почему не читают документацию и что исправить в первую очередь
Вы только что обновили README, добавили схемы в Confluence и закрыли самые частые вопросы. Но через пару дней кто-то из коллег всё равно пишет: «А как правильно?» Обычно после такого предлагают лучше  документировать — и начинают добавлять страницы. Есть другое решение.
3 комментария
Как не превратить пет-проект во вторую работу: правила безопасного размера
Как не превратить пет-проект во вторую работу: правила безопасного размера
Как не превратить пет-проект во вторую работу: правила безопасного размера
Вы садитесь за свой проект в десять вечера, потому что днём было некогда. Правите баг, замечаете второй, к полуночи переписываете модуль, который вообще-то работал. А наутро вспоминаете про дедлайн, который сами себе и поставили. Кажется, это уже не совсем хобби.
Год перерыва в IT: c какой ступеньки лучше возвращаться в профессию
Год перерыва в IT: c какой ступеньки лучше возвращаться в профессию
Год перерыва в IT: c какой ступеньки лучше возвращаться в профессию
После перерыва в карьере есть три пути: вернуться джуном, пойти на оплачиваемую программу для возвращающихся (returnship) или сразу откликаться на свой уровень. Разбираем, кому что подходит и когда шаг вниз всё-таки оправдан.
2 комментария

Хотите сообщить важную новость? Свяжитесь с редакцией через страницу контактов

Главные события и полезные ссылки в нашем Telegram-канале

Обсуждение
Комментируйте без ограничений

Релоцировались? Теперь вы можете комментировать без верификации аккаунта.

Комментариев пока нет.