Написання якісних специфікацій
Ви рідко пишете специфікацію з чистого аркуша. Ви описуєте зміну простими словами, /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. Якщо в вимозі три застереження «і також», це насправді три вимоги. Розділіть їх.Спостережна. Хтось поза кодом повинен мати змогу визначити, чи виконується вона. «Система SHALL показувати банер помилки, коли завантаження перевищує 10 МБ» — спостережно. «Система SHALL коректно обробляти великі завантаження» — ні.
Відповідна сила. OpenSpec використовує ключові слова RFC 2119, і вони означають різне:
Ключове слово Значення MUST/SHALLЖорстка вимога. Без компромісів. SHOULDСильна рекомендація з можливістю обґрунтованого винятку. MAYСправді необов'язково. За замовчуванням використовуйте
MUST/SHALL. ЗастосовуйтеSHOULDлише тоді, коли ви справді маєте на увазі «якщо немає вагомих причин інакше».
Тест для вимоги: чи міг би тестувальник, який ніколи не бачив коду, визначити, чи вона виконана? Якщо ні — її потрібно уточнити.
Що робить сценарій якісним
Сценарії — це місце, де вимога доводить свою цінність. Кожен із них — це конкретний GIVEN / WHEN / THEN, який може стати автоматизованим тестом.
- Він перевіряє свою вимогу. Сценарій, який просто перефразує вимогу іншими словами, нічого не перевіряє. Зробіть його конкретною ситуацією з конкретним результатом.
- Покривайте важливі випадки, а не лише успішний шлях. Коректний вхід — це легко. Порожній ввід, прострочений токен, друге натискання, те, що йде не так, — саме там живуть баги, і саме там сценарій найцінніший.
- Назвіть випадок у заголовку. «Scenario: Rejects an expired token» одразу показує рецензенту, що покрито; «Scenario: Test 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, який відновлює закомічений файл; обрані сховища отримують рекомендації щодо відновлення в межах 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 хвилин.»
Чернетка, уточнення, повторення. Кілька раундів цього дають специфікацію, якій можна довіряти, — і саме в цьому сенс.
Швидкий чек-лист
Куди йти далі
- Відгук на зміну — двоххвилинна перевірка, яка ловить те, що прослизнуло.
- Концепції — глибша модель за специфікаціями, змінами та дельтами.
- Приклади та рецепти — реальні зміни від початку до кінця.