Skip to content

良い仕様書の書き方

仕様書を白紙の状態から書くことはほとんどありません。平易な言語で変更内容を説明すると、/opsx:propose が要件とシナリオの草案を作成し、その後、それを改善していきます。このページはその最後の部分、つまり「良い仕様書」とは何か、そしてAIをその方向に導く方法について説明します。

これは変更内容のレビューの補足資料です。レビューは草案の弱点を見つけることであり、執筆は優れた仕様書の構成要素を知ることです。

仕様書は動作であり、コードではない

仕様書は、誰でも検証できる言葉でシステムが「何を」するかを説明するものであり、「どのように」実装されるかは説明しません。仕様書は要件(動作の記述)とシナリオ(それを証明する具体的な例)で構成されます。

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 やコードに記載します。動作と実装が1つの要件に混在すると、その要件はテスト不可能になり、コードが変更された瞬間に陳腐化し始めます。

優れた要件とは

優れた要件とは、誰かに渡してテストさせられるほど明確に記述された、単一の動作のことです。

  • 1つの記述に、SHALL/MUST は1つだけ。 要件に「~かつ~」という3つの節がある場合、それは実質的に3つの要件です。分割してください。

  • 観測可能であること。 コードに詳しくない人でも、その要件が満たされているかどうかを判断できるべきです。「アップロードが10MBを超えた場合、システムはエラーバナーを表示する」は観測可能ですが、「システムは大きなアップロードを適切に処理する」はそうではありません。

  • 適切な強度。 OpenSpecではRFC 2119のキーワードを使用しており、それぞれ異なる意味を持ちます:

    KeywordMeaning
    MUST / SHALLA hard requirement. Non-negotiable.
    SHOULDA strong recommendation, with room for a justified exception.
    MAYGenuinely optional.

    デフォルトでは MUST/SHALL を使用してください。SHOULD は「明確な理由がない限り~すべき」という意味で使う場合にのみ使用してください。

要件のテスト基準:コードを見たことのないテスターが、その要件が満たされたかどうかを判断できるか? もしできない場合は、要件を明確にする必要があります。

優れたシナリオとは

シナリオは、要件が実際に役立つための核心です。それぞれのシナリオは、自動テストに変換できる具体的な GIVEN / WHEN / THEN です。

  • 要件を実際に検証すること。 単に要件を別の言葉で言い換えただけのシナリオは、何もテストしません。特定の状況と特定の結果を持つ具体的なシナリオにしてください。
  • 重要なケースを網羅すること。ハッピーパスだけではありません。 正常なログインは簡単です。空の入力、期限切れのトークン、2回目のクリック、失敗するような状況——それらこそがバグが潜む場所であり、シナリオが最も価値を発揮する場所です。
  • タイトルにケース名を記載すること。 「シナリオ:期限切れトークンを拒否する」は、レビュアーが一目で何がカバーされているかを把握できますが、「シナリオ:テスト2」ではそうではありません。

便利な習慣:承認する前に、「もし壊れていたら最も困るケースは何か?」 と自問し、そのケースをカバーするシナリオが存在することを確認してください。

適切な差分タイプを選択する

変更内容は、3種類のセクションタイプを使用して仕様書への編集内容を記述します。適切なタイプを使用することで、アーカイブされた仕様書の整合性が保たれます:

  • ## ADDED Requirements — 以前は存在しなかった全く新しい動作。
  • ## MODIFIED Requirements — 既に存在していた動作が変更される場合。新しいバージョンの全文を含めてください。変更内容の簡単なメモは、レビュアーの助けになります。
  • ## REMOVED Requirements — 廃止される動作。理由を1行記載してください。

アーカイブ時、ADDEDはメインの仕様書に追加され、MODIFIEDは古いバージョンを置き換え、REMOVEDは削除されます。実際の変更をADDEDとしてマークすると、競合する2つの要件ができてしまいますし、新しい動作をMODIFIEDとして記述すると、置き換える対象がなくなってしまいます。判断に迷った場合は、現在の仕様書を開いて、その要件が既に存在するかどうかを確認してください。

変更内容の適切な規模

仕様書作成で最もよくある間違いは、文言の悪い要件ではなく、3つの変更を1つにまとめようとしていることです。

優れた変更内容は、1つの文章で説明できる意図を持っています。 「ダークモードのトグルを追加する」「ログインエンドポイントにレート制限を設ける」「セッションをクッキーから移行する」。変更内容の説明に「~かつ~」が多く必要になる場合は、分割するべきサインです。

変更内容が大きすぎる兆候:

  • 提案の範囲が無関係な機能のリストのように読める。
  • レビューに半日かかるため、誰もレビューしたがらない。
  • 2人が同時に作業すると競合が発生する。
  • タスクの半分は単独でリリースできる。

小さな変更の方がレビューしやすく、集中して1回の作業で実装しやすく、6ヶ月後にアーカイブだけが残った状態でも理解しやすいです。複数の変更を並行して実行することもできます——編集と反復ワークフローを参照してください。

その逆も起こります:1行のタイプ修正に3つの要件と設計書は必要ありません。変更の重要性に応じて手順の規模を調整してください。

AIを良い草案に導く方法

/opsx:propose が最初の草案を作成するため、得られる結果の品質は、入力する内容の品質に左右されます。手動で要件を書く必要はありません——AIを適切に誘導することが重要です:

  • 意図と範囲を明確に述べること。 「初回読み込み時にOS設定に従うダークモードのトグルを追加する——既存のテーマAPIには触れないでください。」 対象外の部分は、対象の部分と同じくらい重要です。
  • 重視するケースを明記すること。 「手動でテーマを選択したユーザー向けのシナリオを必ず含めてください。」 AIはあなたが指摘した内容をカバーします。
  • その後、編集する。 これはプレーンなMarkdownです。曖昧な SHALL を明確にし、何もテストしないシナリオを削除し、AIが見落としたケースを追加する——またはAIに依頼することもできます:「タイムアウトの要件が曖昧なので、30分に固定してください。」

草案を作成し、洗練させ、繰り返す。このプロセスを数回繰り返すことで、信頼できる仕様書ができあがります。それが本来の目的です。

クイックチェックリスト

  • [ ] 各要件は、SHALL/MUST を持つ1つの観測可能な動作である。
  • [ ] 実装の詳細が要件に含まれていない。
  • [ ] 各要件には、実際にそれを検証する少なくとも1つのシナリオがある。
  • [ ] 重要なエッジケースとエラーケースにシナリオがあり、ハッピーパスだけではない。
  • [ ] 差分(Deltas)が現在の仕様書に対してADDED / MODIFIED / REMOVEDを正しく使用している。
  • [ ] 変更内容全体が、1つの文章で説明できる単一の意図を持っている。

次のステップ