ИИ‑ассистенты для аудита устаревшего кода: с чего начать
ИИ‑ассистенты для аудита устаревшего кода работают лучше, когда вы отмечаете неактивные пути, слабые тесты и пробелы в владении до того, как просите исправления.

Почему старый код сбивает с толку ИИ-ассистента
ИИ-ассистент может просканировать большой кодовой базис за минуты. Эта скорость полезна, но старый код часто рассказывает неправильную историю.
В наследуемых системах правила живут в головах людей, в старых тикетах и в полузабытых инцидентах. Ветка может выглядеть бессмысленной, пока кто-то не объяснит, что счета можно редактировать в течение 24 часов для одной старой группы клиентов, или что ночное задание пропускает один регион из‑за проблемы, которую никто толком не починил годами. Если этот контекст никогда не попал в код или тесты, ассистент заполняет пробелы — и часто делает это неверно.
«Мёртвые» пути усугубляют проблему. В старых проектах накапливаются устаревшие feature‑флаги, частичные интеграции, резервный код и скрипты, которые когда‑то были важны, а теперь ничего не делают. Для модели всё это всё ещё выглядит активным. Она видит десять способов сделать одну и ту же задачу и может сосредоточиться на пути, по которому уже никто не проходит.
Проходящие тесты сами по себе это не исправят. Во многих старых наборах тестов проверяются только простые случаи: что запрос возвращает 200, что функция что‑то возвращает или что страница отрисовывается. Это не доказывает, что код по‑прежнему защищает важное бизнес‑правило. Если тесты зелёные, ассистент получает ложную уверенность.
Пробелы в владении добавляют ещё одну слепую зону. Во многих старых репозиториях все трогают одни и те же файлы, но никто ими полностью не владеет. Ассистент не может спросить единственного инженера, который знает, почему лимит повторных попыток равен 7, или почему один эндпоинт всё ещё отдает старый формат.
Это та проблема, которую часто наблюдает Oleg Sotnikov, когда команды пытаются использовать ИИ, чтобы ускорить работу над стареющими системами. Первая проблема редко в синтаксисе — это отсутствующий контекст. Пока ассистент не сможет отличить живые пути от мёртвых, сильные тесты от слабых и код с владельцем от заброшенного кода, он будет говорить уверенно раньше, чем окажется прав.
Составьте карту системы до аудита
Прежде чем направлять ассистента на наследуемый код, дайте ему карту того, что поддерживает работу бизнеса.
Начните с рабочих потоков, которые люди используют каждый день. Обычно это вход в систему, биллинг, данные клиентов, административные инструменты, отчётность и всё, что блокирует работу при сбое. Затем отметьте потоки, которые затрагивают деньги, приватные данные или права доступа. Эти пути несут наибольший риск и часто пересекают несколько сервисов.
Поток возврата средств, сброс пароля или смена роли может выглядеть маленьким в интерфейсе. За ним может тянуться код через API, воркеры, старые вспомогательные функции, планировщики и проверки прав.
Ваша карта должна ответить на несколько простых вопросов:
- Какие системы поддерживают ежедневную работу?
- Какие потоки влияют на платежи, данные или доступ?
- Какие модули разработчики избегают менять?
- Какие недавние баги или инциденты указывают на хрупкие места?
Третий вопрос очень важен. В каждом кодбазе есть области, к которым люди подходят на цыпочках — это может быть логика налогов, выставления счетов или старый модуль авторизации, который ломается при переименовании одного поля. Если команда боится его трогать, ассистент должен проверить его в первую очередь. Страх часто лучше показывает риск, чем количество файлов.
Соберите заметки об инцидентах, отчёты об ошибках, тикеты поддержки и постмортемы в одном месте до начала аудита. Не нужен идеальный справочник — общий документ с датами, симптомами, затронутыми модулями и связанными коммитами будет достаточен. Это даст ассистенту реальную историю сбоев вместо чистого, но вводящего в заблуждение вида репозитория.
Держите карту небольшой. Одна страница, которую команда действительно обновляет, лучше огромной диаграммы, которой никто не доверяет.
Начните с мёртвых путей
Если нужен безопасный старт, начните с кода, который, вероятно, больше не важен.
Неиспользуемый код таит риск, не давая ценности, и искажает взгляд ассистента. Если модель видит десять возможных путей, а по настоящему трафика проходят только три, её предложения склоняются в сторону кода, которым никто не пользуется.
Начните с эндпоинтов, по которым никто больше не ходит. Старые API остаются в проекте, потому что никто не хочет сломать забытый клиент. Сравните определения маршрутов с логами доступа, логами шлюза и недавними трассировками. Если по эндпоинту не было реального трафика месяцами, пометьте его для ревью.
Затем посмотрите на фоновые задания, скрипты и feature‑флаги. В наследуемых системах накапливаются ночные задания, которые обрабатывают пустые очереди, скрипты, которые когда‑то исправляли миграцию, и флаги, связанные с запусками годы назад. Код остаётся, и люди предполагают, что он важен.
Быстрый проход обычно выявляет одни и те же проблемные места:
- API‑эндпоинты с нулевым или почти нулевым трафиком
- cron‑задачи или воркеры, которые запускаются, но ничего не делают
- одноразовые скрипты, хранящиеся в папках деплоя
- feature‑флаги без явного владельца
Логи дают реальную проверку. Код показывает, на что система способна. Логи показывают, что она действительно делает.
Возьмём, например, сервис биллинга. На бумаге он может экспортировать CSV через старый эндпоинт, запускать ночную синхронизацию счетов и хранить флаг для устаревшего потока скидок. По логам картина другая: эндпоинт не вызывался 180 дней, синк обрабатывает ноль записей, флаг выключен для всех аккаунтов. Это мёртвый путь, пока кто‑то не докажет обратное.
Не торопитесь удалять. Помечайте рискованные удаления до вмешательства. Всё, что связано с платежами, авторизацией, комплаенсом, колбэками партнёров или старыми корпоративными клиентами, требует осторожности. Путь может быть тихим и всё ещё важным для одного клиента.
Достаточно простых меток: «неиспользуемо», «возможно не используется» и «неиспользуемо, но рискованно». Такие метки дают ассистенту чище контекст и вашей команде — безопасную очередь для чистки.
Проверяйте слабые тесты, прежде чем доверять зелёному прогону
Зелёный набор тестов может скрывать многое.
Когда ассистент читает наследуемый код, он часто рассматривает проходящие тесты как доказательство безопасности поведения. Это быстро разваливается, когда тесты поверхностны.
Откройте выборку тестов и читайте утверждения, а не только названия. Если тест только проверяет статус 200, отрисовку страницы или огромный снапшот, он может пропустить правило, которое действительно важно пользователям. Чек‑аут может возвращать успех, но считать неверно налоги, пропускать лимиты скидок или брать плату не в тот день продления.
Несколько паттернов требуют внимания сразу:
- тесты, проверяющие только коды статуса, но не содержимое ответа
- snapshot‑тесты, которые часто меняются и их никто внимательно не читает
- тесты с sleep, случайными датами, ретраями или общим состоянием
- большие области кода без теста для реального бизнес‑правила
Флейки нужно отмечать отдельно. Если тест падает из‑за тайминга, порядка тестов, случайных ID или нестабильного внешнего сервиса, пометьте его до продолжения аудита. Иначе ассистент может воспринять шум тестов за поведение продукта и предложить исправления не по адресу.
Потом ищите правила, для которых вообще нет теста. Запишите случаи, которые пользователи заметят в первую очередь: окна возврата, лимиты одобрений, округления в счетах, проверки прав, сроки продления. Если этих правил нет в покрытии, слабые тесты уже формируют аудит сильнее, чем сам код.
Одна команда биллинга имела десятки проходящих API‑тестов. Каждый тест проверял код ответа и пару полей. Ни один из них не гарантировал, что годовые планы сохраняют старую цену для существующих клиентов в период льгот. Сьют оставался зелёным, но важное правило отсутствовало.
Рассматривайте чистый прогон как подсказку, а не как доказательство. Он показывает, за чем набор тестов сейчас следит. Он не говорит, что система обещает пользователям.
Найдите пробелы в владении
Ассистент быстро читает код, но не скажет, кто может его безопасно менять.
Отсутствие этого контекста приводит к плохим советам. Ветка, кажущаяся модели бесполезной, может защищать правило биллинга, обещание клиенту или обходной путь, который помнит только один человек.
Начните с простой карты владения. Для каждой области кодовой базы укажите, кто утверждает изменения, кто их ревьюит и кто подменяет при отсутствии основного человека. Достаточна простая таблица или спредшит.
Обратите внимание на модули, которыми в основном занимались ушедшие сотрудники. Эти области часто аккумулируют тихий риск. Команда может и править там баги, но никто не уверен при изменениях поведения. Именно туда ИИ‑ассистент становится чрезмерно уверенным и предлагает чистку, которая на экране выглядит аккуратно, но ломает реальную работу.
Нотатки при передаче дела важнее, чем многие признаются. Если у модуля нет заметок, ясной истории тикетов и владельца — считайте его высоким риском, даже если он кажется стабильным. Стабильность может значить, что код надёжен. А может значить, что все боятся его трогать.
Пробелы в владении проявляются мелкими признаками: запросы ревью скачут, алерты не имеют ответственного, один и тот же файл правят пять человек за полгода, но никто не может объяснить весь поток. Когда видите такой паттерн, считайте, что ассистент упустит часть человеческого контекста, если вы её не добавите в аудит.
Проведите простой поток аудита
Начните с малого. Если направите ассистента на весь репозиторий, он потратит время на суммирование структуры вместо поиска проблем.
Выберите один болезненный модуль с четкими границами — биллинг, авторизация или воркер, который ломается каждые несколько недель. Затем соберите небольшой пакет доказательств вокруг него: недавние логи, падающие тесты, баг‑тикеты и последние коммиты часто расскажут полезнее, чем только код.
Простой поток работает так:
- Выберите один модуль с недавними ошибками и четкими границами.
- Добавьте логи, результаты тестов, отчёты об ошибках и недавние изменения.
- Попросите ассистента сначала объяснить риски, прежде чем предлагать исправления.
- Просмотрите вывод с тем, кто лучше всего знает модуль.
Порядок важен. Если ассистент сразу предложит план рефакторинга, притормозьте. Сначала нужен ранжированный список рисков. Спросите, какие пути выглядят неиспользуемыми, какие тесты не защищают поведение, где владение неясно и какое изменение с наибольшей вероятностью снова сломает прод.
Хорошие подсказки заставляют модель притормозить. Попросите короткие причины, доказательства в коде и предположения, которые она сделала. Если она не может объяснить предположения — она ещё не готова направлять изменение.
Человек‑владелец должен сразу просмотреть вывод, пока контекст свеж. Он увидит обходные решения, скрытые зависимости и бизнес‑правила, которые модель пропустит. После ревью обновите план простым языком: что проверять в первую очередь, что игнорировать пока и какие тесты нужны до релиза исправлений.
Это держит аудит дешёвым и честным. Один модуль, один пакет доказательств, один список рисков. Обычно этого достаточно, чтобы найти первую реальную проблему.
Реалистичный пример с биллингом
Представьте, что команда унаследовала старый сервис биллинга, выросший слоями за многие годы. Он обрабатывает счёта, повторные попытки списаний, кредиты и путь возврата, добавленный когда‑то для одной особой группы клиентов. Никто из текущей команды тот код не писал, а тесты вокруг него покрывают только простой случай.
Команда просит ИИ‑ассистента найти безопасную работу по очистке. Модель сканирует репозиторий, находит ветку возвратов за старой конфигурационной проверкой и предлагает удалить её. Ветка выглядит устаревшей: мало файлов упоминает её, недавние коммиты игнорируют, и тонкий тест проходит, не затрагивая крайние случаи.
Потом команда смотрит логи продакшна.
Ветка возвратов всё ещё отрабатывает несколько раз в неделю для клиентов по старым контрактам. Трафик редкий, но реальный. Если бы команда удалила этот путь, небольшая группа платящих клиентов потеряла бы возвраты за ночь.
Модель не была «сломана». Репозиторий дал ей неверную карту. Тесты никогда не создавали старый тип контракта, поэтому ветка выглядела неиспользуемой. Также у сервиса не было явного владельца: инженер, который добавил возвраты, ушёл годами раньше, и никто формально не взял на себя эту область.
Такая смесь встречается часто. Код, выглядящий мёртвым, не всегда мёртв. Слабые тесты скрывают живое поведение, а пробелы в владении убирают человеческий контекст, который объясняет странные ветки.
Команда исправляет окружение прежде, чем просить дальнейших советов: добавляет тест для пути со старым контрактом, назначает владельца правил биллинга и помечает ветку возвратов как мало‑трафиковую, но активную. После этого ассистент перестаёт настаивать на удалении и начинает предлагать более безопасные изменения, например изолировать ветку за более ясным интерфейсом и добавить алерты на ошибки возвратов.
Это гораздо лучшее начало.
Ошибки, которые тратят время впустую
ИИ быстро читает старый код. Он также быстро идёт не в ту сторону.
Большая часть потерь времени приходит из плохой подготовки: просьб об исправлениях слишком рано, доверия устаревшей документации или попыток заставить ассистента судить сразу всё.
Одна распространённая ошибка — просить рефакторить до проверки реального использования. Функция может выглядеть уродливой и удобной для удаления, но поддерживать одно ночное задание, старый клиентский поток или админ‑инструмент. Если пропустить логи, трассировки и данные об использовании, ассистент примет догадки за факт.
Устаревшая документация даёт тот же эффект. Старые комментарии, заброшенные дизайн‑ноты и НЕактуальные README ведут модель к коду, который уже не важен. Если комментарий говорит «временное решение», а код в проде четыре года — комментарий стал шумом.
Показатели покрытия тестами вводят команды в заблуждение чаще, чем должны. Отчёт может показывать 82% покрытия, но это ничего не говорит о качестве тестов. Некоторые тесты лишь проверяют, что функция что‑то возвращает. Другие мокают так много, что никогда не затрагивают рискованную ветку.
Ещё одна потеря времени — упихивание слишком многих файлов в один запрос. Попросите один ответ по контроллерам, воркерам, хелперам, тестам и старым миграциям одновременно — и ассистент начнёт смешивать идеи. Меньшие пакеты работают лучше.
Простая рутина экономит часы:
- Проверьте, какие пути ещё запускаются в проде или стейджинге.
- Уберите устаревшие доки и комментарии из подсказки.
- Читайте примеры тестов вместо того, чтобы слепо верить проценту покрытия.
- Разбивайте большие модули на меньшие группы для ревью.
Команды обычно получают лучшие результаты, когда замедляют первый проход. Десять осторожных минут в начале могут сэкономить день на проверке плохих предложений.
Быстрые проверки, прежде чем доверять предложению
Красивое объяснение может выглядеть умнее, чем оно есть.
Старые системы прячут правила в неожиданных местах, и ассистент часто видит форму кода раньше, чем бизнес‑риск. Прежде чем доверять предложению, проверьте несколько простых фактов:
- Кто сегодня владеет модулем?
- Запускается ли путь в логах, трассах или недавних заданиях?
- Покрывают ли тесты именно то правило, которое вы хотите менять?
- Объясняет ли ассистент режим отказа, а не только стиль кода?
Слабые тесты — частая ловушка. Тест может вызвать функцию, которую вы собираетесь менять, но покрывать только простой случай с чистым вводом и ожидаемыми флагами. Это не доказывает безопасности изменения. Нужен тест, показывающий краевой случай, ради которого писался старый код.
Представьте модуль импорта с запасным парсером. Ассистент предлагает убрать его, потому что появился новый формат. Это звучит красиво. Но если логи показывают, что запасной парсер по‑прежнему обрабатывает 2% импортов, и у модуля нет владельца — безопасный шаг: остановиться, собрать реальный образец файла и написать тест, прежде чем что‑то менять.
Хорошая помощь от ИИ называет риск простыми словами: что может сломаться, где пробел и какие доказательства ещё нужны. Если он не может этого сделать, ему рано менять продакшн‑логику.
Следующие шаги для вашей команды
Команды получают лучшие результаты, если первый аудит остаётся небольшим.
Выберите одну область, которая может навредить бизнесу при сбое — биллинг, вход в систему или синхронизация заказов. Запишите, что нашёл ассистент, что оказалось шумом и какие вопросы может ответить только человек. После одного сфокусированного прохода те же шаблоны обычно повторяются: старые ветки, которыми никто не пользуется, тесты, проходящие без проверки важного, и файлы без ясного владельца.
Короткая рутина достаточна. Проследите один рискованный рабочий поток от начала до конца. Отметьте отсутствующих владельцев для файлов, задач и алертов. Пометьте тесты, которые пропускают краевые случаи или покрывают только счастливые пути. Сохраните находки в простом шаблоне, который команда сможет повторять.
Не бросайтесь в большой рефакторинг только потому, что ассистент сгенерировал аккуратный план. Если владение неясно и тесты слабы — большие изменения превратятся в догадки. Закройте пробелы, добавьте пара тестов, покрывающих реальные ошибки, и только потом меняйте структуру.
Последовательность важнее одноразовой чистки. Проводите такое ревью каждый месяц или перед крупной работой в старых частях системы. Со временем у вашей команды появится живой чеклист аудита наследуемого кода, а не ещё один забытый документ.
Если вашему стартапу или малому бизнесу нужна внешняя помощь, Oleg Sotnikov на oleg.is работает с командами по наследуемым системам, технической стратегии, инфраструктуре и практическим рабочим процессам аудита с ИИ. Внешний обзор помогает, когда команде нужен второй взгляд перед неделями правок не той части кода.
Один аккуратный проход по рискованной области часто экономит больше времени, чем широкий аудит, за которым никто не последует.
Часто задаваемые вопросы
Where should we start an AI audit in legacy code?
Начните с одного рискованного модуля, а не с всего репозитория. Биллинг, авторизация, возвраты, импорт или другая область с недавними ошибками дают ассистенту достаточно контекста, чтобы найти реальные проблемы, не тонув в устаревшем коде.
Why not point the assistant at the whole repo?
Полный скан репозитория обычно даёт общие сводки и ненадёжные догадки. Сужение области позволяет ассистенту сопоставить код с логами, тестами и недавними изменениями и выдать то, что реально можно проверить.
How do we find dead code without breaking something?
Сравните определения маршрутов, фоновые задания и скрипты с логами доступа, трассировками и активностью очередей. Если путь не использовался месяцами, пометьте его как вероятно неиспользуемый и удаляйте только после проверки влияния на клиентов.
Why can a green test suite still mislead the assistant?
Зеленая сборка часто означает, что набор тестов проверяет только простой случай, а не бизнес-правило. Тест может проходить, хотя приложение всё ещё списывает неправильную сумму, пропускает проверку доступа или не учитывает старые пути для клиентов.
Which tests should we review first?
Сначала прочтите тесты, связанные с деньгами, доступом, датами и краевыми случаями. Если тест только проверяет код статуса, снимок или счастливый путь, считайте его слабым, пока не добавите утверждение для реального правила.
How do ownership gaps cause bad AI suggestions?
Модель видит код, но не знает, кто понимает скрытое правило за ним. Если у модуля нет явного владельца, ассистент может предложить чистку, которая выглядит аккуратно, но нарушит обещание, данное клиентам годами ранее.
What should go into the evidence pack for an audit?
Держите пакет доказательств коротким и конкретным: недавние логи, падающие или флейки тесты, тикеты с багами, заметки инцидентов и последние коммиты обычно рассказывают ассистенту больше, чем гора исходников.
When should we avoid deleting a low-traffic branch?
Остановитесь, если путь связан с платежами, авторизацией, соответствием, колбэками партнёров или условиями старых контрактов. Низкий трафик не равен нулевой ценности — один редкий путь может быть важен для платящего клиента.
How can we verify an AI suggestion before we trust it?
Проверьте четыре вещи сразу: кто владеет модулем, выполняется ли путь в логах или заданиях, покрывают ли тесты конкретное правило, и какой сбой может вызвать предлагаемое изменение. Если ассистент не может это ясно объяснить — не деплойте изменения.
When should we get outside help with a legacy code audit?
Если команда постоянно спорит по одной и той же проблемной области, нет явного владельца модуля или логика биллинга и авторизации слишком хрупка — привлеките внешнюю проверку перед переписыванием. Консультация с опытным CTO или советником поможет инспектировать модуль, отделить шум от риска и выбрать более безопасный шаг.