Перейти к содержимому

Выбрать язык

Текущий язык: Русский

Как писать хорошие спецификации

Обычно спецификацию не пишут с чистого листа. Вы описываете изменение обычными словами, /opsx:propose составляет черновик требований и сценариев, а затем вы доводите его до хорошего состояния. На этой странице — о последнем шаге: как выглядит «хорошая» спецификация и как направить ИИ к её созданию.

Это дополнение к разделу Проверка изменения: проверка помогает выявить слабые места черновика, а написание — понять, из чего складывается сильный вариант.

Спецификация описывает поведение, а не код

Заголовок раздела «Спецификация описывает поведение, а не код»

Спецификация описывает, что делает система, в терминах, которые можно проверить, а не то, как она устроена. Она состоит из требований (описаний поведения) и сценариев (конкретных примеров, которые их подтверждают).

### 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. Если в требовании есть три части, соединённые словами «а также», вероятно, это три требования. Разделите их.

  • Наблюдаемость. Человек, не знакомый с кодом, должен иметь возможность проверить выполнение требования. «Система ДОЛЖНА показывать сообщение об ошибке, если размер загружаемого файла превышает 10 МБ» — проверяемое требование. «Система ДОЛЖНА корректно обрабатывать большие файлы» — нет.

  • Подходящая степень обязательности. В OpenSpec используются ключевые слова RFC 2119, каждое со своим значением:

    Keyword Значение
    MUST / SHALL Строгое требование, не допускающее отклонений.
    SHOULD Настоятельная рекомендация, допускающая обоснованные исключения.
    MAY Действительно необязательное условие.

    По умолчанию используйте MUST/SHALL. Выбирайте SHOULD, только если действительно подразумеваете «если нет веской причины поступить иначе».

Проверьте требование вопросом: сможет ли тестировщик, не видевший код, определить, выполнено ли оно? Если нет, формулировку нужно уточнить.

Сценарии делают требования полезными. Каждый из них — конкретный пример в формате GIVEN / WHEN / THEN, который можно превратить в автоматизированный тест.

  • Сценарий проверяет своё требование. Если он лишь повторяет требование другими словами, он ничего не тестирует. Опишите конкретную ситуацию с конкретным результатом.
  • Покрывайте важные случаи, а не только успешный сценарий. Проверить корректный вход просто. Ошибки чаще скрываются в пустых данных, просроченном токене, повторном нажатии и прочих сбоях — именно для них сценарии особенно важны.
  • Укажите проверяемый случай в заголовке. «Сценарий: отклонение просроченного токена» сразу объясняет проверяющему, что покрыто; «Сценарий: тест 2» — нет.

Полезная привычка: прежде чем согласовать спецификацию, спросите себя: какая ошибка расстроила бы меня больше всего? Убедитесь, что сценарий явно охватывает этот случай.

Изменения описывают правки спецификаций с помощью трёх типов разделов. Выбор правильного типа помогает поддерживать архивные спецификации в актуальном состоянии:

  • ## ADDED Requirements — новое поведение, которого раньше не было.
  • ## MODIFIED Requirements — существующее поведение, которое меняется. Приведите новую версию целиком; краткое описание изменений поможет при проверке.
  • ## REMOVED Requirements — удаляемое поведение с пояснением причины.

При архивации раздел ADDED добавляется в основную спецификацию, MODIFIED заменяет прежнюю версию, а REMOVED удаляет требование. Если удалить последнее требование возможности, эта возможность выводится из эксплуатации: вместо пустой спецификации архивация удаляет openspec/specs/<capability>/spec.md. Поскольку это единственный этап архивации, удаляющий файл, его нужно явно разрешить: добавьте retire_capabilities: true в .openspec.yaml изменения рядом с обязательным полем schema:. Без этой настройки архивация прервётся и сообщит причину. Вывод из эксплуатации удаляет файл целиком, поэтому он также запрещён, если спецификация содержит что-либо помимо заголовка, ## Purpose и блоков требований (например, раздел ## Notes или комментарий под требованием). При прерывании указываются эти строки; перенесите их в ## Purpose или требование либо удалите спецификацию вручную. Если спецификация находится в рабочей копии вызывающего пользователя, вывод архивации также содержит команду git checkout для восстановления зафиксированного файла; для выбранных хранилищ вместо этого выдаются инструкции по восстановлению в соответствующей рабочей копии. Если пометить реальное изменение как ADDED, появятся два конкурирующих требования; если описать новое поведение как MODIFIED, заменять будет нечего. Если сомневаетесь, откройте текущую спецификацию и проверьте, есть ли в ней это требование.

Важно знать и ещё об одном разделе. Если дельта создаёт новую возможность, начните её с ## Purpose — одного-двух предложений о назначении этой возможности. Архивация использует этот текст как Purpose основной спецификации; если его пропустить, будет добавлена заглушка TBD, которую придётся заполнить вручную. У существующей спецификации уже есть Purpose, поэтому Purpose из дельты игнорируется. Чтобы изменить его, отредактируйте непосредственно openspec/specs/<capability-path>/spec.md. Здесь <capability-path> — путь каталога относительно specs/, например user-auth в проекте с плоской структурой или identity/user-auth в проекте, организованном по областям.

Самая частая ошибка при подготовке документации — не неудачная формулировка требования, а попытка объединить три изменения в одном.

У хорошего изменения одна цель, которую можно изложить одним предложением. «Добавить переключатель тёмной темы». «Ограничить частоту запросов к эндпоинту входа». «Перевести сеансы с cookie на другой механизм». Если для описания изменения нужно много раз говорить «а ещё», это признак, что его следует разделить.

Признаки слишком большого изменения:

  • В предложении перечислены несвязанные функции.
  • Проверка займёт целый день, поэтому никто не захочет за неё браться.
  • Два человека не смогут работать параллельно без конфликтов.
  • Половину задач можно выпустить независимо.

Небольшие изменения проще проверять, реализовывать за один сосредоточенный сеанс и осмысливать через полгода, когда останется только архив. Несколько изменений можно вести параллельно — см. Редактирование и доработка и Рабочие процессы.

Встречается и обратное: для исправления опечатки в одной строке не нужны три требования и проектный документ. Соразмеряйте формальности с масштабом задачи.

Поскольку первый черновик готовит /opsx:propose, его качество зависит от качества исходных данных. Не обязательно писать требования вручную — важно правильно направить ИИ:

  • Опишите цель и границы. «Добавь переключатель тёмной темы, который при первой загрузке учитывает настройки ОС; существующий API темы не меняй». То, что выходит за рамки работы, так же важно, как и то, что в них входит.
  • Назовите важные для вас случаи. «Добавь сценарий для пользователя, который уже выбрал тему вручную». ИИ учтёт то, на что вы укажете.
  • Затем отредактируйте черновик. Это обычный Markdown. Уточните расплывчатое SHALL, удалите сценарий, который ничего не проверяет, добавьте пропущенный случай — или попросите ИИ: «Требование о времени ожидания расплывчатое, укажи 30 минут».

Подготовьте черновик, уточните его и повторите. Несколько таких итераций дадут надёжную спецификацию — в этом и состоит цель.

  • Каждое требование описывает одно проверяемое поведение с ключевым словом SHALL/MUST.
  • Требования не содержат деталей реализации.
  • Для каждого требования есть хотя бы один сценарий, действительно его проверяющий.
  • Для важных граничных ситуаций и ошибок есть сценарии, а не только для успешного выполнения.
  • Типы дельт ADDED / MODIFIED / REMOVED правильно применены с учётом текущей спецификации.
  • У всего изменения одна цель, которую можно выразить одним предложением.

HagiCode

HagiCode — агентная среда разработки со структурированными процессами, параллельным выполнением несколькими агентами и интерфейсами Hero Dungeon.

Превращайте идеи в полезное ПО с более умным, быстрым и увлекательным агентным рабочим процессом.

Главный экран HagiCode в светлой теме
  • SmartСтруктурированные процессы превращают намерение в исполнимый путь от идеи до готового изменения.
  • EfficientМультиагентные процессы параллельно продвигают исследование, реализацию и проверку.
  • FunHero Dungeon делает длительную совместную разработку наглядной и увлекательной.
Перейти на HagiCode