1. «Зроби краще» — не ціль
Task spec тримається на блоці Goal. Немає цілі — решта висить у повітрі: Current behavior стає набором спостережень, Scope — списком місць, Constraints — заборонами без відповіді «навіщо». Проблема «зроби краще» не в лаконічності, а у відсутності перевірюваного результату: хто отримає покращення, що зміниться, де це проявиться, як зрозуміти, що готово, — незрозуміло. Один чує «додати поле замітки», інший — «переробити екран повернень», Claude — «відрефакторити три компоненти».
Порівняйте слабкі й сильні формулювання:
| Слабке формулювання | Чому воно слабке | Сильне формулювання |
|---|---|---|
| Покращити refund-request | Незрозуміло, що вважати покращенням | Дозволити оператору додавати замітку під час створення refund-request |
| Зробити зручнішими повернення | Немає спостережуваного результату | Показувати замітку оператора в картці повернення для фінансового аудиту |
| Доопрацювати форму | Незрозуміло, хто користувач і що змінюється | Оператор може ввести необовʼязковий коментар до 1000 символів і зберегти його разом із поверненням |
Сильні формулювання не довші — вони роблять результат спостережуваним: очима, тестом, API-відповіддю, поведінкою інтерфейсу. «Зробити краще» так не перевірити — лише кивнути на diff у 47 файлах. Навіть у tiny spec ціль перевірювана: не «пофіксити текст», а «виправити підпис Refnd на Refund у заголовку картки повернення; решта не змінюється».
2. З чого складається добра ціль
Добра ціль складається з чотирьох елементів: хто отримує зміну (оператор, менеджер, адміністратор, користувач API, інколи сам розробник); що стає можливим або іншим; де видно результат (форма, картка, API-відповідь, подія, документація); що не має випадково зламатися (ще не non-goals, але вже стабілізатор).
Зручна формула:
Добра ціль = хто отримує зміну + яке поведінка змінюється +
де це проявляється + що не має випадково змінитися
На прикладі F-03 із Commerce OS:
| Компонент цілі | Питання | Приклад для F-03 |
|---|---|---|
| Користувач зміни | Хто це відчує? | Оператор підтримки і фінансовий ревʼюер |
| Зміна поведінки | Що стає можливим? | Додавати і бачити замітку до повернення |
| Точка прояву | Де видно результат? | У формі, в деталях повернення, у події |
| Стабілізатор | Що не має зламатися? | Поріг ручного/авто-апруву залишається незмінним |
Ціль описує поведінку, а не рішення. «Створити колонку notes у refunds, оновити RefundRequestDto, змінити RefundService і RefundCreatedEvent» — це реалізація. Ціль читають ревʼюер, аналітик, тимлід і ви самі через три дні; зрозуміло лише тому, хто знає архітектуру, — отже, описує внутрішню будову, а не результат.
3. Цільовий результат залежить від типу задачі
Тут спотикаються й досвідчені. Вид цілі залежить від типу задачі: у фічі один результат, у багфікса інший, у рефакторингу третій. Один шаблон на всіх — формулювання почне брехати:
| Тип задачі | Що вважається доброю ціллю | Приклад формулювання |
|---|---|---|
| Нова функціональність | Нова спостережувана поведінка | Оператор може додати замітку до запиту на повернення |
| Виправлення помилки | Зникнення дефекту + підтвердження коректної поведінки | Пагінація замовлень більше не повертає дублікати на другій сторінці |
| Рефакторинг | Збереження зовнішньої поведінки під час покращення структури | Спрощити логіку валідації повернення без зміни публічної поведінки |
| Тести | Поява перевірюваного захисного сценарію | Додати regression test для порогу ручного підтвердження повернення |
| Документація | Точний і запускаємий опис поведінки | Оновити опис події refund.created так, щоб він збігався з поточним payload |
| Дослідження | Висновки з доказами, а не код | Визначити, чи вже є підтримка заміток у схемі БД і яких consumers зачіпає зміна |
| Крок міграції | Підтверджена сумісність і перевірюваний перехід | Сервіс збирається на цільовій версії, а smoke-check повернення проходить без регресії |
Для bugfix погана ціль — «полагодити замовлення»; добра — «після переходу на другу сторінку немає дублікатів, сортування лишається тим самим». Для investigation код узагалі не обіцяють: ціль — відповідь із доказами. А «додати», «полагодити», «відрефакторити» й «оновити README» в одній цілі — це не героїзм, а кілька задач, яким тісно в одному Goal.
4. Розбираємо задачу F-03 із Commerce OS
Повернімося до наскрізної задачі — issue F-03: Add notes field to refund-request. Опишете ціль так само прямолінійно — Claude побачить напрям, а не результат.
Найслабша версія:
## Мета
Додати поле notes у refund-request.
Тут лише ідея: хто користується полем, де воно зʼявиться, чи зберігається, чого не можна зламати — невідомо.
Трохи краще:
## Мета
Дозволити оператору додавати поле notes під час створення refund-request.
Роль і дія зʼявилися, але спостережуваності мало: поле є у формі, не збереглося в базі — фраза формально виконана. Або збереглося, але не видно ревʼюеру.
Доводимо до робочого стану:
## Мета
Дозволити оператору додавати необовʼязкове поле `notes` під час створення
refund-request в адміністративному інтерфейсі. Замітка має зберігатися
разом із записом повернення, відображатися в деталях повернення і потрапляти в
payload події `refund.created`, щоб фінансовий ревʼюер бачив контекст
рішення під час подальшого аудиту. Поточна логіка порогів авто- і ручного
підтвердження повернення не змінюється.
Тепер ціль — інженерний орієнтир: видно, для кого зміна (оператор і фінансовий ревʼюер); поле зберігається, відображається і бере участь у події; зрозуміла бізнес-причина — аудит. Остання фраза про пороги — «що не має змінитися»: захист від розповзання. Вона знімає ризик, що Claude вирішить: «Раз ми вже у refund flow, давайте заодно підчистимо бізнес-логіку».
5. Goal vs рішення, scope і побажання
На початку в блок Goal потрапляє все: проблема, список файлів, технічний план, обмеження. Навчіться відрізняти одне від іншого — інакше в тексті змішаються і оператор, і RefundService, і міграції:
| Формулювання | Що це насправді | Чому це не просто goal |
|---|---|---|
| Оператор може додати замітку до повернення | Ціль | Це описує спостережувану поведінку |
| Зміни зачіпають admin UI, refund detail і event payload | Scope | Це не результат, а межі поверхні |
| Не змінювати approval thresholds і PSP integration | Обмеження / межа змін | Це правило виконання, а не сама ціль |
| Додати колонку notes у refunds, оновити DTO і сервіс | Рішення / реалізація | Це вже спосіб досягнення результату |
| Зробити повернення зручнішими | Побажання | Тут немає перевірюваної поведінки |
Правило: goal відповідає на «що стане true після задачі?» — не «як дійдемо» і не «які файли зачепимо». Уявляєте код, а не поведінку — отже, вже перейшли до реалізації. Перевірка: прочитайте Goal тому, хто не відкривав репозиторій. Зрозумів, що зміниться для користувача або системи, — ціль непогана. Питає «де, в якому сервісі, що вважати успіхом?» — формулювання розмите.
6. Заповнюємо блок Goal у TASK_SPEC.md
Зберімо все в робочий шаблон: він змушує проговорити ціль простою мовою і не дає потонути в реалізації.
Міні-шаблон:
## Мета
[Хто] має отримати можливість [що зробити / який результат побачити].
Зміна має проявлятися в [де саме це видно].
Успіх задачі означає, що [2–3 спостережувані ознаки результату].
При цьому [що не має ненавмисно змінитися].
І ось він у чернетці TASK_SPEC.md для Commerce OS:
# TASK_SPEC.md
## Мета
Дозволити оператору додавати необовʼязкове поле `notes` під час створення
refund-request в адміністративному інтерфейсі. Замітка має зберігатися
разом із записом повернення, відображатися в деталях повернення і потрапляти в
payload події `refund.created`, щоб фінансовий ревʼюер бачив контекст
рішення під час подальшого аудиту. Поточна логіка порогів авто- і ручного
підтвердження повернення не змінюється.
За нею легко запитати: «Зроблено — що я побачу?» Відповідь конкретна: поле у формі, замітку в деталях повернення, її ж у події — і не побачу раптово змінену логіку підтвердження.
Так task spec перестає бути проханням «зроби щось корисне» і стає інженерною угодою про результат. Чим точніша ціль, тим менше в Claude простору для імпровізації.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ