JavaRush /Курсы /Claude code /Rollback plan как precondition для pilot-среза

Rollback plan как precondition для pilot-среза

Claude code
29 уровень , 1 лекция
Открыта

1. Rollback до первой правки кода

Считайте, что pilot slice уже выбран: reports/* попал в MIGRATION_PLAN.md, branch или worktree созданы, объём понятен. Этого достаточно, чтобы не трогать весь сервис, но недостаточно, чтобы делать первую правку. До первой правки нужен rollback-план.

После выбора pilot slice обычно возникает очень опасное ощущение контроля: кажется, что раз кусок маленький и безопасный, можно уже спокойно открыть build.gradle, поменять версию Boot и посмотреть, что взорвётся. Именно в этот момент и начинаются приключения в стиле «ну мы думали, что быстро вернём назад». Rollback-план нужен как раз для того, чтобы эти приключения не стали жанром.

У migration есть неприятная особенность: даже маленькое изменение почти никогда не ограничивается кодом. Меняете версию фреймворка — подтягиваются библиотеки. Меняете библиотеку — меняется поведение конфигурации. Меняете конфигурацию — ломаете окружение запуска. Поэтому «можем ли начать pilot?» идёт рядом с «можем ли быстро вернуться к baseline?». Формула простая:

Сначала rollback, потом edit.

Звучит чуть менее романтично, чем «сначала хакнем, потом разберёмся», зато сильно дешевле. В CashFlow Dashboard мы идём из Spring Boot 2.7 + Java 8 в сторону Boot 3.x + Java 21. Pilot на read-only модуле reports трогает зависимости, сборку и старт. До первой правки фиксируем письменно: что откатывается, кто подтверждает, по каким сигналам «стоп».

Rollback в этом смысле — не документ для постмортема, а часть стартовой площадки. Нет его — вы не начали контролируемую migration; вы просто открыли редактор с хорошими намерениями.

2. Пять слоёв отката, а не только git revert

Когда разработчик слышит слово rollback, мозг часто автоматически подставляет git revert или git restore. Команды полезные, спору нет. Но migration ломается не только в Git-истории: иногда в зависимостях, иногда в конфигурации, иногда в данных, а иногда в деплой-цепочке. Поэтому rollback полезно мыслить не как одну кнопку, а как пять разных слоёв.

Сводная карта выглядит так:

Тип отката Что возвращаем назад Типичный механизм Пример для CashFlow Dashboard
Code rollback Изменённые файлы в репозитории
git restore, git revert, возврат ветки
Вернуть reports/* и build.gradle.kts к baseline commit
Dependency rollback Версии библиотек и lockfile Восстановление зафиксированных версий и lockfile Вернуть Spring Boot 2.7.18, откатить gradle.lockfile
Config rollback Флаги, env, yaml/properties Вернуть старые значения, отключить flag Выключить reports.boot3_pilot_enabled, восстановить старые actuator-paths
Data rollback Изменения схемы или данных backup, restore, rollback-script Для read-only pilot — none, because ...
Deployment rollback Ранее выложенный артефакт redeploy previous artifact Вернуть предыдущую сборку, если она совместима с текущими данными

Самый приятный из этих пяти — code rollback: часто решается средствами Git и занимает считанные минуты. Но дальше начинаются нюансы, которых таблица не покажет.

Dependency rollback уже требует дисциплины: без явных версий и lockfile «вернуться на прежний стек» превращается в угадайку. Тот же build.gradle без корректного lockfile подтянет другой граф зависимостей — формально откатились, а фактически стоите в слегка другом мире.

Config rollback ещё коварнее, потому что многие конфигурационные правки кажутся безобидными. Поменяли путь к actuator, включили флаг pilot-сценария — а потом никто не помнит, что и где меняли. Git поможет с application.yml, но не скажет, кто включал флаг в staging и где env var в секретах CI.

Data rollback — самый дорогой. Хорошая новость в том, что наш срез по reports read-only, поэтому здесь честно стоит не пустое n/a, а ясное объяснение: none, because pilot is read-only and does not change schema or seed data. Даже незадействованный слой отмечается явно.

Deployment rollback обычно кажется простым — пока кто-нибудь не вспомнит, что предыдущий артефакт уже несовместим с текущей схемой или конфигом. Тогда «вернуть старую сборку» не равно «вернуть рабочее состояние».

Хорошее практическое правило: на каждый из пяти слоёв — либо конкретный способ отката, либо none, because .... Пустые секции — не аккуратность, а приглашение к хаосу.

Небольшой фрагмент рабочего документа может выглядеть так:

## Откат данных
none, because pilot touches only `reports/*` read-only endpoints
and does not change schema, seed data or stored calculations.

## Откат зависимостей
restore Spring Boot version to `2.7.18`
and recover `gradle.lockfile` from baseline commit.

Ни поэзии, ни тумана. И прекрасно.

3. Abort conditions: измеримые стоп-сигналы

Даже самый аккуратный rollback-план почти декоративен, если команда заранее не договорилась, в какой момент его применять. Фраза «если станет плохо, откатим» звучит бодро, но по сути ничего не значит. Что такое «плохо» — упавший тест, флакнувший smoke check, жалоба коллеги в чате? Тут очень легко скатиться в долгие споры вместо действий.

Поэтому рядом с rollback-планом всегда живут abort conditions — заранее объявленные стоп-сигналы: измеримые, проверяемые, привязанные к конкретному pilot scope. Разница между обычным упавшим чеком и abort condition тонкая, но важная: failing check — сигнал «разберись», abort condition — «разбираться будем уже после возврата к baseline». То есть это не техническая ошибка, а управленческая граница риска.

Размытая формулировка Инженерно пригодная формулировка
Если что-то пойдёт не так, откатываем Если /reports/monthly отдаёт 5xx на staging после migration build — rollback
Если тесты станут нестабильными Если MonthlyRevenueIT падает 3 прогона подряд на чистом окружении — rollback
Если ответ как-то изменится Если JSON shape отличается от baseline snapshot — rollback
Если станет медленно Если p95 latency выросла более чем на 30% на smoke-нагрузке — stop and review

Для нашего pilot по модулю отчётов разумно добавить ещё одно, которого нет в таблице: feature flag не возвращает систему к старому поведению в staging. Видно, что это уже не «мне показалось», а наблюдаемые события.

Иногда в rollback-стратегию удобно добавить feature flag — быстрый выключатель и очень дешёвую первую реакцию:

reports_engine:
  boot3_pilot_enabled: false   # быстрый возврат к старому пути
  owner: dashboard-team
  rollback_window_minutes: 30

Но здесь важно не переоценить его магию: feature flag сам по себе не спасает от неудачного обновления зависимостей, не чинит сборку, не восстанавливает данные. Это инструмент config rollback, а не универсальная палочка-выручалочка.

Когда формулируете abort conditions, полезно задать себе очень приземлённый вопрос: поймёт ли другой инженер, дежурящий в 2:17 ночи, когда именно откатывать pilot, не звоня вам? Если ответ «ну, примерно да» — условие ещё сырое.

4. Owner approval: ответственные за откат

На небольших личных pet-проектах легко вообразить, что owner всегда один и тот же человек — вы. В реальной migration даже pilot быстро упирается в общие ресурсы: модуль у одной команды, конфиг у другой, CI/CD у третьей, база вообще под отдельным вниманием. Не зафиксируете — rollback превратится в игру «кто сейчас достаточно смелый, чтобы нажать кнопку».

После предыдущих модулей у вас уже есть полезная привычка смотреть на риск и права доступа заранее. Migration по определению не из категории «мелких безобидных задач», поэтому в ROLLBACK.md пишем не абстрактное «команда решит», а конкретного владельца слоя или хотя бы конкретную роль.

Для нашего сценария с CashFlow Dashboard картина может быть такой:

Область Кто подтверждает Почему именно он
Код reports/* tech lead модуля отчётов Он отвечает за поведение pilot scope
Версии Boot / Gradle / lockfile build/platform owner Он понимает совместимость сборки и зависимостей
Feature flags и runtime config owner сервиса или on-call Он управляет включением конфигурации в окружении
Изменения схемы данных data owner Только он подтверждает rollback данных и backup
Возврат релизного артефакта release/on-call engineer Он владеет деплой-процессом

Здесь есть важный психологический эффект: как только вы записали owner, rollback перестаёт быть абстракцией — у документа появляется адресат. А когда адресата нет, аварийные действия принимают те, кто просто оказался ближе к клавиатуре. Плохой критерий.

Ещё одна тонкость: Claude Code поможет собрать черновик, найти конфиги, напомнить про lockfile, подсказать владельцев по структуре репозитория. Но решение «откатываем» остаётся человеческим. Это не недоверие к AI, а нормальная инженерная гигиена: у migration-агента нет полномочий самостоятельно решать судьбу общих ресурсов — максимум, напомнит, что у ресурса есть владелец.

5. Структура хорошего ROLLBACK.md

Теперь соберём всё в один рабочий артефакт. Хороший ROLLBACK.md — не роман, не послание потомкам и не чек-лист на двадцать экранов. Короткий, жёсткий и очень конкретный документ на три вопроса: что откатываем, при каком сигнале и кто подтверждает.

В начале документа полезно зафиксировать контекст pilot’а: какой slice мигрируем, в какой ветке или worktree, от какого baseline commit отталкиваемся, кто владелец документа и когда он последний раз проверялся. Звучит бюрократично — ровно до первого момента, когда у вас открыто три похожих ветки, две из них названы почти одинаково. Тогда подпись Branch: migration/boot3-pilot внезапно оказывается одной из лучших строк в вашей жизни.

Черновой каркас может быть таким:

# ROLLBACK.md

Pilot: `reports` Boot 3.x pilot
Branch: `migration/boot3-pilot`
Baseline commit: `a1b2c3d`
Owner: `@dashboard-tech-lead`

## Откат кода
## Откат зависимостей
## Откат конфига
## Откат данных
## Откат деплоя
## Условия прерывания
## Владельцы и одобрения

После этого каждый раздел надо заполнять не общими пожеланиями, а конкретикой. Хорошая секция Code rollback называет файлы и минимальный прогон после отката. Dependency rollback указывает, где именно фиксируется версия: build.gradle.kts, gradle.properties, gradle.lockfile, wrapper-конфиг. Config rollback называет feature flag, env var или config path. А незадействованный слой получает не ленивое n/a, а честное объяснение.

Небольшой фрагмент уже заполненного документа для нашего pilot может выглядеть так:

## Откат кода
restore `reports/*`, `build.gradle.kts` and `gradle.lockfile`
from baseline commit `a1b2c3d`, then rerun `reports-it`.

## Откат конфига
set `reports.boot3_pilot_enabled=false`
and restore previous actuator path settings in staging.

## Откат данных
none, because pilot is read-only and does not touch schema or stored data.

Обратите внимание на стиль: всё написано так, чтобы другой человек взял файл и выполнил действия без телепатии. В этом и смысл.

Есть ещё одна небольшая, но очень полезная привычка — связывать ROLLBACK.md с соседними артефактами: в шапке — ссылка на MIGRATION_PLAN.md, в abort conditions — на smoke checks или integration suite. Тогда у вас не россыпь Markdown-файлов, а связанный пакет migration evidence.

6. Claude как помощник по rollback-плану

Когда речь заходит об артефактах вроде ROLLBACK.md, новички иногда совершают зеркальные ошибки. Одни вообще не подключают Claude Code — «это же управленческий документ, AI тут не нужен». Другие, наоборот, пишут «сделай rollback plan» и надеются на волшебство. Обе крайности так себе: Claude полезен как исследователь и редактор, а не как тот, кто принимает решение.

Лучший режим работы — plan-first и read-only. То есть вы не просите Claude что-то откатывать, а просите подготовить черновик по pilot scope, просмотрев код, конфиги и build-файлы. Хороший запрос может звучать так:

Review the pilot scope in `reports/*` and draft `ROLLBACK.md`.
Для каждой секции напиши:
- exact rollback action, or
- `none, because ...`
List measurable abort conditions and required owners.
Do not edit code. Do not start migration.

Такой запрос хорош тем, что сразу задаёт формат мышления: Claude не уходит в implementation и не прячет пустые места за красивыми словами. Либо действие, либо честное «почему слой не участвует».

После этого начинается самая важная часть — человеческая проверка. Вам нужно пройтись по черновику и задать приземлённые вопросы. Воспроизводим ли dependency rollback и не забыт ли lockfile? Выполним ли config rollback без доступа в три системы? Кто именно владелец shared feature flag? Если где-то написано «просто вернуть предыдущую версию» — это не план, а пожелание.

Очень полезно также просить Claude отдельно искать пробелы, а не только писать текст: все ли пять слоёв закрыты, не размыты ли abort conditions, не забыты ли owner approvals. В этом режиме он особенно хорош — выступает не как автор, а как педантичный второй читатель, который спасает команду от красивого, но бесполезного файла.

И когда ROLLBACK.md после такого прохода становится коротким, понятным и связанным с реальным объёмом pilot-среза, migration внезапно перестаёт выглядеть как прыжок в темноту. Рискованной она быть не перестаёт. Но это уже контролируемый риск, а не надежда на «ну Git же есть, как-нибудь выкрутимся».

1
Задача
Claude code, 29 уровень, 1 лекция
Недоступна
Черновик rollback outline внутри Claude CLI
Черновик rollback outline внутри Claude CLI
1
Задача
Claude code, 29 уровень, 1 лекция
Недоступна
Документирование полного rollback plan
Документирование полного rollback plan
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ