Модуль 2 · Качество · урок 7 из 17
Рефакторинг и легаси
Рефакторинг кажется идеальной работой для агента: много механических изменений, понятная цель. На деле это одна из самых рискованных задач, особенно в легаси, где тестов мало, а поведение держится на неочевидных деталях. В уроке — порядок, при котором агент действительно ускоряет рефакторинг, а не превращает его в лотерею.
Почему легаси опасно для агента
Две особенности агентов здесь бьют сильнее всего.
Агент копирует то, что видит. В статье OpenAI о harness engineering команда описывает это прямо: Codex воспроизводит шаблоны, которые уже есть в репозитории, включая неудачные, и код постепенно дрейфует. В легаси неудачных шаблонов много, и агент может растиражировать худший из них.
Агент не знает истории. Странная пауза перед запросом к платёжному шлюзу, проверка на конкретный ID в шаблоне, дублирующий метод «на всякий случай» — за каждым может стоять инцидент. Агент видит лишний код и удаляет его.
Отсюда правило: в легаси сначала фиксируют текущее поведение, потом меняют структуру.
Шаг 1. Карта перед стройкой
Начните с исследования в режиме только для чтения. Для рефакторинга нужны конкретные ответы:
Мы будем выносить логику из компонента
plugins/acme/booking/components/BookingForm.php (метод onSubmit,
около 600 строк) в отдельные сервисы. Перед этим перечисли все побочные
эффекты onSubmit: запись в БД, письма, запросы во внешние API, сессия,
кэш. Кто вызывает этот обработчик? Какие места выглядят как защита
от прошлых проблем? Ничего не меняй.Подозрительные места проверьте по истории: попросите агента найти коммит, в котором появилась строка, и прочитать его описание (git log -L, git blame). Иногда одна такая находка экономит день разбора инцидента.
Шаг 2. Страховочные тесты
Если тестов на onSubmit нет, сначала пишут их — тесты, фиксирующие текущее поведение (characterization tests), даже если оно кажется странным:
Напиши тесты, которые фиксируют ТЕКУЩЕЕ поведение onSubmit, включая
неочевидное: что пишется в БД, какие письма уходят, что возвращается
при ошибке валидации и при недоступном API. Внешние сервисы — через
фейки. Найденные баги не исправляй, отметь в комментарии к тесту.Найденные баги — отдельные задачи. Смешивать рефакторинг с исправлением поведения нельзя: если после рефакторинга что-то изменилось, вы не поймёте, намеренно или нет.
Прогоните новые тесты на неизменённом коде — они должны быть зелёными. Это и есть страховочная сеть.
Шаг 3. Маленькие шаги, каждый зелёный
Рефакторинг по шагам: каждый шаг — одно преобразование (вынести метод,
переместить класс, заменить вызов). После шага — тесты, если зелёные —
коммит "refactor: что сделано". Если тест покраснел — откати шаг
и сообщи, тест не подгоняй.Почему так мелко: если ошибка всплывёт на ревью или через неделю на проде, git bisect по маленьким коммитам укажет точный шаг. Один коммит на полторы тысячи строк такого шанса не даёт.
Изменения поведения в рефакторинговом MR запрещены. Запишите это в AGENTS.md:
## Рефакторинг
- Рефакторинг не меняет поведение. Нашёл баг — запиши в отчёт, не чини.
- Не удаляй код, назначение которого неясно: спроси или оставь TODO с вопросом.
- Не пиши новые хелперы, если подходящие уже есть (app/Support/, plugins/*/classes/).Шаг 4. Образец, потом тираж
Многие рефакторинги однотипны: перевести 40 контроллеров на валидацию через form request, заменить устаревший вызов во всех плагинах, перевести экраны мобильного приложения на новый API навигации. Не отдавайте все 40 сразу.
- Образец. Агент переделывает один контроллер. Вы внимательно ревьюите и правите, пока не получите результат, который хотите видеть везде.
- Рецепт. Попросите агента описать преобразование: что меняется, на что обращать внимание, как проверить. Сохраните в
docs/refactoring/form-requests.md. - Тираж. «Переведи контроллеры из списка по рецепту и по образцу
LeadController, по одному коммиту на контроллер». Гайд «How OpenAI uses Codex» советует то же: ставить задачу как хорошее issue и указывать «сделай так же, как в модуле X».
Если преобразований десятки и они независимы, их можно распараллелить по нескольким сессиям в отдельных worktree — об этом урок «Несколько задач параллельно». А если рецепт будет повторяться в других проектах, его стоит упаковать в навык — см. урок «Навыки».
Обновление версий
Отдельный вид рефакторинга — миграции версий: PHP, Laravel, мажорная версия библиотеки в мобильном приложении. Здесь агенту особенно нужна документация нужной версии: changelog и upgrade guide. Дайте ссылку или попросите найти гайд веб-поиском (флаг --search включает живой поиск), а затем пройти по его пунктам и для каждого ответить, касается ли он проекта, — с файлами.
Сама миграция идёт по тем же шагам: тесты зелёные до, маленькие коммиты, тесты зелёные после. Подробнее о миграциях и рутинной работе — в уроке «Документация, миграции и рутина».
Ревью рефакторинга
Ревьюеру нужна уверенность, что поведение не изменилось. Помогите ему: в описании MR укажите, какие тесты фиксируют поведение и что в ходе рефакторинга они не менялись — git diff main -- tests/ показывает только добавленные страховочные тесты. Запустите /review с инструкцией искать изменения поведения; свои инструкции к ревью разбираются в следующем уроке.
Попробуйте сами
10–15 мин на рабочем месте- Выберите в проекте метод длиннее 200 строк. Попросите агента в режиме только для чтения перечислить его побочные эффекты и подозрительные места; одно из них проверьте через
git blame. - Попросите написать тесты на текущее поведение этого метода и прогоните их на неизменённом коде.
- Сделайте один шаг рефакторинга с коммитом и убедитесь, что существующие тесты в
tests/не менялись.
Коротко
- Агент копирует существующие шаблоны и не знает истории кода — в легаси это главный риск.
- Сначала карта побочных эффектов и тесты на текущее поведение, потом изменение структуры.
- Шаги маленькие, после каждого — зелёные тесты и коммит; баги попутно не чинить.
- Однотипные изменения: образец → рецепт → тираж по образцу.
- В MR рефакторинга доказывайте, что поведение не изменилось.