Есть легаси, которое просто неприятно поддерживать. А есть проекты, где уже непонятно, за что хвататься.

В одном репозитории могут жить JavaScript и TypeScript, NestJS и внутренний фреймворк компании. Рядом лежат модули десятилетней давности и свежий код. Документация давно разошлась с реальностью, тестов местами нет. Иногда приложение удаётся запустить только после разговора с человеком, который работает в компании дольше всех. С тем же сталкиваются и в старых проектах на Java, Go, Python или C#. Приходится менять систему, которую до конца не понимаешь.

Казалось бы, тут AI-агент и пригодится: быстро прочитает код, найдёт связи, предложит изменение. Но агент так же быстро достроит картину там, где фактов не хватает. Увидит знакомый паттерн, сделает разумное предположение, а в этом проекте всё окажется устроено иначе. В плохом легаси агент может ускорить создание очень правдоподобной ошибки.

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

Сначала один маршрут через систему

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

Я беру маршрут:

запрос пользователя → создание заказа → сохранение данных → отправка события

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

Где факт, а где догадка

Опыт здесь иногда мешает. Знакомая структура подсказывает, как система должна работать. Но за годы в коде накопились исключения, которых не видно по названиям классов.

Агенту особенно легко заполнить пробелы убедительным объяснением. Я прошу показать опору для каждого утверждения, от которого зависит изменение: реализацию, пример использования, тест, документацию или подтверждение человека, который знает этот участок.

«Скорее всего, здесь всё работает так» для меня ещё не результат исследования. Нужен участок кода или другой источник, по которому можно проверить вывод. Если подтверждения нет, так и записываем: это предположение.

Сохраняю найденное рядом с кодом

Агент разобрал сценарий, нашёл неочевидную зависимость и понял, почему странный кусок кода нельзя удалить. Через несколько сессий этот контекст исчезнет. Следующему агенту придётся проходить тот же маршрут заново.

Поэтому оставляю знания рядом с проектом. В AGENTS.md можно хранить правила работы с репозиторием: как его запустить, чем проверить изменения, где нужна осторожность. Бизнес-термины, сценарии и ограничения держать отдельно. Если решение потом будет выглядеть странным, пишу короткий ADR с причиной.

Документировать весь проект заранее я бы не взялся. Изучил создание заказа, зафиксировал именно его. Разобрал возврат, добавил то, что узнал о возврате. Так документация растёт вслед за задачами и опирается на проверенный код.

До правки нужен способ увидеть прежнее поведение

Можно понять сценарий, написать код и внимательно посмотреть diff. Но если проверок нет, откуда узнать, что изменение ничего не сломало?

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

Такие проверки называют characterization tests. Они не доказывают, что нынешнее поведение правильное. Они фиксируют: сейчас система отвечает вот так. Для легаси это уже полезная точка отсчёта.

И проверять стоит то место, где проявится ошибка. Тест маленькой функции удобен, но бесполезен для задачи, если заказ ломается на стыке компонентов, в базе данных, очереди сообщений или внутренней библиотеке. Если сбой виден только на всём маршруте, проверяю маршрут. Если всё упирается в одну интеграцию, строю проверку вокруг неё.

Иногда сначала приходится немного изменить код, чтобы нужную часть системы можно было наблюдать или контролировать. Такой рефакторинг нужен ради следующей проверяемой правки, а не ради красивой схемы классов.

Не чиню соседние модули заодно

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

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

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

Архитектурный запрос у меня звучит конкретнее:

Исследуй сценарий создания заказа и его непосредственные зависимости. Найди до трёх изменений, которые позволят проще проверять его поведение или уменьшат количество компонентов, которые приходится менять вместе. Покажи конкретные места в коде и стоимость изменений. Пока ничего не меняй.

Теперь можно проверить предложения агента: уменьшат ли они объём кода, который нужно понимать и менять ради следующей задачи.

Как это выглядит в работе

Мой цикл: исследование сценария → фиксация знаний → воспроизводимая проверка → изменение → code review → обновление знаний. Скиллы для него я взял из репозитория Мэтта Покока.

Когда сценарий незнаком, использую /grill-with-docs. Агент проходит текущий путь выполнения, отделяет факты от предположений и помогает уточнить требования. Если баг воспроизводится, подключаю /diagnosing-bugs: сначала воспроизведение и минимальный сценарий, потом исправление и регрессионная проверка.

С понятными требованиями перехожу к /implement, уже зная границы изменения и способ его проверить. К /improve-codebase-architecture и при необходимости /codebase-design обращаюсь, когда архитектура мешает этой конкретной задаче. Большую работу делю на задачи, которые помещаются в отдельные сессии с небольшим контекстом.

На /code-review меня прежде всего интересуют незапрошенные изменения поведения. Тот ли сценарий мы поменяли? Не задели ли соседний?

Что остаётся после десяти задач

После первой задачи у меня есть карта одного сценария. После второй появляется ещё одна. Где-то добавляется первая автоматическая проверка, где-то ADR объясняет странное решение. У часто меняемых частей системы постепенно появляется история, на которую можно опереться.

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