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

Інвентаризація поведінки перед змінами

Claude code
Рівень 26 , Лекція 4
Відкрита

1. BEHAVIOR_INVENTORY.md поруч із risk map

Коли у вас уже є карта ризиків, дуже легко потрапити в пастку хибного спокою: ось небезпечні зони, no-test area, fragile config — здається, ніби все вже зрозуміло. Але risk map каже, де змінювати небезпечно, і мовчить про те, яка поведінка там живе і що не можна зламати. Для зміни коду цього недостатньо.

Зручно тримати в голові просте розділення ролей між артефактами:

Артефакт На яке запитання відповідає Що дає вам на практиці
ARCHITECTURE_CURRENT.md
Як система влаштована зараз? Поточну картину без прикрас
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, а «Часткове повернення посеред періоду». Тоді його зрозуміє і інженер, який відкриє файл через місяць.

Приклад одного запису:

## Потік
Пауза підписки та подальше відновлення

## Поточна поведінка
Під час паузи підписка залишається в 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 subscription залишається в 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. Часті поломки inventory на етапі 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
Опитування
Legacy discovery: поточна архітектура і ризик-карта, рівень 26, лекція 4
Недоступний
Legacy discovery: поточна архітектура і ризик-карта
Legacy discovery: поточна архітектура і ризик-карта
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ