1. Призначення risk map як карти рішень
Коли ви вперше заходите в legacy-сервіс на кшталт CashFlow Dashboard, спокуса дуже зрозуміла: виписати довгий список усього неприємного і відчути, що робота виконана. Тут deprecated, тут мало тестів, тут конфіг ніби писала людина в ліфті між поверхами. Команді такий список майже марний: він не підказує, куди йти, а куди краще навіть не сунути викрутку.
RISK_MAP.md потрібен саме для цього: він перетворює хаос знань на керовану карту «що небезпечно змінювати, наскільки це важливо для бізнесу і яку дію розумно зробити наступною». Legacy страждає не від того, що код місцями сумний. Legacy страждає від того, що хтось каже «та я тут один рядок поправлю», — і до вечора у фінменеджера MRR з’їжджає на вісім відсотків.
Корисно тримати в голові три артефакти поруч, тому що вони відповідають на різні питання:
| Артефакт | На яке питання відповідає |
|---|---|
|
Що взагалі є в проєкті? |
/ current-state notes |
Як система реально працює зараз? |
|
Де зміна найбільш небезпечна і що з цим робити? |
Якщо говорити зовсім просто, inventory — це карта вулиць, current-state документ — опис дорожнього руху, а risk map — позначки «тут міст ремонтують, сюди краще не сунутися без плану». І саме ця третя частина найчастіше виявляється найпрактичнішою: вона рятує команду від героїчного, але дуже дорогого хаосу.
Тому RISK_MAP.md — не Markdown-версія тривожного щоденника, а спосіб перестати ставитися до всіх зон однаково: mrr-engine, прапорці в конфігу і старий клас із legacy/ не рівні за ризиком, навіть якщо так і просяться «терміново почистити».
2. Дві осі: criticality і change risk
Найкорисніша думка в цій лекції дуже проста: у risk map завжди мінімум дві осі. Перша — «наскільки боляче бізнесу, якщо область зламається», друга — «наскільки ймовірно і дорого щось зламати, якщо туди полізти». Поки ви їх не розділили, карта бреше.
Business criticality, важливість для бізнесу, вимірюється не красою коду, а наслідками. Зламалася логіка MRR — це бачать Commerce OS, фінансові звіти, бухгалтерія, і за кілька годин це вже грошова проблема. Зламався формат підпису в некритичному звіті — світ не падає.
Change risk, ризик зміни, дивиться зовсім в інший бік: тут цікаво не те, наскільки область важлива, а те, наскільки вона крихка. Низьке покриття, розбіжність документації і коду, високий churn в історії Git, неясний власник, конфіг між yaml і змінними середовища — усе це робить зону небезпечною, навіть якщо вона не є головним бізнес-флоу.
Добре працює така спрощена матриця:
| Важливість для бізнесу \ Ризик зміни | Низький ризик зміни | Високий ризик зміни |
|---|---|---|
| Низька важливість | Можна досліджувати і змінювати досить вільно | Не варто лагодити «заодно»; спочатку зрозуміти, чому зона така крихка |
| Висока важливість | Змінювати можна лише вузько і з явною перевіркою | Червона зона: спочатку потрібні додаткові докази, власник і обмеження |
Саме тому mrr-engine у CashFlow Dashboard майже автоматично падає у правий верхній кут: бізнес-критичний і ризикований у зміні. А старий utility-клас із legacy/, навіть потворний, скоріше потрапить у «високий change risk, але не перший пріоритет за бізнесом».
Дуже важливо не склеювати ці осі в одну оцінку «небезпечно / не небезпечно». Інакше команда або панічно уникає всіх змін, або безтурботно чіпає критичні флоу. Legacy такі ілюзії любить. Потім виставляє рахунок.
3. Unknowns як повноцінний сигнал ризику
На legacy-проєктах слово «unknowns» звучить менш урочисто, ніж мало б, — а на практиці саме невідомість часто і є головним підсилювачем ризику. Найнебезпечніше тут — вдавати, ніби картина ясна. Claude Code теж не проти зробити розумний вигляд і продовжити — не піддавайтеся.
Невідомість у risk map — не сміттєвий залишок після аналізу, а повноцінний сигнал. Не знаємо, як система поводиться на межі місяця під час зміни таймзони, — це не «поки без оцінки», а підвищений ризик. У PaymentRetryService логіка начебто відновлює підписку після retry, але тесту немає — і невідомість сама піднімає change risk.
На CashFlow Dashboard хороший приклад — тема паузи підписки. Документ каже, що paused subscription не входить в активний MRR, а код у MrrFormulas.java рахує її активною. Чесне формулювання не «логіка, мабуть, виключає paused», а «документація і код розходяться; потрібна ручна перевірка».
Корисне правило тут жорстке: якщо Claude не показав evidence anchor, значить, він не знає, а припускає. Тоді в артефакті з’являється позначка assumption або manual verification needed, а не впевнений висновок. Проєкт і так страждає від накопичених напівправд — не додавайте ще одну, тепер зі штучним інтелектом.
І так, іноді найпрофесійніша дія на цьому етапі — чесно написати: «власник області неочевидний», «реальна поведінка в проді не підтверджена», «конфіг зібраний із кількох джерел і потребує ручної звірки». Це не слабкість аналітика, а інженерна гігієна.
4. Зміст одного запису в RISK_MAP.md
Коли risk map зроблено добре, він читається швидко і допомагає так само швидко ухвалювати рішення, тому структура запису проста і повторювана, без літературних відступів на пів сторінки. Сам файл — артефакт проєкту: Workflow Kit дасть шаблон, skill або read-only агента, але RISK_MAP.md живе поруч із CashFlow Dashboard.
На практиці один запис відповідає на сім питань, зводячи спостереження із signal log і current-state не в дубль, а в рішення.
| Поле | Що воно має прояснити |
|---|---|
|
Про яку область проєкту йдеться |
|
Наскільки боляче бізнесу, якщо там щось зламається |
|
Наскільки небезпечно вносити туди зміни |
|
Якого типу це ризик: дані, конфіг, невідома поведінка, слабкі тести і так далі |
|
На чому ґрунтується висновок: файли, рядки, логи, звіти, git log, coverage |
|
Чого нам бракує для впевненого внесення змін |
|
Що розумно зробити зараз, а не колись у світлому майбутньому |
Запис не має перетворюватися на мініроман. Ось компактний робочий фрагмент:
## Область
mrr-engine / pause-resume MRR
**Критичність для бізнесу:** висока
**Ризик зміни:** високий
**Категорії ризику:** business-critical, no-test, unknown behavior
**Докази:** `MrrFormulas.java:88`, `SubscriptionService.java:154`, JaCoCo ~25%
**Бракує перевірок:** немає сценарію pause-resume
**Рекомендована дія:** не змінювати формули до фіксації поточної поведінки та review власником
Зверніть увагу на дві пастки. Missing checks — не Evidence: одне говорить, що ми знаємо, інше — чого бракує. А Recommended action — не «покращити код», а виконувана дія: заморозити зміну, уточнити власника, зафіксувати поведінку, обмежити scope, не чіпати зону.
Якщо в запису немає останнього рядка, він майже завжди марний: risk map існує заради вибору наступного ходу, а не опису страху.
5. Використання Claude Code
На цьому етапі Claude Code дуже корисний, але строго в режимі «прискорюємо збір evidence», а не «нехай сам поставить діагноз». Тримайте сесію в read-only: агент читає, шукає по коду, дивиться git log, відкриває звіти, але не редагує. Нам не потрібен ентузіаст з редактором — потрібен швидкий акуратний дослідник.
Добрий запит до Claude в цій задачі виглядає структуровано і нудно — і це комплімент:
Проаналізуй область `mrr-engine` як елемент risk map.
Поверни:
1. business criticality,
2. change risk,
3. categories,
4. evidence,
5. missing checks,
6. recommended action.
Код не змінюй.
Формат повертає дані у формі, з якої реально зібрати RISK_MAP.md, і не дає Claude зіскочити в звичне «ось ще три ідеї рефакторингу, які я придумав вам безкоштовно». Безкоштовне в legacy потім оплачується дорого.
Якщо команда вже зібрала Workflow Kit, там може жити read-only агент risk-mapper — з навмисно нудною і обмеженою конфігурацією:
---
name: risk-mapper
description: Збирає RISK_MAP.md тільки за evidence, без правок коду
tools: Read, Grep, Glob, Bash(git log:*)
---
Тут важливе саме обмеження. Дайте агенту Edit — він рано чи пізно почне «допомагати», а потрібна дисципліна: прочитай, порівняй, зібери anchor, познач невідоме, зупинися.
Ще одна корисна звичка — вимагати опори під кожним висновком. «Зона високого ризику через складність» — красиво і марно; нехай покаже файл, coverage, git log, документ, що розходиться з кодом. Не може — отже, це гіпотеза, позначена чесно.
І ще один технічний нюанс, про який часто забувають: тримайте файл поруч із кодом, інакше через два тижні він стане «десь там була корисна markdown-ка», яку ніхто не відкриває.
6. CashFlow Dashboard: mrr-engine, retry і конфіги
Тепер давайте приземлимо все це на проєкт. У CashFlow Dashboard є щонайменше три дуже показові зони — вони хороші тим, що показують: високий ризик народжується з комбінації бізнес-критичності і слабкої перевірюваності. Спочатку подивімося на компактну картину:
| Область | Business criticality | Change risk | Чому це небезпечно | Розумна дія |
|---|---|---|---|---|
|
Висока | Високий | Впливає на MRR, coverage низький, код і документи розходяться | Не змінювати формули без фіксації поточної поведінки |
|
Висока | Високий | Зачеплені гроші, зовнішня інтеграція, неочевидні гілки retry | Спочатку уточнити реальний потік і власника області |
|
Середня/висока | Високий | Конфіг розмазаний по yaml і env, таймзона поводиться нерівномірно | Спочатку зібрати current-state конфігурації, не чіпати «заодно» |
mrr-engine — майже навчальний приклад червоної зони. Є реальний бізнес-біль: Commerce OS уже скаржиться на розбіжність MRR, а під капотом низьке покриття і формули в кількох файлах. Навіть простий сигнал із Git це підсвічує:
git log --since="1 year ago" --name-only --pretty=format: \
| grep 'mrr-engine/MrrFormulas.java' | wc -l
# 11
Одинадцять змін самі по собі ще нічого не доводять. Але складіть їх із coverage близько 25% і розбіжністю документа з кодом — і вийде вже не відчуття, а цілком пристойний пакет доказів. Запис для mrr-engine:
## Область
mrr-engine / pause-resume MRR
**Критичність для бізнесу:** висока
**Ризик зміни:** високий
**Категорії ризику:** business-critical, no-test, unknown behavior
**Докази:** `MrrFormulas.java:88`, `SubscriptionService.java:154`, `git log`, JaCoCo ~25%
**Бракує перевірок:** немає сценарію pause-resume і перевірки межі місяця
**Рекомендована дія:** обмежити будь-які зміни, доки не підтверджено поточну поведінку
Тепер візьмімо payments / retry recovery — тут risk map менш очевидна, бо код іноді акуратніший, ніж у mrr-engine. Але навіть за кращого покриття помилка дорога — особливо коли неясно, коли підписка відновлена після retry, а коли має потрапити в churn.
Третя зона — конфіги і таймзона. Це той випадок, коли багато хто недооцінює ризик, бо «ми ж не змінюємо бізнес-логіку, лише поправимо конфіг». На legacy така фраза звучить приблизно як «я лише трохи посунув цеглину в несучій стіні». Feature flags розмазано між application.yml, середовищем і старими overrides, дати місцями йдуть через UTC, місцями через local time — change risk високий навіть без алгебраїчних формул.
І є ще один підступний приклад: legacy/OldBillingUtils.java. Важливість для бізнесу в нього може бути неочевидною, на перший погляд — просто старий utility, який дуже хочеться переписати заради внутрішнього спокою і душевного здоров’я. Але він використовується в десятках місць і без покриття — change risk високий. Risk map дає змогу сказати: «ні, це не перша ціль» — не тому, що код хороший, а тому, що ціна необережного покращення вища за очікувану користь.
7. Читання готової risk map і ухвалення рішень
Коли RISK_MAP.md починає працювати, він перестає бути документом «для галочки» і стає фільтром: кожне нове питання по legacy звучить трохи інакше — не «чи можемо ми це швидко поправити?», а «що карта каже про ціну виправлення?».
Хороша карта допомагає ухвалювати чотири практичні рішення. Іноді вона каже: сюди можна йти, але вузько і обережно. Іноді: сюди — лише після уточнення власника і поведінки. Іноді: сюди взагалі не треба лізти в межах задачі, вона роздується і потягне ще три підсистеми. І, що особливо цінно, іноді карта дає право сказати «не зараз» — не зі страху, а з інженерної дисципліни.
Водночас карта не зобов’язана бути величезною, їй не потрібно покривати кожен файл: десять змістовних записів корисніші за п’ятдесят рядків «щось тут тривожно». Не допомагає вирішити, як поводитися з областю, — значить, запис ще сирий.
І так, risk map — живий артефакт: з’явився власник, підтягнули evidence, зникла розбіжність документа і коду — місце зони змінюється. Але починаємо не з оптимізму, а з доказів.
Коли ви дивитеся на CashFlow Dashboard і замість імпульсу «треба терміново все почистити» спокійно кажете: «ось червона зона, ось чому вона червона, і чому туди зараз не можна без додаткового evidence», — RISK_MAP.md уже не декоративний. Він працює. Так і починається доросле ставлення до legacy — навіть якщо сам legacy все ще виглядає так, ніби його писали в ніч перед релізом.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ