1. «Сделай лучше» — не цель
Task spec держится на блоке Goal. Нет цели — остальное висит в воздухе: Current behavior становится набором наблюдений, Scope — списком мест, Constraints — запретами без ответа «ради чего». Проблема «сделай лучше» не в краткости, а в отсутствии проверяемого результата: кто получит улучшение, что изменится, где проявится, как понять, что готово — неясно. Один слышит «добавить поле заметки», другой — «переделать экран возвратов», Claude — «отрефакторить три компонента».
Сравните слабые и сильные формулировки:
| Слабая формулировка | Почему она слабая | Сильная формулировка |
|---|---|---|
| Улучшить refund-request | Неясно, что считать улучшением | Разрешить оператору добавлять заметку при создании refund-request |
| Сделать удобнее возвраты | Нет наблюдаемого результата | Показывать заметку оператора в карточке возврата для финансового аудита |
| Доработать форму | Непонятно, кто пользователь и что меняется | Оператор может ввести необязательный комментарий до 1000 символов и сохранить его вместе с возвратом |
Сильные формулировки не длиннее — они делают результат наблюдаемым: глазами, тестом, API-ответом, поведением интерфейса. «Сделать лучше» так не проверить — только покивать на diff в 47 файлов. Даже у tiny spec цель проверяема: не «пофиксить текст», а «исправить подпись Refnd на Refund в заголовке карточки возврата; остальное не меняется».
2. Из чего собирается хороший goal
Хороший goal собирается из четырёх элементов: кто получает изменение (оператор, менеджер, администратор, пользователь API, иногда сам разработчик); что становится возможным или иным; где виден результат (форма, карточка, API-ответ, событие, документация); что не должно случайно сломаться (ещё не non-goals, но уже стабилизатор).
Удобная формула:
Хороший goal = кто получает изменение + какое поведение меняется +
где это проявляется + что не должно случайно измениться
На примере F-03 из Commerce OS:
| Компонент цели | Вопрос | Пример для F-03 |
|---|---|---|
| Пользователь изменения | Кто это почувствует? | Оператор поддержки и финансовый ревьюер |
| Изменение поведения | Что становится возможным? | Добавлять и видеть заметку к возврату |
| Точка проявления | Где видно результат? | В форме, в деталях возврата, в событии |
| Стабилизатор | Что не должно сломаться? | Порог ручного/авто-аппрува остаётся прежним |
Цель описывает поведение, а не решение. «Создать колонку notes в refunds, обновить RefundRequestDto, изменить RefundService и RefundCreatedEvent» — это реализация. Цель читают ревьюер, аналитик, тимлид и вы сами через три дня; понятна только знающему архитектуру — значит, описывает внутренности, а не результат.
3. Целевой результат зависит от типа задачи
Тут спотыкаются и опытные. Вид цели зависит от типа задачи: у фичи один результат, у багфикса другой, у рефакторинга третий. Один шаблон на всех — формулировка начнёт врать:
| Тип задачи | Что считается хорошей целью | Пример формулировки |
|---|---|---|
| Новая функциональность | Новое наблюдаемое поведение | Оператор может добавить заметку к запросу на возврат |
| Исправление бага | Исчезновение дефекта + подтверждение корректного поведения | Пагинация заказов больше не возвращает дубли на второй странице |
| Рефакторинг | Сохранение внешнего поведения при улучшении структуры | Упростить логику валидации возврата без изменения публичного поведения |
| Тесты | Появление проверяемого защитного сценария | Добавить regression test для порога ручного подтверждения возврата |
| Документация | Точное и запускаемое описание поведения | Обновить описание refund.created event так, чтобы оно совпадало с текущим 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 draft для Commerce OS:
# TASK_SPEC.md
## Цель
Разрешить оператору добавлять необязательное поле `notes` при создании
refund-request в административном интерфейсе. Заметка должна сохраняться
вместе с записью возврата, отображаться в деталях возврата и попадать в
payload события `refund.created`, чтобы финансовый ревьюер видел контекст
решения при последующем аудите. Текущая логика порогов авто- и ручного
подтверждения возврата не меняется.
По ней легко спросить: «Сделано — что я увижу?» Ответ конкретный: поле в форме, заметку в деталях возврата, её же в событии — и не увижу внезапно изменённую логику подтверждения.
Так task spec перестаёт быть просьбой «сделай что-нибудь полезное» и становится инженерным договором о результате. Чем точнее цель, тем меньше у Claude пространства импровизировать.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ