JavaRush /Курсы /Claude code /Инвентаризация поведения перед изменениями

Инвентаризация поведения перед изменениями

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

1. BEHAVIOR_INVENTORY.md рядом с risk map

Когда у вас уже есть карта рисков, очень легко попасть в ловушку ложного спокойствия: вот опасные зоны, no-test area, fragile config — кажется, будто всё уже понятно. Но risk map говорит, где менять опасно, и молчит о том, какое поведение там живёт и что нельзя сломать. Для изменения кода этого недостаточно.

Удобно держать в голове простое разделение ролей между артефактами:

Артефакт На какой вопрос отвечает Что даёт вам на практике
ARCHITECTURE_CURRENT.md
Как система устроена сейчас? Current-state картину без украшательств
RISK_MAP.md
Где изменение особенно опасно и почему? Приоритет зон внимания и тип риска
BEHAVIOR_INVENTORY.md
Какие сценарии система реально выполняет? Перечень поведений, которые надо понимать
Список characterization candidates Что стоит зафиксировать тестами до изменений? Очередь на будущую safety net

Characterization candidate — это сценарий, который позже имеет смысл зафиксировать baseline-тестом. Сегодня test не пишу и не превращаю candidate в красивую метку важности: ставлю yes или no по риску, неизвестности и missing checks.

Если у вас уже есть CRITICAL_FLOWS.md, он остаётся крупнозернистой картой: где проходят деньги, retry, MRR, возвраты. BEHAVIOR_INVENTORY.md идёт глубже — раскладывает каждый поток на записи уровня сценария: inputs, outputs, evidence, characterization.

Если совсем по-простому, RISK_MAP.md — это карта минного поля, а BEHAVIOR_INVENTORY.md — список того, что в поле лежит. Без второго вы знаете, что шагать опасно, но не понимаете, за что боретесь. Это как прийти в старую квартиру перед ремонтом, обвести красным несущие стены — и не сфотографировать, где были трубы, розетки и выключатели. Ремонт бодрый, а удивление ещё бодрее.

Для CashFlow Dashboard это особенно важно, потому что почти все неприятные истории живут в сценариях, а не в названиях модулей. Не «модуль mrr-engine опасный», а «пауза подписки не уменьшает MRR». Не «payments/ выглядит сложно», а «успешный retry после failed payment, возможно, не создаёт churn dip». Вы мыслите бизнес-сценариями, а не папками, — это и есть переход от чтения кода к пониманию системы.

2. Состав одной записи в BEHAVIOR_INVENTORY.md

Хороший inventory не пытается быть энциклопедией: он подробен настолько, чтобы потом на его основе принять решение, и компактен настолько, чтобы его вообще можно было читать без обезболивающего. Запись строится вокруг одного понятного flow, а не файла, пакета или строки кода, и называется живым действием. Не MrrFormulas.java:88, а «Пауза подписки и последующее возобновление». Не RefundService, а «Частичный refund в середине периода». Тогда её поймёт и инженер, который откроет файл через месяц.

Пример одной записи:

## Поток
Пауза подписки и последующее возобновление

## Текущее поведение
Во время паузы подписка остаётся в active MRR; после resume сумма не меняется

## Входы
plan=pro, $50/month, pause day 10, resume day 40

## Выходы
MRR snapshot остаётся $50 на всём интервале pause/resume

## Существующие тесты
Нет

## Недостающие проверки
Нет проверки MRR во время паузы и после resume

## Кандидат на characterization
yes

## Доказательства
`MrrFormulas.java:88`, `SubscriptionService.java:154`

Внутри такой записи у каждого поля своя задача. Current behavior — что система делает сегодня, без фантазии «как должно быть». Inputs нужны не для красоты, а чтобы сценарий воспроизводился: реальные значения из sample data, логов или тестов, а не «какая-то подписка». Outputs — результат наблюдаемый, а не предполагаемый.

Два поля студенты часто смешивают, и зря: Existing tests («что уже есть») и Missing checks («чего нет, даже если что-то частично покрыто»). Это разные вещи. Тест на happy path не значит, что edge case защищён. В legacy это болезненно: видят один integration test и радостно говорят «ну тесты есть». Есть. Но не про то.

Наконец, поле Characterization candidate — это уже не описание, а инженерное решение: фиксировать ли flow тестом. И очень важно, что появляется оно внутри записи, а не фантазией сбоку — растёт из конкретного flow, а не из общего ощущения тревоги.

3. Текущее поведение не равно правильному поведению

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

Представьте ситуацию: в BILLING_RULES.md написано, что paused subscription не входит в active MRR. Красиво, логично, бухгалтер плакал бы от счастья. А в коде MrrFormulas.java вы видите, что paused подписка остаётся в active set. Что писать? Поведение по коду плюс пометку о расхождении с документацией. Иначе вы не документируете систему, а спорите с ней. Держите в голове различие:

Неправильная запись Правильная запись
Во время паузы подписка не должна учитываться в MRR По текущему коду paused subscription остаётся в active MRR; документация этому противоречит
Retry-success корректно восстанавливает доход После retry-success churn dip не обнаружен; подтверждающего теста нет, нужна ручная проверка
Refund считается правильно По сценарию partial refund середины периода итоговая сумма уменьшается по формуле из RefundService, но поведение на proration не покрыто тестом

То есть вы всегда описываете сначала факт, а потом, если нужно, расхождение — не наоборот. Это защищает от неприятной истории: команда начинает изменения, уверенная, что зафиксировала baseline, а он уже был тихо «улучшен» на бумаге.

Здесь же важно разделять confirmed fact и assumption. Если вы видите код, но не можете уверенно сказать, что ветка исполняется, — так и пишите: «предположение, нужна ручная проверка». Legacy не становится лучше от уверенного тона. Он просто получает повод сломать вам субботу.

4. Признаки сильного characterization-кандидата

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

Хороший кандидат обычно отвечает хотя бы одному из трёх сильных признаков. Первый — завязан на business-critical или high-risk area из RISK_MAP.md. Второй — edge case без проверок. Третий — расхождение между кодом, документацией и ожиданиями. Сходятся вместе — почти наверняка yes.

Flow Решение Почему
Пауза подписки и resume yes Business-critical, нет тестов, есть расхождение code vs docs
Partial refund mid-period yes Денежный сценарий, сложная формула, edge case без покрытия
Failed payment → retry success yes Влияет на churn/MRR, поведение неочевидно, тестов мало
Порядок колонок в CSV-экспорте скорее no Неприятно, но низкий риск и легко проверяется вручную
Текст подсказки на help-экране no Не влияет на расчётную логику и не требует characterization baseline

Для CashFlow Dashboard разумный ориентир — не гнать пятьдесят кандидатов за один заход. Лучше соберите 10–15 сильных сценариев, где велик риск повредить важное поведение: pause/resume, refund, upgrade/downgrade в середине периода, retry logic, переключение плана в день биллинга. Этого хватит, чтобы строить safety net осмысленно.

Если вы используете Claude Code как помощника на этом шаге, лучше давать ему задачу не «придумай тесты», а именно «классифицируй кандидатов». Например:

Для каждой записи из BEHAVIOR_INVENTORY.md реши,
нужен ли characterization candidate = yes.

Ставь yes, если выполняется хотя бы одно условие:
1. сценарий связан с high-risk или business-critical зоной из RISK_MAP.md;
2. есть missing checks для edge case;
3. есть расхождение между кодом и документацией.

Верни: flow, решение, причина, evidence.
Код тестов не предлагай.

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

5. Связка discovery, risk map и inventory в цепочку

Очень полезно смотреть на этот уровень не как на пять отдельных разговоров, а как на одну цепочку артефактов — тогда BEHAVIOR_INVENTORY.md не «ещё один документ», а звено, вырастающее из evidence.

файлы + тесты + логи + команды
            ↓
 discovery findings + signal log
            ↓
 ARCHITECTURE_CURRENT.md
(при необходимости — MODULE_INVENTORY/CRITICAL_FLOWS)
            ↓
        RISK_MAP.md
            ↓
   BEHAVIOR_INVENTORY.md
            ↓
characterization candidates (yes/no)

То есть вы не садитесь и не выдумываете flows с нуля — порядок в схеме читается сверху вниз, а решение о фиксации приходит последним. Возьмём один живой пример: discovery показал, что jobs/MrrSnapshotJob.java пересчитывает MRR по расписанию; risk map отметил зону mrr-engine / pause-resume как business-critical и no-test; inventory описал flow «пауза подписки и последующее возобновление» с input/output и evidence. И только теперь вы пишете Characterization candidate: yes. Не раньше.

Это очень отрезвляет и в работе с Claude Code. Если попросить модель сразу «найти, что покрыть тестами», она почти наверняка срежет углы и выдаст советы, плохо привязанные к evidence. Если же дать ей RISK_MAP.md и BEHAVIOR_INVENTORY.md, вы вынуждаете её работать как аналитика, а не как вдохновенного угадывателя.

Если вам помогает read-only агент из Workflow Kit, хорошо, когда задачу вы ставите не героически, а скучно и по делу: собрать факты, не предлагать правок, вернуть решение и evidence. Чем скучнее и проверяемее помощник, тем меньше потом сюрпризов.

6. CashFlow Dashboard: три явных кандидата

На CashFlow Dashboard есть несколько сценариев, которые прямо напрашиваются в BEHAVIOR_INVENTORY.md и почти автоматически получают yes в колонке characterization candidate.

Flow Risk area Candidate Почему
Partial refund в середине периода refunds / MRR yes Денежная логика, proration, неочевидный расчёт
Failed payment, затем retry success payments / MRR yes Влияет на churn и continuity revenue
Plan switch в день биллинга billing / MRR yes Пограничная дата, высокий шанс неочевидного поведения
Текстовое описание тарифа в help-секции docs / UI no Не формирует критичный baseline для legacy-перестройки

Посмотрим на один сценарий чуть ближе. Partial refund mid-period — классический кандидат. Опасность не только в деньгах: формула часто размазана по нескольким файлам — RefundService, биллинговый расчёт, MRR snapshot. Не зафиксируете поведение до изменений — потом не ответите: это новый баг или вы «починили» старую неочевидную ветку.

Сценарий retry success после failed payment кажется проще, но это обманка. По-человечески хочется сказать: «ну платёж же потом прошёл». А на системном уровне вопрос уже другой: был ли между failed payment и retry провал в churn-метрике, не считаем ли мы подписку непрерывной там, где была яма. Мало тестов, серьёзное влияние на метрики — кандидат почти обязателен.

А вот косметическая история с подсказкой в help-разделе сама по себе characterization candidate не заслуживает. Это не значит, что ею можно пренебречь: это значит, что baseline перед сложными изменениями строят не с неё. И это важный навык — не путать важное с просто заметным.

7. Частые поломки инвентаря на этапе discovery

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

Первая частая поломка — слишком мелкая гранулярность. Если заведёте запись на каждый условный if, получите файл, который никто не дочитает. Flow — на уровне узнаваемого бизнес-сценария. Пауза подписки — да. «Ветка else в строке 67» — нет.

Вторая поломка — отсутствие evidence в надежде «потом допишу». Не допишете, а legacy такие пустоты любит особенно нежно. Нет ссылки на код, тест, лог или вывод команды — это не запись inventory, а заметка на память. Помечайте сразу как гипотезу.

Третья неприятная вещь — смешивать текущий baseline с планом ремонта. Как только рядом появляется мысль «здесь бы переписать на отдельный сервис», inventory течёт в сторону modernization roadmap. А это уже другой артефакт и другой разговор. Здесь вы не проектируете лечение — вы делаете снимок пациента перед операцией.

И последнее. Не спешите писать сами characterization tests, даже если руки чешутся и Claude уже подсовывает заготовки. Сегодня задача — чтобы напротив важных flows стояло честное yes, а рядом лежало достаточно доказательств. С таким BEHAVIOR_INVENTORY.md legacy перестаёт быть тёмной комнатой: он всё ещё старый, местами вредный и пахнет 2019 годом — но уже понятно, за какие провода нельзя дёргать без перчаток.

Когда такой inventory собран, следующий шаг становится гораздо яснее: записи с characterization candidate = yes идут в before-change baseline и только потом превращаются в тесты. Сейчас достаточно честно отметить эти точки и не перепрыгивать к реализации.

1
Задача
Claude code, 26 уровень, 4 лекция
Недоступна
Инвентаризация поведения четырёх flows legacy-сервиса
Инвентаризация поведения четырёх flows legacy-сервиса
1
Опрос
Legacy discovery: текущая архитектура и риск-карта, 26 уровень, 4 лекция
Недоступен
Legacy discovery: текущая архитектура и риск-карта
Legacy discovery: текущая архитектура и риск-карта
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ