Когда спека работает — и когда ломается
Предыдущий урок дал инструменты: requirements.md с нотацией EARS, design.md с архитектурными решениями, tasks.md с трассировкой. Теперь посмотрим, как эти инструменты работают на практике — и где ломаются.
Разберём четыре кейса: один удачный и три типичных провала.
flowchart TD
A[Спека] --> B[Рабочая: EARS + AC + edge-кейсы]
A --> C[Пустая: нет деталей]
A --> D[Противоречивая: конфликты]
A --> E[Псевдокод: реализация вместо поведения]
style B fill:#d4edda,stroke:#28a745
style C fill:#f8d7da,stroke:#dc3545
style D fill:#f8d7da,stroke:#dc3545
style E fill:#f8d7da,stroke:#dc3545Случай 1 (правильно): поиск по каталогу
Команда добавляет поиск в интернет-магазин. Вот фрагмент requirements.md:
## FR-03 Поиск по каталогу
### User story
Как покупатель, я хочу вводить запрос в строку поиска и получать
релевантные товары, чтобы быстро находить нужное.
### Requirements
1. WHEN пользователь вводит запрос длиной >= 2 символов
THE SYSTEM SHALL вернуть до 20 результатов, отсортированных по релевантности,
за время не более 300 мс (p95).
2. WHEN запрос содержит менее 2 символов
THE SYSTEM SHALL не отправлять запрос к бэкенду и показать подсказку.
3. IF поиск не вернул результатов
THEN THE SYSTEM SHALL показать экран «Ничего не найдено».
4. WHILE выполняется запрос
THE SYSTEM SHALL показывать skeleton-индикатор вместо списка товаров.
### Acceptance criteria
- [ ] Запрос < 2 символов -> нет вызова API, есть подсказка пользователю
- [ ] Запрос >= 2 символов -> список до 20 товаров, p95 <= 300 мс
- [ ] Нет результатов -> экран «Ничего не найдено»
- [ ] Skeleton виден во время ожиданияАгент получает ровно то, что нужно: четыре различимых поведения, каждое с конкретным триггером. Ни одного вопроса «что делать при пустой строке?» — ответ в требовании 2. Каждый acceptance criterion станет тестом: агент пишет не «что-то похожее на поиск», а реализацию четырёх конкретных сценариев.
Случай 2 (неправильно): пустая спека
Та же задача, написанная «на ходу»:
## Поиск
Нужно добавить поиск по товарам. Быстро и удобно.Агент начинает угадывать. Минимальная длина запроса? Неизвестно. Порядок сортировки? Неизвестно. Что показывать при пустом результате? Неизвестно. Первый PR вызовет десять вопросов от ревьюера — и все они должны были войти в спеку до старта.
Пустая спека — это не спека. Это промпт в формате Markdown.
Случай 3 (неправильно): противоречивая спека
Спека написана подробно, но внутри живёт тихое противоречие:
### Requirements
1. WHEN пользователь вводит запрос >= 2 символов
THE SYSTEM SHALL искать по полю name товара.
2. WHEN пользователь вводит запрос >= 3 символов
THE SYSTEM SHALL искать по полям name и description.Что делать агенту при запросе ровно из двух символов? Требование 1 говорит «ищи по name», требование 2 молчит. Агент разрешит конфликт — но не обязательно так, как вы ожидали.
Противоречия чаще всего появляются, когда спеку писали в несколько итераций без единой проверки на консистентность. Простое правило: перед стартом реализации прочитать спеку за один раз, как связный текст, а не как список пунктов.
Случай 4 (неправильно): спека-псевдокод
Самый коварный анти-паттерн. Выглядит как тщательная работа — на деле убивает разделение «что / как»:
### Requirements
1. WHEN пользователь вводит запрос
THE SYSTEM SHALL вызвать searchProducts(query: string),
сделать GET /api/v1/products/search?q={query},
десериализовать ответ в Product[] и записать в useState-хук.Это не требование — черновик реализации. Если завтра вы перейдёте с REST на GraphQL или с useState на Zustand, спеку придётся переписывать. Она устарела раньше, чем написан первый тест.
Рабочая спека описывает поведение. Как его реализовать — задача design.md и агента.
Что отличает рабочую спеку от нерабочей
| Признак | Рабочая спека | Нерабочая спека |
|---|---|---|
| Язык | WHEN / IF / WHILE + поведение | «нужно», «быстро», «удобно» |
| Полнота | Все edge-кейсы явны | Агент угадывает |
| Консистентность | Нет пересечений | Тихие конфликты |
| Уровень описания | ЧТО (поведение) | КАК (реализация) |
| Acceptance criteria | Конкретны и проверяемы | Расплывчаты или отсутствуют |
Проблема не в объёме. Пустая спека плохо, но спека-псевдокод тоже плохо. Хорошая спека содержит ровно столько информации, сколько нужно для однозначного понимания поведения, — и не больше.
В следующем уроке разберём анти-паттерны на уровне процесса: spec rot, over-specification и когда SDD вообще не стоит применять.