Перейти к содержимому

Техдолг – это не то, что вы думаете

· 20 мин
Содержание

TL;DR: Слово “техдолг” больше не работает. В нём смешаны пять разных проблем, и каждая требует своей реакции. CEO слышит “дайте два месяца ничего не делать” и отказывает – он прав, пока ты приходишь без вариантов и цен. AI-агенты за два года изменили правила: код растёт быстрее, копипаст обогнал рефакторинг, обычное ревью эту скорость не держит. В статье – рамка: зачем перестать просить “спринт на рефакторинг”, как измерить долг в деньгах, какие fitness functions ставить в CI завтра, и как выстроить процесс, при котором проценты не становятся неподъёмными.


Шестнадцать разработчиков, у которых ИИ забрал четверть времени

16 опытных open-source разработчиков. Двести сорок шесть задач. Их собственные репозитории – те, в которых они сидят годами. Им дали Cursor с Claude. Сказали: работайте как обычно, мы замеряем.

До эксперимента они оценили: ИИ ускорит нас на 24%. После – спросили снова: ускорил процентов на 20. Потом им показали данные.

ИИ замедлил их работу. На 19%.

Это исследование METR от июля 2025, и оно – лучшая отправная точка для разговора про техдолг в 2026-м. Дело не в том, что ИИ – плохой инструмент. Дело в том, что разрыв между ощущением скорости и реальной скоростью составил 39 процентных пунктов у опытных людей, работавших на собственных репозиториях с нормальным инструментарием.

Если ты отстаёшь от собственной интуиции на 39 п.п. в выборке из 246 задач – что происходит на горизонте полугода, года, трёх лет?

То, что обычно называют техдолгом.

Можно сказать иначе: техдолг – это разница между тем, как быстро мы себя чувствуем, и тем, как быстро мы реально движемся. Эта разница не существует в моменте. Она копится. И в 2026-м она копится быстрее, чем когда-либо в истории отрасли.

Дальше – как с этим жить.


Почему CEO отказывает, и почему он прав

Лето 2019. Я работаю в платёжном агрегаторе – крупном, российском, давно живущем. У меня есть редкая возможность: разговаривать напрямую с CEO. Я этой возможностью пользуюсь.

Прихожу к нему как инженер.

“У нас всё плохо. Старые технологии. Деплой – ручной, на IIS, через RDP. Конкуренты сидят в Docker, у них Kubernetes и CI/CD. Нам нужно два месяца. Сделаем нормально – потом будем быстрее.”

CEO смотрит на меня. Молчит. Долго.

“Слушай. За годы я слышал это тысячу раз. Каждый разработчик, который сюда приходил, в первые шесть месяцев говорил то же самое. Каждый. Дайте два месяца, дайте три, дайте полгода – потом всё будет лучше. Никто из них не вернулся со словами “обещал – выполнил”. Что я скажу руководству? “Мы выпали на два месяца, чтобы что?""

Он прав. Я – не прав. Не в фактах: технологии действительно старые, деплой действительно ручной, конкуренты действительно опережают. Я не прав в формате разговора.

“Техдолг” – слово для разработчиков. Бизнес не понимает, что с ним делать, и это не упрёк бизнесу. Разработчик принёс в кабинет CEO жалобу под видом архитектурной задачи – и расстроился, что её не приняли как архитектурную задачу.

Через несколько месяцев и несколько таких разговоров приходит то, что в фильмах называется монтажом – переключение мышления. Я перестаю говорить “техдолг” и начинаю говорить “варианты”.

Через полгода CEO приходит с задачей: подключить Apple Pay. Конкуренты уже подключили, мерчанты спрашивают. Раньше я ответил бы:

“У нас интеграции с платёжными методами захардкожены, лапша if-else на сотни строк. Сначала нужно отрефакторить модуль, привести к нормальной архитектуре. Это три-четыре недели. Потом Apple Pay – два дня.”

Это снова разговор про “потом”. Сейчас я говорю по-другому.

“Есть два варианта.

Вариант А – быстрый. Прикручиваем Apple Pay сбоку, копипастом, как уже делалось. Две недели до прода. Работает. Но следующий метод (Google Pay, потом Samsung Pay, потом СБП) будет стоить столько же. Каждый. Три метода суммарно – шесть недель. Плюс риск: если меняется общая логика, например требования по 54-ФЗ, править придётся в каждом методе отдельно.

Вариант Б – с запасом. Сначала вытаскиваем абстракцию платёжного метода. Это четыре недели. Apple Pay поверх неё делается за три дня. Google Pay – тоже три. Любой следующий метод – снова три. Итого по трём методам пять недель. На дистанции дешевле, и не нужны разовые рывки на каждое изменение.”

CEO смотрит на оба варианта. У него теперь есть с чем работать. Он выбирает Б – потому что видит, на чём экономит.

Это тот же самый разговор, что я провалил полугодом раньше. Только без слова “техдолг”. Со словом “варианты” и цифрами.

Краткую версию этой сцены – про сам провал разговора с CEO – я уже выкладывал в телеграм-канале в самом начале серии. Здесь – полная история, с тем, что произошло дальше.


Что Каннингем имел в виду – и что мы из этого сделали

Спросите пятерых разработчиков, что такое техдолг. Получите семь определений. Один скажет “грязный код”. Другой – “всё, что нужно отрефакторить”. Третий посмотрит в код и ткнёт пальцем: “вот это. И вот это”. Каждый прав по-своему – и в этом проблема.

В 1992 году Уорд Каннингем впервые применил метафору финансового долга к коду – в рассказе про систему WyCash. Контекст был узкий: команда выпустила первую версию, появилось новое понимание домена, и встал выбор. Либо переписать кусок системы под это понимание, либо оставить как есть и двигаться дальше.

Каннингем сравнил это с финансовым долгом – потому что у долга две стороны:

  1. Вы взяли быстрее, чем сделали бы “правильно”. Это первоначальная экономия.
  2. Вы платите проценты, пока не вернёте основную сумму. Если не возвращаете – проценты накапливаются.

Ключевое в метафоре – осознанность. Каннингем не говорил про плохой код. Он говорил про осознанное решение взять shortcut с планом возврата. План – главное слово.

Поэтому “у нас плохой код” – это не техдолг. Это халтура.

Долг – это: “мы знаем, что эта реализация не подходит для второго рынка; делаем под первый, потому что нужно срочно; через квартал, когда подключим второй, переписываем под общую модель”. Срок есть. Условие есть. Критерий “вернули” есть.

“У нас всё плохо, нужен спринт на рефакторинг” – халтура. Никто никогда не возьмётся за её возврат, потому что нет ни срока, ни условия, ни критерия. Это не долг. Это кредитная карта без даты погашения и с плавающей суммой.

Когда метафору упростили до “техдолга вообще” – она перестала быть инструментом. Слово вместило несколько разных проблем. Я обычно разделяю их на пять категорий – это рабочий фрейм для разговора, а не таксономия:

  • Bug debt – известные, незакрытые баги. Закрывается backlog’ом и приоритизацией.
  • Design debt – доменная модель не подходит под текущий бизнес. Чинится переосмыслением границ: Event Storming, выделение bounded contexts (см. #3 и #4).
  • Knowledge debt – контекст потерян, документация устарела, ключевой человек ушёл, ИИ-агент написал код, который никто не понимает. ADR, парное программирование, регулярный архитектурный синк.
  • Process debt – нет CI/CD, ручной деплой, ручное тестирование, релизы по пятницам в 18:00. Снимается автоматизацией.
  • Dependency debt – устаревшие либы, фреймворки без активной поддержки от вендора, известные уязвимости без патчей. Регулярные обновления, ничего другого не помогает.

На практике они переплетаются. Bug debt часто – следствие knowledge debt’a: некому объяснить, что эта функция должна работать иначе. Process debt тянет за собой design debt: без автоматизированного теста никто не рискует менять структуру.

Когда на стендапе кто-то говорит “у нас техдолг” – он может иметь в виду любой из пяти. Или все сразу. И никто не знает, что именно.

Это первое, что нужно прекратить. Не разговор про долг – а разговор про техдолг вообще. Перед каждым обсуждением – называть конкретный тип. Перед каждой задачей в backlog – приклеить ярлык. Это пять минут работы и сдвиг в коммуникации, который видно через неделю.

“Спринт на рефакторинг” не работает по той же причине, по которой не работает “месяц спорта” в качестве плана здорового образа жизни. Разовое усилие против системной проблемы, у которой пять разных причин – каждая копится постепенно. Усилие сжигается, причины остаются.


Матрица Фаулера: команды чинят то, что и так чинится

В 2009 году Мартин Фаулер предложил разложить долг по двум осям. По первой – намеренный он или случайный (Deliberate vs Inadvertent). По второй – осознанный или безрассудный (Prudent vs Reckless). Получается четыре квадранта.

Reckless + Deliberate – “У нас нет времени на дизайн”. Знают, что делают плохо. Делают плохо специально. Самый честный квадрант, как ни странно: люди отдают себе отчёт, что закладывают мину под себя.

Prudent + Deliberate – “Мы должны зарелизить, разберёмся с последствиями потом”. Каннингемовский долг в чистом виде. Осознанный shortcut с планом возврата. План иногда выполняется, иногда нет – но он был.

Reckless + Inadvertent – “А что такое слоистая архитектура?” Не знают, что делают плохо. Делают плохо случайно, потому что не имеют рамки. Самый дорогой квадрант. И самый невидимый – потому что внутри команды никто не понимает, что прямо сейчас закладывается долг. С точки зрения автора кода – он работает нормально.

Prudent + Inadvertent – “Теперь, когда система выросла, мы понимаем, как надо было сделать”. Появился новый контекст, прежняя модель устарела. Это не вина команды – это естественная эволюция домена. Чинится переосмыслением границ.

Полезно держать эту картинку в голове. Ещё полезнее – задать один вопрос: какой квадрант лечат “спринты на рефакторинг”, когда их таки удаётся пробить?

Обычно – Prudent + Deliberate. Тот, что и так бы починился, потому что владельцы кода знают про долг и помнят про план возврата. Команды чинят то, что и так чинится. Берут самый понятный участок, на котором есть консенсус и план, и его рефакторят. Получается аккуратно, виден прогресс, можно показать менеджменту.

То, что убивает – Reckless + Inadvertent – никто не трогает. Потому что не видит. Команда не знает, в каких местах прямо сейчас формируется долг от незнания. Если бы знала – он не был бы Inadvertent.

И именно сюда в 2026-м прилетел ИИ.

ИИ-агент пишет уверенно. Код выглядит грамотно. Структура соблюдена, тесты проходят. Внутри – by-the-book реализация, копипаст похожих паттернов из обучающей выборки, вторая, третья, четвёртая копия одного и того же бизнес-правила в разных модулях. Каждая копия проходит ревью, потому что по отдельности каждая выглядит нормально. Это и есть Reckless + Inadvertent на скорости генерации. Подробно – в разделе про ИИ ниже.

Что делать с матрицей сегодня. Прогнать backlog с тегом “технический долг” через четыре квадранта. По моему опыту получается: 60-70% оказываются Prudent + Deliberate (самообслуживающиеся), 5-10% – Reckless + Deliberate (политические – кто-то в команде борется с практикой, которую команда уже приняла), и большая чёрная дыра под названием “не знаю, в каком квадранте, потому что не понимаю, какой код там работает” – это и есть Reckless + Inadvertent в чистом виде.

С Inadvertent работать иначе. Backlog здесь не помогает – потому что задача в backlog’е появляется после того, как долг обнаружили. А он не обнаружен. Нужен механизм, который ловит долг в момент возникновения. Это и есть DORA-метрики и fitness functions – то, что превращает невидимое в видимое.


Как измерить долг в деньгах: DORA-четвёрка как термометр

Вернёмся к Apple Pay-сцене из начала статьи. У варианта А и варианта Б была разная цена в часах работы – это понятно. Но у них была и другая цена, на которую инженеры обычно не смотрят.

В терминах DORA-метрик (см. также #1):

Вариант А – копипастом. Каждая новая платёжная интеграция = полный цикл с нуля, ~2 недели до прода. Lead time на одну “фичу размером с интеграцию” – стабильно высокий. Change failure rate распределён: у каждой интеграции свой набор багов, чинятся в изоляции, MTTR – средний. Deployment frequency низкая, потому что каждый релиз – это “крупный кусок”.

Вариант Б – с абстракцией. Стартовая инвестиция 4 недели – за это время ни одной новой интеграции не вышло. Throughput на этом отрезке – ниже. Но после: lead time на интеграцию падает с 14 дней до 3. Deployment frequency растёт вчетверо. Change failure rate концентрируется на единой абстракции – баги в общей части ловятся быстрее и фиксятся в одном месте, а не в трёх.

У каждого варианта своя кривая по DORA. На одном релизе А выглядит дешевле. На трёх – Б уже впереди. На пяти – А перестаёт масштабироваться.

Это и есть “измерить долг в деньгах”. Не “давайте посчитаем строки legacy-кода и переведём в человеко-часы рефакторинга” – это бессмысленно. А: как изменение в структуре кода влияет на четыре конкретных параметра доставки. И уже эти параметры – переводимы в деньги.

Грубая прикидка cost of delay. Допустим, фича после релиза приносит 100 тыс. ₽ в день. Ваш lead time – 14 дней, у конкурента – 3. На одной фиче: 11 × 100 тыс. ₽ = 1,1 млн ₽ упущенной выручки. На двадцати в год – 22 млн ₽ только за счёт того, что цикл доставки длиннее. Это и есть процент по техдолгу, выплаченный реальными деньгами.

Эту арифметику можно делать грубо – никто не требует точности до рубля. Главное – она существует. Когда вы приходите к CEO с “нам нужен месяц на абстракцию платёжных методов, потому что иначе Google Pay будет стоить столько же, сколько Apple Pay, плюс мы теряем X млн ₽ в год на пролонгациях lead time’а” – это другой разговор, чем “у нас плохой код”.

DORA – это термометр. Команды, которые не меряют четвёрку, не лечат долг – они лечат ощущения. И как любые ощущения, они бывают неправильными. Помните 39 п.п. разрыва из METR? То же самое работает на уровне команды: интуиция “у нас всё ок” легко расходится с реальностью на 30-40%.

И вот что важно для 2026 года.

Отчёт DORA 2024 показал: рост AI-adoption в команде на 25% коррелирует со снижением delivery stability на 7.2% и падением throughput на 1.5%. Не статистическая случайность – устойчивый сигнал по тысячам команд. DORA 2025 уточнил рамку: “AI doesn’t fix a team; it amplifies what’s already there”. Эффект зеркала. У команд с проработанным процессом ИИ ускоряет и улучшает. У команд без процесса – ускоряет деградацию.

Это значит: если у вас нет DORA-четвёрки до того, как вы внедряете ИИ-агентов широко – вы внедряете их вслепую. И, скорее всего, ускоряете рост Reckless + Inadvertent квадранта. Без термометра вы об этом узнаете через год, когда lead time на типовую фичу вырастет с 3 дней до 9, и никто не сможет внятно объяснить, почему.


Что произошло в 2024-м: копипаст обогнал рефакторинг

Главное число от компании GitClear, которая анализирует git-историю в инженерных оценках.

В 2024 году, впервые в их датасете из 211 миллионов изменённых строк, доля скопированного кода (12,3%) превысила долю отрефакторенного (меньше 10%). Раньше было наоборот: разработчики чаще улучшали существующий код, чем клонировали его. С приходом массового использования ИИ-агентов это перевернулось.

Это не эссе и не мнение, а git history публичных репозиториев. Сдвиг отрасли за два года.

Отчёт GitClear от января 2026 даёт ещё пару цифр: copy-paste 8,3% (2021) → 12,3% (2024), блоки клонированного кода длиной 5+ строк выросли в восемь раз. Code churn (код, переписанный в течение двух недель после коммита) – с 3,1% до 5,7%. Рефакторинг ушёл в обратную сторону.

Что это значит на уровне команды? Кодовая база растёт быстрее, чем когда-либо. Часть этого роста – клоны. Каждый клон – независимая поверхность багов, независимая точка эволюции, независимая копия бизнес-правила, которое теперь существует в трёх местах. Это и есть Reckless + Inadvertent на скорости генерации.

Почему именно такой паттерн получается у ИИ. Отчёт Ox Security “Army of Juniors” (октябрь 2025) проанализировал 300 OSS-проектов, из которых 50 – частично или полностью AI-generated. Систематические закономерности:

  • By-the-Book Fixation (80-90% случаев). Агент воспроизводит самый частый паттерн из обучающей выборки. Сам по себе паттерн нейтрален: просто средний, без понимания, что ваш конкретный домен от среднего отличается.
  • Avoidance of Refactors (та же частота). Агент дополняет код. Он не удаляет, не переосмысливает структуру, не выделяет общее. Каждый промпт – это +строки, не -строки.
  • Bugs Déjà-Vu (та же частота). Тот же класс багов, который был частым в обучающей выборке.

Формулировка отчёта: “highly functional but systematically lacking in architectural judgment”. Хорошо работает. Архитектурного суждения не имеет.

И теперь – сцена.

На edtech-проекте, на котором я работал в эпоху Claude Code и Codex (миграция legacy на современный стек, команда 4-5 человек), за квартал я обнаружил одно и то же бизнес-правило, реализованное в трёх независимых модулях. Правило простое по описанию, нюансное в реализации: что считается завершённым уроком. Просмотрел ли учащийся видео полностью, прошёл ли квиз, сдал ли задание с порогом в баллах – и в какой комбинации этих условий урок засчитывается.

В каждом из трёх модулей правило реализовано отдельно. В прогресс-баре, который учащийся видит на своей странице курса. В модуле сертификации, который решает, когда выдавать диплом по итогам курса. В отчётах для HR корпоративного клиента – там “процент завершённых уроков по сотруднику” собирался отдельным агрегатом. Все три PR проходили ревью. Каждый код по отдельности выглядел правильно: структура была, тесты были, имена нормальные.

Почему агент этого не заметил: он не видел двух других модулей. Контекст промпта – текущий файл, иногда соседние. Правило в прогресс-баре существовало два месяца. Когда писали отчёты для HR, агент о нём не знал и генерировал заново – на основе общих знаний о LMS из обучающей выборки.

Почему этого не заметило ревью: каждый PR по отдельности выглядел нормально. Дублирование становилось видимым только с уровня архитектуры – на пересечении всех трёх модулей. Этого взгляда на ревью никто не делал, потому что ревьюер открывал diff одного PR.

Когда правило поменялось (HR-клиент попросил учитывать урок завершённым, только если выполнены и видео, и квиз, и задание, а не любое из них), править пришлось в трёх местах. Один из багфиксов сделали с опозданием – узнали из расхождения цифр: учащийся видел у себя “8 из 10”, в HR-дашборде по нему стояло “6 из 10”. Дальше – пара недель объяснений корпоративному клиенту, какая цифра “правильная”.

Это AI tech debt в живой природе. И это прямое продолжение темы из #2: “в прод идут не знания, а предположения”. ИИ-агент – машинный assumption-усилитель. Раньше предположение в код приносил человек, и его можно было поймать на ревью или в парном программировании. Сейчас предположение приносит агент, генерирует уверенно, и ловить его нужно на скорости генерации – не на скорости человеческого внимания.

У этой проблемы есть имя. Эдди Османи в 2025-м запустил термин Comprehension Debtдолг кода, который никто не понимает. Не “грязный код”, а код, в котором команда не может уверенно сделать изменение, потому что не знает, какие предположения он держит, какие edge cases закрывает, какой контракт обещает наружу. Сгенерированный агентом код, прошедший ревью на отметке “выглядит ок”, – главный поставщик comprehension debt’а.

Закон сохранения техдолга: время сотрёт всё, кроме костылей
Закон сохранения техдолга: Время сотрёт всё, кроме костылей

Чарити Мейджорс сформулировала это в июне 2024-го:

“Code is easy, in other words, but systems are hard.”

Агент пишет код. Системы – это другая задача. ИИ не строит вам систему. Это работа команды, и эта работа в эпоху агентов не сокращается, а становится сложнее: к обычным задачам добавляется верификация AI-output’а на структурном уровне.

Из той же статьи: “You cannot trust generated code. I can’t emphasize this enough.” Не в том смысле, что “AI ошибается” – а в том, что вывод агента не является доказательством решения задачи. Доказательство – это инварианты, которые держатся, метрики, которые не сломались, понимание, как изменение влияет на остальную систему.

Что с этим делать конкретно – в следующем разделе. Не “отказаться от AI” – это не вариант в 2026-м. А встроить в практику так, чтобы скорость генерации не превращалась в скорость накопления долга.


Что делать: “завтра” и “в долгую”

Этот раздел – рецепт. Каждый пункт – действие, не идея. Можно скопировать и применить.

Слой 1. На этой неделе

1. Перестать использовать слово “техдолг” в общении с продактом – на две недели. Заменить на: “риск задержки”, “стоимость следующей фичи”, “налог, который мы не платили”. Это упражнение, не правило. Цель – обнаружить, какую часть “техдолга” ты сам не можешь объяснить, когда лишён удобной обёртки.

2. Прогнать backlog с тегом “технический долг” через четыре квадранта Фаулера. Каждый тикет – в один из квадрантов. По моему опыту получается: 60-70% уходит в Prudent + Deliberate (самообслуживающиеся), 5-10% – в Reckless + Deliberate (политические – кто-то воюет с практикой, которую команда уже приняла), и большая чёрная дыра “не знаю, в каком квадранте” – это и есть Reckless + Inadvertent. Вот с ним и работаем дальше, остальное оставляем самообслуживанию.

3. Внедрить ОДНУ fitness function в CI. Не семь. Одну. Базовую: Domain-проект не зависит от Infrastructure. На .NET – через NetArchTest, это unit-тест, который падает в CI:

[Fact]
public void Domain_does_not_depend_on_infrastructure()
{
    var result = Types.InAssembly(typeof(Booking).Assembly)
        .That()
        .ResideInNamespace("BusinessTravel.Domain")
        .Should()
        .NotHaveDependencyOn("BusinessTravel.Infrastructure")
        .GetResult();

    Assert.True(result.IsSuccessful);
}Tests/Architecture/DomainIsolationTests.cs

Падает – PR не мёрджится. 30 минут работы; через месяц у вас есть архитектурная граница, которую нельзя сломать незаметно. Это и есть превращение Inadvertent-долга в Deliberate: попытка пробить границу теперь видна.

4. Провести one-on-one с каждым в команде на тему “какой код тебе страшно трогать?”. Записать. Это карта Reckless + Inadvertent в голове команды. CodeScene на основе анализа сотен проектов показала: 25-70% всех дефектов сидят в небольшом числе hotspot-файлов. Команда обычно знает, где они. Просто никто не спрашивал.

5. Завести один SLA-поинт – cycle time для двух-дневной фичи. Берёте типовую story размера ~2 дня. Меряете, сколько идёт от старта работы до прода. Если 2 → 5 → 9 за три квартала – вы видите долг в реальном времени. Это сильнее любой ретроспективной оценки backlog’а.

6. Ввести правило структурного ревью для AI-PR. Не “работает ли код” – этого недостаточно. Вопросы к каждому AI-сгенерированному PR:

  • К какому агрегату/модулю относится изменение?
  • Какие инварианты держатся в этом коде? Откуда видно, что они не сломаны?
  • Не реализовано ли это уже в другом месте кодовой базы?
  • Какие оптимистичные допущения о домене зашиты?

Если PR не отвечает на эти четыре – не мёрджим. Ревьюер просит автора переоформить или дописать. Это компенсация скорости генерации; без неё – те самые 80-90% by-the-book.

Слой 2. Чтобы проценты не стали неподъёмными

1. Owner у каждой части кодовой базы. Не “команда владеет всем” – это значит “никто не владеет ничем”. Конкретный человек на каждый bounded context, модуль, проекцию. Owner может меняться – но в каждый момент он есть. Без owner’а долг растёт, потому что некому возражать на “давайте быстро добавим”.

2. Continuous tax вместо рефакторинг-спринтов. 15-20% capacity каждого спринта – на снижение сложности. Встроено в процесс, не выпрашивается. Если налог приходится выпрашивать – значит, его нет.

3. Fitness functions растут от 1 до 5-7 за полгода. По одной в месяц. Каждая закрывает реальный архитектурный риск, проявившийся на инциденте или ревью. Не пишем “на всякий случай”.

Второй пример – bounded contexts не зовут друг друга напрямую, только через публичные контракты:

[Fact]
public void Booking_module_uses_only_public_contracts_of_pricing()
{
    var result = Types.InAssembly(typeof(BookingService).Assembly)
        .That()
        .ResideInNamespace("BusinessTravel.Booking")
        .Should()
        .NotHaveDependencyOn("BusinessTravel.Pricing.Internal")
        .GetResult();

    Assert.True(result.IsSuccessful);
}Tests/Architecture/BoundedContextTests.cs

Третий пример – performance budget как fitness function. Архитектурные характеристики (latency, throughput) проверяются как unit-тест:

[Fact]
public async Task SearchEndpoint_responds_within_budget()
{
    var sw = Stopwatch.StartNew();
    var response = await _client.GetAsync("/api/search?q=москва");
    sw.Stop();

    response.EnsureSuccessStatusCode();
    Assert.True(sw.ElapsedMilliseconds < 500,
        $"Search exceeded 500ms budget: {sw.ElapsedMilliseconds}ms");
}Tests/Performance/SearchEndpointBudget.cs

Подход в целом – Architecture-as-Code – попал в раздел Adopt в Thoughtworks Tech Radar 2025. Полная картина – у Нила Форда в книге “Building Evolutionary Architectures”, там примеры fitness functions от dependency rules до chaos engineering.

4. Раз в квартал – review hotspots через анализ git history. Файлы с высоким change frequency × высоким cyclomatic complexity. Это и есть Reckless + Inadvertent в физическом виде: код, в который часто лезут, и в котором часто ошибаются. Инструменты: CodeScene (платный, удобный), либо самописный скрипт на git log + cyclomatic-анализатор.

5. AI-политика команды – явная и записанная.

  • Что AI пишет свободно: бойлерплейт, тесты по образцу, миграции данных, скрипты автоматизации.
  • Что AI пишет только под структурное ревью: доменная логика, агрегаты, integration boundaries, изменения в публичных контрактах.
  • Что AI не пишет без двойного ревью: security-критичный код, DDL-миграции на проде, изменения в авторизации.

Без этой политики команда тонет в comprehension debt’е. С ней – AI работает на пользу, а не против.

6. Связка с продактом. В каждый квартальный roadmap – хотя бы одна архитектурная инвестиция, переведённая в продуктовый язык. Не “отрефакторить billing”, а “снизить cycle time для billing-фич с 9 до 3 дней – это закроет N задержанных интеграций и Y млн ₽ упущенной выручки в год”. Если не получается так сформулировать – значит, не приоритет, а нытьё.

7. Метрика всего этого – DORA-четвёрка, замеренная самостоятельно. Не на чужих dashboards. Своя четвёрка: lead time, deployment frequency, change failure rate, MTTR. Замеряем квартально. Деградация – налог недостаточный. Стабильность – работает.

Пенсия в 25, а не в 55

На текущем проекте я начинаю с нуля – лизинговая компания, новый продукт, кода написано 2 недели. Техдолга ещё нет. И при этом я уже запланировал две fitness functions на CI до конца месяца, выделил один SLA на cycle time, договорился с продуктом про 15% налога на снижение сложности с самого начала.

Это как заводить пенсию в 25 лет, а не в 55. На дистанции – другой порядок. Через 3 года, если процесс работает, lead time на типовую фичу останется 2-3 дня. Без процесса – будет 9. Разница – один процент в спринте, накопленный за 36 месяцев.

Долг управляется как кредит, не как болезнь. Кредит требует процесса: ставка, график, owner. Болезнь требует разовых усилий – спринтов, авралов, врачей. Команды, которые относятся к долгу как к болезни, всю жизнь его лечат и никогда не выздоравливают. Те, что относятся к нему как к кредиту, платят меньше – и доставляют больше.


Заключение: долг как кредит, а не как болезнь

Если убрать слово “техдолг” из лексикона и оставить только то, что под ним стоит – получится разговор про разницу между тем, как быстро мы чувствуем, что движемся, и тем, как быстро мы реально движемся. METR показал эту разницу в 39 п.п. на одной задаче. DORA показывает её на горизонте квартала. AI её ускоряет у команд без процесса и усиливает у команд с процессом – это и есть mirror effect, который зафиксировал отчёт DORA 2025.

Управлять этой разницей можно. Сначала её надо назвать правильно: пять категорий, четыре квадранта Фаулера. Дальше – измерить термометром (DORA). И уже потом – встроить в процесс налог, который гасит разницу непрерывно: continuous tax, fitness functions, AI-политика, владельцы у каждой части кодовой базы. Это работа каждого спринта, не разовая.

В следующей и финальной статье цикла – про эволюционную архитектуру: как принимать решения, когда ты не знаешь будущего. Долг – это процесс возврата того, что выбрали неосознанно. Эволюционная архитектура – про то, как изначально выбирать так, чтобы возврат был возможным, и чтобы решение завтра можно было пересмотреть без переписывания всего.

Если хочется обсудить статью или поделиться своим опытом “спринтов на рефакторинг”, которые сработали или провалились, – приходите в телеграм-канал. На этой неделе там два AI-угла, которые в эту статью не вошли: про структурное ревью AI-PR и про то, как договариваться с командой о границах AI-генерации.


Что почитать

  • Уорд КаннингемThe Debt Metaphor. Оригинальная формулировка с авторскими комментариями. Ключевое – про осознанность и план возврата.
  • Мартин ФаулерTechnical Debt Quadrant. Короткий пост 2009 года, который до сих пор работает как рамка для обсуждения.
  • DORA 2024 и DORA 2025dora.dev/research. Полные отчёты с разбивкой по типам команд. 2025 – главный документ года про связь AI и delivery-метрик (“mirror effect”).
  • METR study, июль 2025Measuring the Impact of Early-2025 AI on Experienced OS Developer Productivity. 19% замедление и 39 п.п. разрыва между ощущением и реальностью у опытных разработчиков на собственных репозиториях.
  • GitClearAI Copilot Code Quality 2025. 211 миллионов строк, год за годом, видна траектория сдвига от refactor к copy-paste.
  • Adam Tornhill – “Your Code as a Crime Scene” (2nd ed., 2024) и блог CodeScene. Hotspot-анализ через git history. Сам подход применим без CodeScene и работает на любом репозитории – нужен только git log и cyclomatic-анализатор.
  • Neal Ford et al. – “Building Evolutionary Architectures” (2nd ed., 2023). Полная теория и кейсы по fitness functions – от dependency rules до chaos engineering.
  • Charity MajorsGenerative AI is not going to build your engineering team for you. Главный пост 2024 года про AI в инженерии: “code is easy, systems are hard”.
  • Addy OsmaniComprehension Debt. Имя для главной AI-проблемы 2025-2026: код, который никто в команде не понимает.
  • Александр ПоломодовRecap of “Building Evolutionary Architecture”. Конспект книги Нила Форда от русскоязычного архитектора (T-Bank, направление цифровых экосистем). Полезен как мост между академической теорией fitness functions и тем, как это реально внедряют в крупном продакшене – в одной статье.
Поделиться: Telegram X