Написание качественных спецификаций
Вы редко пишете спецификацию с чистого листа. Вы описываете изменение простым языком, команда /opsx:propose составляет черновик требований и сценариев, а потом вы доводите их до ума. Эта страница посвящена последнему этапу — что такое «хорошая» спецификация и как подтолкнуть ИИ к её созданию.
Это дополнение к странице Проверка изменений: при проверке вы ищете слабые места в черновике, а при написании вы знаете, из чего состоит сильная спецификация.
Спецификация описывает поведение, а не код
Спецификация описывает, что делает ваша система, в терминах, которые может проверить любой человек — а не то, как она построена. Она состоит из требований (утверждений о поведении) и сценариев (конкретных примеров, подтверждающих их выполнение).
markdown
### Requirement: Session Timeout
The system SHALL expire a session after 30 minutes of inactivity.
#### Scenario: Idle timeout
- GIVEN an authenticated session
- WHEN 30 minutes pass with no activity
- THEN the session is invalidated and the user must re-authenticateОписание как это работает — очередь, библиотека, схема таблицы — оставляйте в файле design.md или в коде. Когда поведение и реализация смешиваются в одном требовании, оно перестаёт быть проверяемым и начинает устаревать сразу после изменения кода.
Из чего состоит хорошее требование
Хорошее требование описывает одно поведение, изложенное настолько просто, что вы можете передать его другому человеку для проверки.
Одно утверждение, один
SHALL/MUST. Если в требовании есть три пункта с «а также», то на самом деле это три отдельных требования. Разделите их.Проверяемое на практике. Человек, не работающий с кодом, должен иметь возможность определить, выполняется ли оно. Требование «Система SHALL показывать баннер с ошибкой, если размер загрузки превышает 10 МБ» является проверяемым. А «Система SHALL корректно обрабатывать большие загрузки» — нет.
Подходящая степень обязательности. OpenSpec использует ключевые слова из RFC 2119, и они имеют разное значение:
Ключевое слово Значение MUST/SHALLЖёсткое обязательство. Не подлежит обсуждению. SHOULDСильная рекомендация, с возможностью обоснованного исключения. MAYДействительно необязательно. По умолчанию используйте
MUST/SHALL. ПрименяйтеSHOULDтолько если вы действительно имеете в виду «если нет веской причины не делать этого».
Проверка требования: сможет ли тестировщик, который никогда не видел код, определить, выполнено ли оно? Если нет — требование нужно доработать.
Из чего состоит хороший сценарий
Сценарии — это то, ради чего требования и существуют. Каждый из них представляет собой конкретную последовательность GIVEN / WHEN / THEN, которую можно превратить в автоматизированный тест.
- Он проверяет соответствующее требование. Сценарий, который просто перефразирует требование другими словами, ничего не проверяет. Сделайте его описанием конкретной ситуации с конкретным результатом.
- Охватывайте важные случаи, а не только счастливый путь. Успешный вход в систему прост. Пустой ввод, истёкший токен, повторный клик, ситуация, в которой что-то пошло не так — именно в таких местах живут ошибки, и именно такие сценарии имеют наибольшую ценность.
- Назовите случай в заголовке. «Scenario: Отклоняет истёкший токен» сразу говорит рецензенту, что проверяется; а «Scenario: Тест 2» — нет.
Полезная привычка: перед утверждением спрашивайте себя: какой случай я буду расстроен увидеть сломанным? — и убедитесь, что для него есть соответствующий сценарий.
Выбирайте правильный тип дельты
Изменение описывает правки в спецификациях с помощью трёх типов разделов. Использование правильного типа позволяет сохранять достоверность архивированных спецификаций:
## ADDED Requirements— совершенно новое поведение, которого раньше не существовало.## MODIFIED Requirements— поведение, которое уже существовало и изменяется. Укажите полную новую версию; краткое примечание о том, что изменилось, поможет рецензенту.## REMOVED Requirements— поведение, которое удаляется, с указанием причины.
При архивации раздел ADDED добавляется в конец основной спецификации, MODIFIED заменяет старую версию, а REMOVED удаляется. Если вы пометите реальное изменение как ADDED, у вас получится два противоречащих друг другу требования; если опишете новое поведение как MODIFIED, не будет ничего, что можно было бы заменить. Если сомневаетесь, откройте текущую спецификацию и проверьте, есть ли в ней уже это требование.
Подбирайте правильный размер изменения
Самая распространённая ошибка при написании — не плохо сформулированное требование, а изменение, которое пытается быть сразу тремя разными изменениями.
Хорошее изменение имеет одну цель, которую можно сформулировать в одном предложении. «Добавить переключатель тёмной темы». «Ограничить частоту запросов к конечной точке входа в систему». «Перенести сессии из куки». Если для описания изменения нужно много раз использовать «а также», это сигнал, что его нужно разделить.
Признаки того, что изменение слишком большое:
- Область применения предложения выглядит как список несвязанных функций.
- На его проверку уйдёт весь день, поэтому никто не будет этим заниматься.
- Два человека не могут работать над ним одновременно, не мешая друг другу.
- Половина задач может быть выпущена отдельно.
Мелкие изменения легче проверять, легче реализовать за один сеанс сосредоточенной работы, и легче анализировать полгода спустя, когда от проекта останется только архив. Вы всегда можете запустить несколько изменений параллельно — см. Редактирование и итерации и Рабочие процессы.
Бывает и обратное: исправление опечатки в одной строке не требует трёх требований и документа проектирования. Соотносите формальность процесса с важностью задачи.
Как подтолкнуть ИИ к созданию качественного черновика
Поскольку первый черновик составляет команда /opsx:propose, качество полученного результата напрямую соответствует качеству того, что вы ей передаёте. Вам не нужно писать требования вручную — достаточно правильно задать направление для ИИ:
- Сформулируйте цель и границы. «Добавить переключатель тёмной темы, который при первой загрузке использует настройки операционной системы — не трогать существующий API тем.» Часть, описывающая, что не входит в область изменений, важна не меньше, чем часть с описанием целевой функциональности.
- Назовите случаи, которые вас интересуют. «Убедитесь, что есть сценарий для пользователя, который уже вручную выбрал тему.» ИИ покрывает только то, на что вы ему укажете.
- Затем отредактируйте результат. Это обычный Markdown. Уточните расплывчатое
SHALL, удалите сценарий, который ничего не проверяет, добавьте случай, который ИИ пропустил — или попросите ИИ сделать это: «требование о таймауте слишком расплывчатое, зафиксируйте его значение в 30 минут.»
Составьте черновик, доработайте его, повторите. Несколько таких циклов дадут вам спецификацию, которой вы сможете доверять — это и есть главная цель.
Краткий чек-лист
- [ ] Каждое требование описывает одно проверяемое поведение и содержит
SHALL/MUST. - [ ] В требованиях не встроены детали реализации.
- [ ] Для каждого требования есть хотя бы один сценарий, который его реально проверяет.
- [ ] Для важных пограничных случаев и сценариев ошибок есть соответствующие сценарии, а не только сценарии счастливого пути.
- [ ] В дельтах правильно используются теги ADDED / MODIFIED / REMOVED относительно текущей спецификации.
- [ ] Всё изменение имеет одну цель, которую можно сформулировать в одном предложении.
Дальнейшие шаги
- Проверка изменений — быстрая проверка за две минуты, которая ловит то, что было пропущено.
- Концепции — более подробная модель, лежащая в основе спецификаций, изменений и дельт.
- Примеры и рецепты — реальные изменения от начала до конца.