.NET Tutorial
Senior6 мин чтенияВопрос 5 из 8

Технический долг: что это и как объяснить бизнесу необходимость рефакторинга?

Что такое технический долг

Быстрое решение:
фича вышла на 2 недели раньше

Каждое изменение
в этом коде дольше на 30%

Баги из-за хрупкости,
инциденты

Команда боится трогать код,
новички не понимают

Фичи, которые раньше
занимали неделю, — месяц

Быстрое решение:
фича вышла на 2 недели раньше

Каждое изменение
в этом коде дольше на 30%

Баги из-за хрупкости,
инциденты

Команда боится трогать код,
новички не понимают

Фичи, которые раньше
занимали неделю, — месяц

Проценты по долгу

Долг — это не только «плохой код»:

Вид долга Примеры
Код Дублирование, God-классы на 3000 строк, отсутствие границ между модулями
Архитектура Общая БД у сервисов, синхронные цепочки вызовов, отсутствие идемпотентности
Тесты Нет тестов на критичную логику, флакающие тесты, которые все игнорируют
Инфраструктура Ручной деплой, нет мониторинга, конфигурация на серверах вручную
Зависимости .NET Core 3.1 без поддержки, пакеты с уязвимостями, заброшенные библиотеки
Знания Только один человек понимает биллинг, нет документации

Квадрант технического долга

Разумный

Осознанный:
«Выпускаем сейчас,
исправим после релиза»

Неосознанный:
«Теперь мы знаем,
как надо было сделать»

Безрассудный

Осознанный:
«Нет времени на дизайн»

Неосознанный:
«Что такое слои?»

Разумный

Осознанный:
«Выпускаем сейчас,
исправим после релиза»

Неосознанный:
«Теперь мы знаем,
как надо было сделать»

Безрассудный

Осознанный:
«Нет времени на дизайн»

Неосознанный:
«Что такое слои?»

Квадрант Мартина Фаулера

Разумный осознанный долг — инструмент: взяли, записали, вернули. Проблема — долг, который никто не фиксирует и не возвращает.

Как объяснить бизнесу

Бизнесу не интересно, что «код некрасивый». Интересно: деньги, скорость, риски.

В модуле заказов нет тестов
и всё связано со всем

Каждая фича в заказах —
на 2 недели дольше,
3 из 5 последних инцидентов — отсюда

Мы на .NET 6,
поддержка закончилась

Уязвимости больше не закрываются —
риск утечки и штрафов,
не пройдём аудит PCI DSS

Ручной деплой
по инструкции

Релиз раз в 2 недели,
4 часа работы двух человек,
ошибки при выкатке

В модуле заказов нет тестов
и всё связано со всем

Каждая фича в заказах —
на 2 недели дольше,
3 из 5 последних инцидентов — отсюда

Мы на .NET 6,
поддержка закончилась

Уязвимости больше не закрываются —
риск утечки и штрафов,
не пройдём аудит PCI DSS

Ручной деплой
по инструкции

Релиз раз в 2 недели,
4 часа работы двух человек,
ошибки при выкатке

Перевод с технического на бизнес-язык

Структура аргумента:

  1. Проблема в цифрах: сколько времени/денег теряем сейчас (время на фичи в модуле, число инцидентов и их стоимость, время на ручные операции).
  2. Риск: что будет, если не делать (безопасность, соответствие требованиям, отказ ключевого клиента, уход людей).
  3. Предложение: что конкретно сделать, сколько стоит, в какие сроки — лучше поэтапно.
  4. Результат: как изменится метрика («фичи в заказах быстрее на 30%», «деплой 10 раз в день вместо раза в 2 недели»).
  5. Связь с целями бизнеса: «в следующем квартале план — 5 фич в модуле заказов; без рефакторинга это 5 месяцев, с ним — 3,5 месяца, включая сам рефакторинг».

Метрики, которые помогают

Метрика Что показывает
Lead time / cycle time фич по модулям Где разработка тормозит
Доля времени на баги и незапланированную работу «Налог» долга
Инциденты и их причины (постмортемы) Где долг приводит к потерям
Change failure rate, MTTR (DORA) Надёжность изменений
Hotspots: частота изменений × сложность файла Где долг стоит дороже всего
Время онбординга новичка Долг знаний

Hotspot-анализ (подход Адама Торнхилла): сложный код, который редко меняется, почти не мешает. Сложный код, который меняется каждую неделю, — главный кандидат на рефакторинг.

Частота изменения файлов за год
git log --since="1 year ago" --name-only --pretty=format: -- '*.cs' | sort | uniq -c | sort -rn | head -20

Стратегии возврата долга

Технический долг

Правило бойскаута:
небольшие улучшения
в каждом PR

Рефакторинг как часть фичи:
трогаем модуль — улучшаем его

Фиксированная доля ёмкости:
15–20% каждого спринта

Крупные переработки —
инкрементально (Strangler Fig),
с измеримыми этапами

«Переписать всё с нуля»
за полгода без фич

Технический долг

Правило бойскаута:
небольшие улучшения
в каждом PR

Рефакторинг как часть фичи:
трогаем модуль — улучшаем его

Фиксированная доля ёмкости:
15–20% каждого спринта

Крупные переработки —
инкрементально (Strangler Fig),
с измеримыми этапами

«Переписать всё с нуля»
за полгода без фич

Стратегии
  • Не просите «спринт на рефакторинг» без результата: бизнес видит паузу без ценности. Лучше встраивать улучшения в фичи и показывать эффект.
  • «Переписать с нуля» почти всегда дольше и рискованнее, чем кажется: старая система содержит годы исправленных граничных случаев, а бизнес не может ждать. Strangler Fig — постепенная замена по частям.
  • Реестр долга: задачи в трекере с меткой, описанием ущерба и оценкой. Регулярно пересматривать и включать в планирование.
  • Не допускать нового безрассудного долга: ревью, Definition of Done (тесты, мониторинг), архитектурные правила в тестах (NetArchTest).

Вопросы на засыпку

Всегда ли технический долг плох?

Нет. Прототип для проверки гипотезы, MVP к важной дате, код, который скоро будет удалён, — разумные поводы взять долг. Плохо, когда долг неосознанный, не зафиксированный или никогда не возвращается, а проценты по нему съедают всю скорость команды.

Бизнес всё равно говорит «сейчас не время». Что делать?

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

Как не превратить рефакторинг в бесконечный процесс?

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

Чем рефакторинг отличается от переписывания?

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

Итог

Технический долг — это заём с процентами в виде замедления, багов и рисков. Фиксируйте его в реестре, приоритизируйте по реальному ущербу (hotspots, инциденты), возвращайте постоянно — правилом бойскаута, долей ёмкости и рефакторингом в составе фич, крупное — инкрементально. С бизнесом говорите языком денег, скорости и рисков, с цифрами и поэтапным планом.