1. Карта — ще не маршрут
Після дослідження кодової бази легко зловити оманливе відчуття, що задача вже майже вирішена: лишилося набрати кілька рядків і прийняти оплески. На практиці саме в цей момент найчастіше починається локальний хаос: ви зрозуміли, де змінювати, але не що саме і не в якому порядку.
Investigation Note відповідає на запитання «Де живе проблема?». Але це ще не план — це карта місцевості, а не маршрут. Карта показує міст і річку, але не каже, їхати через міст чи об’їжджати, тому що він у ремонті. З кодом так само: баг пов’язаний із OrderController, OrderService, GlobalExceptionHandler і тестами checkout — але де ставити захист, як повернути 400 і чим довести, що валідний checkout не зламано, ще незрозуміло.
Зручно тримати в голові дуже простий ланцюжок:
Issue Intake Note → Investigation Note → Approved plan → лише потім зміни
Якщо перескочити через затверджений план, Claude перетворюється на дуже старанного помічника, який відремонтує півквартири, поки ви просили підтягнути дверну ручку. Він не злий, він допомагає занадто широко. Ваше завдання — дати йому не лише напрям, а й межі.
2. Слово approved вирішує все
Тепер давайте заземлимо термін. Implementation Plan — не документ «для порядку» і не любов до таблиць, а узгоджений людиною чернетковий варіант майбутньої реалізації. Живе поруч із Issue Intake Note або окремим блоком у TASK_SPEC.md. Сенс один: до старту кодових змін ви фіксуєте маршрут і перевіряєте, що він адекватний.
Слово approved тут особливо важливе. Чернетку Claude збере хорошу, але затверджує людина: вона приймає ризик, погоджується на межі й відповідає, що план вирішує потрібну проблему, а не просто виглядає переконливо. А «виглядає переконливо» — небезпечна категорія.
Ось що саме ви затверджуєте, коли дивитеся на план:
| Що в плані | На яке запитання ви відповідаєте |
|---|---|
| Мета | Ми справді лікуємо потрібну проблему, а не сусідній симптом? |
| Scope | Зміни залишаються в розумних межах? |
| Non-goals | Зрозуміло, чого ми не робимо «заодно»? |
| Ризики | Ми розуміємо, що можемо зламати? |
| Перевірки | У нас є реальний спосіб довести результат? |
| Stop conditions | Зрозуміло, коли треба зупинитися, а не «дотискати»? |
Чернетку плану зручно замовляти у Claude у дуже прямій формі — без магії, без «зроби красиво», без надії, що він сам здогадається, який формат вам потрібен.
Підготуй чернетку плану за задачею про empty cart у checkout.
Не змінюй код.
Поверни: goal, scope, non-goals, affected files, steps, risks,
verification strategy, stop conditions.
Якщо доказів бракує, познач unknown, а не вгадуй.
Бачите, тут немає жодного романтичного слова. І це добре: плани не зобов’язані надихати — вони зобов’язані економити вам помилки.
3. Кожна секція — на своє запитання
Коли ви вперше бачите хороший Implementation Plan, виникає дивне відчуття: він одночасно дуже простий і дуже дисциплінуючий. Зайвої філософії в ньому немає, зате кожна секція відповідає на окреме практичне запитання. А якщо якоїсь секції немає — це майже завжди не дрібниця, а дірка, через яку пізніше вилізе scope creep або неперевірений ризик.
Для нашого Commerce OS давайте візьмемо реалістичний тикет: при POST /api/orders з порожнім списком товарів backend повертає 500, а має 400 з зрозумілою validation error. Нижче — не величезний документ, а зручна карта секцій, які в плані мають бути.
| Секція | Що означає по-людськи | Приклад для Commerce OS |
|---|---|---|
|
Що саме має стати краще | Порожня корзина більше не валить checkout у 500, а API повертає зрозумілу validation error |
|
Де працюємо | Валідація empty cart у checkout, пов’язаний error mapping і релевантні тести |
|
Що не робимо заодно | Не редизайнимо корзину, не змінюємо UX непорожнього checkout, не чіпаємо unrelated pricing logic |
|
Які файли найімовірніше зачепимо | OrderService, GlobalExceptionHandler, OrderControllerWebTest і, за потреби, точка входу в OrderController |
|
У якому порядку рухаємося | Спочатку зафіксувати empty cart test, потім закрити доменну перевірку, потім привести HTTP-відповідь до узгодженого формату |
|
Що може піти не так | Можна випадково змінити валідний checkout або зламати загальний формат помилок |
|
Як доведемо результат | Автотести + відтворюваний запит POST /api/orders з порожнім items[] |
|
У яких випадках не продовжуємо | Якщо потрібна загальна переробка error schema, якщо змінюється shared pricing behavior, якщо diff лізе в сусідні checkout-модулі |
|
Як відкочуємося, якщо все пішло не так | Зміна має вміщуватися в один логічний відкат без схемних правок |
Корисно побачити план і у вигляді маленького фрагмента. Зверніть увагу: він не довгий, не бюрократичний і не намагається пояснити історію Всесвіту.
## Мета
Не давати POST /api/orders з порожнім items[] падати в 500;
повернути зрозумілу validation error.
## Область змін
Перевірка empty cart у checkout, error mapping і пов’язані тести.
## Не-цілі
Не змінюємо UI корзини, happy-path checkout і unrelated pricing code.
## Затронутые файлы
OrderService, GlobalExceptionHandler, OrderControllerWebTest
і за потреби точка входу в OrderController.
Важливо ще одне правило: не копіюйте в план весь Issue Intake Note і весь Investigation Note. План — робочий документ для реалізації, а не архів знайденого. Якщо 90% тексту повторюють уже знайдені факти, перед вами не маршрут, а переказ попередніх кроків самому собі.
4. Task risk list: ризики краще назвати до коду
Список ризиків здається нудним рівно до першого разу, коли ви його не написали, — тоді ризики перестають бути рядками в документі й перетворюються на сюрпризи у гілці, тестах і чаті команди. Тому хороший task risk list — не драматизація задачі, а нормальна інженерна чесність: зміна зачіпає не лише той шматок, який ви лагодите.
Для початківця корисно мислити про ризики не як про щось страшне, а як про сусідні поверхні, які зачіпає задача. Навколо empty-cart кейса в Commerce OS зазвичай спливають п’ять типів ризиків.
| Ризик | Severity | Чому це важливо | Що робимо |
|---|---|---|---|
| Зміниться поведінка валідного checkout | Medium | Можна випадково зачепити happy-path з непорожніми items[] | Обмежуємо нову перевірку сценарієм empty cart і окремо перевіряємо happy-path |
| Зламається очікування фронтенду щодо формату помилки | Medium | UI може бути прив’язаний до поточної shape response | Не змінюємо контракт помилки ширше, ніж потрібно, без окремого узгодження |
використовується ще десь |
Medium | Нова доменна захисна перевірка може зачепити інший сценарій | Перевіряємо всі використання до правки й мовчки не змінюємо загальну семантику методу |
| Потрібна загальна переробка error mapping | High | Це вже більше ніж одна локальна bugfix-задача | Ставимо stop condition і не продовжуємо «заодно» |
| Diff полізе в unrelated checkout/pricing файли | Low/Medium | Задача втрачає читабельність і форму, зручну для відкату | Звужуємо scope і переглядаємо steps |
Зверніть увагу на дві речі. По-перше, ризик без реакції майже марний. Якщо ви написали «може зламатися формат помилки», але не додали, як це помітити і що робити, це просто тривожна думка в гарній обгортці. По-друге, список ризиків не має бути нескінченним. Для звичайної задачі вам зазвичай вистачає трьох-шести реальних ризиків. Якщо їх двадцять, або задача занадто широка, або ви записуєте все підряд, включно з поганим настроєм checkout-flow по четвергах.
У практичній роботі добре працює просте правило: якщо ризик настільки серйозний, що при його настанні ви зобов’язані зупинитися, він має потрапити не лише до risk list, а й до stop conditions. Це вже не «на замітку», а жорстка межа.
5. Verification strategy: як довести результат
Ось тут план перестає бути просто «списком кроків» і стає інженерним документом. Бо будь-яку задачу можна красиво описати, але без verification strategy у вас лишається лише надія. А надія, як відомо, прекрасне людське почуття і дуже слабкий технічний інструмент.
У цьому курсі ви вже бачили базовий план перевірки. Тут ми використовуємо ту саму ідею, тільки застосовуємо її до конкретної великої задачі. Не лякайтеся слова strategy: мова не про багатосторінкову QA-методологію. На цьому рівні це дуже приземлена відповідь на запитання: що саме ми запускаємо, перевіряємо і вважаємо достатнім доказом.
Для нашого прикладу з empty cart секція може виглядати так:
## Стратегія перевірки
1. Запустити targeted web/API test на POST /api/orders з порожнім items[].
2. Додати сценарій: empty cart повертає 400, а не 500.
3. Перевірити ручним запитом, що response body лишається в узгодженому validation format.
4. Переконатися, що валідний checkout з непорожнім items[] поводиться як раніше.
5. Якщо з’ясується, що потрібен загальний redesign error schema, зупинитися.
Зверніть увагу: хороша verification strategy завжди конкретна. Фраза «поганяти тести» — погана. Вона не каже, які саме тести, на якому рівні й що вважатиметься успіхом. А от формулювання «додати сценарій, де empty cart повертає 400, а не 500» уже підходить: воно вимірюване, зрозуміле й прив’язане до задачі.
Дуже важливо не переплутати verification strategy з повним дизайном тестів. Тут ми ще не проєктуємо всю test strategy і не обговорюємо весь локальний harness. Ми просто фіксуємо нижній контракт перевірки для цієї задачі. Іншими словами: що ви маєте побачити, щоб чесно сказати «так, ця зміна працює і не рознесла сусідню поведінку».
Для початківця корисно запам’ятати ще один нюанс. Ручна перевірка тут не заборонена. Якщо ви не можете покрити все автоматикою негайно, ручний крок допустимий — але він має бути вузьким і відтворюваним. «Потикати руками, наче ок» — погана перевірка. «Надіслати POST /api/orders з порожнім items[] і переконатися, що приходить узгоджена validation error» — нормальна. Різниця маленька за словами і величезна за користю.
Якщо задача підходить для роботи за метою — цей режим ми вводили на рівні 6, а на TDD розбираємо далі в курсі, — то verification strategy має явно містити машинно-перевірювану умову фінішу: список команд і очікуваних результатів, за якими автоматичний цикл розуміє, що задача завершена. Тоді план перестає бути «списком кроків для людини» і стає специфікацією для циклу «за метою» — через slash-команду на кшталт /goal або скриптований цикл claude -p (точна назва й доступність можуть змінюватися від версії до версії). Якщо хоча б один пункт готовності суб’єктивний, умова фінішу розділяється на машинну частину для автоматичного циклу й людську — для схвалення.
6. Stop conditions і rollback notes
Ця частина багатьом здається надмірною, доки вони не спробують один раз «дотиснути» задачу без стоп-границь. Тоді з’ясовується, що stop conditions — це зовсім не песимізм, а спосіб не зіпсувати хороший план у той момент, коли реальність перестає збігатися з очікуваннями. Простіше кажучи, це заздалегідь написаний дозвіл самому собі не героїчно імпровізувати.
Хороший stop condition — це не «якщо стане складно, засмутитися». Це дуже конкретний сигнал: задача вийшла за поточні межі й потребує нової домовленості. Для empty-cart кейса такими стоп-сигналами можуть бути ось такі речі:
| Якщо сталося це | Що це означає | Правильна дія |
|---|---|---|
| Потрібно змінювати загальний формат помилок для checkout або кількох контролерів | Задача стала ширшою, ніж початковий scope | Зупинитися й винести це в окреме рішення |
| З’ясовується, що empty cart допустимий в іншому flow, наприклад у draft-order сценарії | Доменне правило неоднозначне | Не продовжувати без узгодження поведінки |
| Зміни полізли в shared pricing logic або unrelated checkout-модулі | План був занадто оптимістичним або хибним | Переглянути scope і affected files |
| Тести падають за межами empty-cart сценарію | Зміна зачепила сусідню поведінку | Не «лагодити по ланцюжку», а повернутися до plan |
Rollback note при цьому потрібен не для драматичного postmortem, а для звичайної інженерної гігієни: ви заздалегідь відповідаєте, як повертаємося назад, якщо рішення виявиться поганим. У невеликих задачах відповідь часто скромна, і це нормально.
## Нотатка про відкат
Зміна має вміщуватися в один логічний відкат.
Схемних і data-міграцій у межах задачі не допускається.
Якщо нова обробка empty cart поводиться неправильно,
ми відкочуємо локальний fix цілком і повертаємося
до останньої стабільної поведінки гілки без каскадних змін.
Чим нудніший rollback note, тим краще. Серйозно. Якщо для відкату потрібна окрема балада про доблесть і жертви, значить, задача від самого початку була занадто широкою.
7. Три артефакти — три запитання
Коли документів навколо однієї задачі стає більше ніж один, починаються перші плутанини. Це нормально. Особливо якщо назви здаються схожими і всюди є «goal», «risks» і «files». Тому тут корисно один раз дуже чітко розкласти ролі артефактів. Після цього працювати стає помітно легше.
Кожен документ відповідає на своє запитання. І якщо ви змушуєте один артефакт відповідати за все одразу, він перетворюється на кашу з красивим заголовком.
| Артефакт | На яке запитання відповідає | Що в ньому головне |
|---|---|---|
| Issue Intake Note | Що це взагалі за задача? | Проблема, вплив, вимоги, assumptions, open questions |
| Investigation Note | Де ця задача живе в коді? | Файли, функції, тести, точки зміни, evidence |
| Implementation Plan | Що саме робимо і в якому порядку? | Scope, non-goals, affected files, ordered steps, risks |
| Verification strategy | Чим доведемо, що рішення спрацювало? | Команди, тести, ручні перевірки, критерії зупинки |
Дуже спокусливо робити так: спочатку написати хороший intake, потім хороший investigation, а потім у план просто вставити все це копіпастою й додати заголовок Plan. Не робіть так. Інакше людині, яка читатиме документ перед реалізацією, доведеться заново викопувати з довгого тексту те, що їй потрібно просто зараз. План має бути коротшим, сухішим і практичнішим. Він не пояснює всю історію задачі — він допомагає безпечно пройти її наступну фазу.
Хороший критерій простий: якщо відкрити тільки план, за ним має бути ясно, що змінювати, де змінювати, що не чіпати, чим перевіряти і коли зупинятися. Якщо для цього потрібно гортати три сторінки історичного контексту, значить, план недотиснутий.
8. Скрізний приклад Commerce OS: approved plan
Давайте зберемо все разом в одному компактному прикладі, щоб у вас лишився не абстрактний набір термінів, а цілком відчутний образ готового документа. Візьмемо наш Commerce OS і задачу про порожню корзину в checkout. Intake уже зроблено, investigation уже знайшло потрібні сервіси, тести й unknowns. Тепер із цього народжується затверджений людиною план.
Спочатку корисно попросити Claude зібрати чернетку, а не фінальне рішення:
На основі intake та investigation підготуй чернетку плану.
Не змінюй код.
Потрібно повернути лише:
goal, scope, non-goals, affected files, ordered steps,
task risk list, verification strategy, stop conditions.
Не вигадуй того, чого немає в evidence.
Після цього ви правите чернетку очима інженера, а не людини, якій уже дуже хочеться натиснути Enter і побачити diff. У результаті план може набути приблизно такого вигляду:
## Мета
Не давати POST /api/orders з порожнім items[] падати в 500;
повернути узгоджену validation error на HTTP-рівні.
## Область змін
Валідація empty cart у checkout, error mapping і пов’язані API tests.
## Не-цілі
Не змінюємо UI корзини, happy-path checkout і unrelated pricing logic.
## Затронутые файлы
OrderService.java, OrderController.java,
GlobalExceptionHandler.java, OrderControllerWebTest.java.
## Упорядковані кроки
1. Додати reproducing check для POST /api/orders з порожнім items[].
2. Закрити empty-cart validation поруч із calculateTotal(), не змінюючи unrelated pricing behavior.
3. Повторно використати поточний error mapping або мінімально розширити його,
щоб повернути 400 замість 500.
4. Прогнати targeted tests і відтворюваний запит;
підтвердити, що валідний checkout unchanged.
Потім до нього додаються список ризиків і стратегія перевірки — і ось тут план стає по-справжньому approved, а не просто «звучить розумно».
## Список ризиків задачі
- medium: можна зачепити shared callers calculateTotal()
- medium: фронтенд може залежати від поточного error format
- high: якщо для фікса потрібен загальний redesign error schema,
задача виходить за scope
## Стратегія перевірки
- targeted web/API test на empty cart
- ручний POST /api/orders з порожнім items[]
- підтвердження, що валідний checkout з непорожніми товарами
не змінив поведінку
## Умови зупинки
- потрібен загальний redesign error schema
- неясні shared callers calculateTotal()
- diff іде в unrelated checkout/pricing модулі
Якщо хочете додати ще один запобіжник, можна прогнати цей план через reviewer-agent із вашого Workflow Kit — не для того, щоб він «дозволив» зміни, а щоб він знайшов діри в доказовій базі або занадто широкі кроки.
Перевір чернетку плану як reviewer.
Дивись лише на повноту і межі:
чи немає зайвого scope, чи не пропущено ризики,
чи прив’язані кроки до verification.
Код не змінюй.
У цей момент впевнене «здається, ми зрозуміли задачу» перетворюється на спокійне «ми знаємо, що саме робимо, чим ризикуємо і як зрозуміємо, що зробили правильно». Це документ, який можна показати іншому інженеру, обговорити, поправити, розрізати на reviewable slices і лише потім віддавати в реалізацію.
Окремий випадок — коли план приходить із хмарного планувальника, який ми згадували в попередній темі цього рівня (умовно /ultraplan). Формат результату зазвичай одразу містить усі три артефакти — план реалізації, список ризиків, стратегію перевірки — і часто нотатки самоперевірки. Читати й затверджувати такий план потрібно за тією ж схемою, що й план, зібраний локально: перевірити межі задачі, non-goals, затронуті файли, послідовність кроків, ризики й команди для перевірки. Хмарний планувальник не замінює ваше схвалення — він прискорює чорнове опрацювання й розширює контекст дослідження.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ