🐧 要するにどういう話か
ChatGPTが出た当初、プログラムのコードを出力してくれるので、「素人でもコードが書ける!プログラマはもう不要だ!」という論調だった。実際、Excel VBAをさらっと書いてもらって普段の仕事に活用している人がいて素直に感心したが、一方で、素人の下手くそなAI生成コード(たいていはPython)の面倒を見る機会が増えただけでなく、一部の未熟なITエンジニアのダニング=クルーガー効果を促進した面もあったようで、「最新のAIを使いこなして作ったオレの素晴らしいプログラムを見よ!」とドヤ顔でゴミを押し付けられてうんざりしたことがある。「バイブコーディング」という言葉もその傾向に拍車をかけた。
そのとき思ったのは、「ダメな人はAIを使ってもダメ」ということであった。たとえるなら、私の部下にアインシュタインを割り当てられても、私のような凡人ではまったく活用できないのと同じことである。やはり生成AIの利用にも方法論が必要なのではないか。そのようにモヤモヤしていたところに出てきたのが、同様のクソみたいな状況が世界的に生じているという報道と、バイブコーディングへの反論しての仕様駆動開発である。
1. はじめに
本書は、仕様駆動開発(Spec-Driven Development, SDD)について解説する。
SDDとは、仕様が信頼できる情報源であり、コードはその生成物である、という開発手法である。
2. 仕様駆動開発とはなにか
仕様駆動開発(SDD)とは、書かれた仕様がプロジェクトの一次成果物であり、コードはその仕様から人間やAIエージェントによって生成される再生成可能な出力物である、というソフトウェア開発の手法である。
従来の開発では、要件書が一度書かれ、開発チームに投げ渡された後に放置されることが多い。コードが事実上の正解となり、要件書はスプリントのうちに陳腐化する。SDDはこの流れを反転させる。仕様がリポジトリの中で生き続け、プロジェクトとともに進化し、コードはそこからいつでも再生成できる。
SDDには4つの特性がある。
- バージョン管理される。 仕様はコードと並んでバージョン管理される。
- 信頼できる情報源である。 要件が変化したら、まず仕様を更新し、コードをそれに合わせて修正または再生成する。
- 構造化された形式を持つ。 仕様はユーザーストーリー、受け入れ基準、制約条件といった固定されたスキーマに従い、自由記述ではない。
- 実行可能である。 AIコーディングエージェントが仕様を読み、計画を立て、タスクに分解し、コードを書き、受け入れ基準に照らして結果を検証できる。
仕様は、人間の意図と機械の実行をつなぐ橋渡しである。システムが何をすべきか、なぜそうすべきか、どのような制約のもとでそうすべきかを、人間にも言語モデルにも読み取れる形で記述する。
3. 登場した背景
SDDへの移行は、2024〜2025年に主流となったLLMベースのエージェントによる「バイブコーディング」の失敗モードに対する直接的な応答である。バイブコーディング——自然言語でAIエージェントに指示を出し、出てきたものをそのまま受け入れる——はプロトタイプには速いが、スケールすると崩壊する。
SDDの必要性が明らかになった失敗モードは3つある。
- 意図のずれ(ドリフト) 「ログイン機能を追加して」という指示は極端に曖昧だ。モデルは妥当なデフォルトを選ぶが、それがチームの意図と一致することはまずない。
- 文脈の劣化 コードベースがエージェントの有効なコンテキストウィンドウを超えると、古い意思決定を忘れてしまい、黙ってそれに矛盾する実装を生成する。
- 出力の検証不能 明示的な受け入れ基準がなければ、エージェントのコードが正しいかどうかを判断する手段がない。コードレビューが果てしなく続く。
AI支援開発は技術的負債も加速させる。仕様が生成プロセスの支えになければ、チームは次の問題に直面する。
- 文脈のドリフト 一箇所のバグ修正が、別の箇所での機能破壊を招く。
- 断片化 新しく生成された機能が既存のアーキテクチャ規約と整合せず、コードベースの一貫性が侵食される。
- 運用コスト 本来は明確な仕様で防げたエラーを解決するために、膨大なトークンを費やすプロンプトの往復が発生する。
より根深い問題は、翻訳ロスである。ステークホルダーのニーズから要件、設計、実装、検証へと進む過程で、各段の引き継ぎで意味が失われる。意図を保全する共通の成果物がなければ、すべての引き継ぎが解釈のステップになる。AIはそれらのステップを加速できるが、そもそも解消されていない曖昧さを修正することはできない。
SDDはこれらすべてに対処する。業界の議論で繰り返し登場する表現がある。「仕様がプロンプトである」。仕様は、人間の意図と機械の実行の間に欠落していたレイヤーを補う。
4. 考え方
SDDは、開発者の役割をコーダーからアーキテクト兼レビューアーへと変える。開発者は意図を定義し、制約を設け、出力をレビューする。AIエージェントが生成と実行の重労働を担当する。
このアプローチを支える原則がいくつかある。
- 生き続ける文書 仕様は一度書いて終わりではない。コードとともに進化し続ける。振る舞いが変わったら、まず仕様を更新し、コードをそれに合わせて再生成する。仕様の更新がコードのリファクタリングと同様に自然になり、しかもコードに一切触れない。
- 人間のチェックポイント 各フェーズの境界で人間がレビューする。仕様が計画の前にレビューされ、計画がタスクの前にレビューされ、タスクが実装の前にレビューされる。これがSDDを予測可能にする。
- 明確さの前倒し 曖昧さは、コードを書く前に解消する。初期に意図を明確化するコストは、下流で何倍にもなって返ってくる。
- 実行可能な意図 仕様はAIツールによって本質的に実行されることを前提に設計される。単なるドキュメントではなく、コード生成と検証を駆動する入力である。
- コードは拘束される成果物、仕様は軽やかな成果物 実装を書くと、そこから切り離すのが大変になる。仕様は、数回のキー入力ですべて変更できる。SDDはこの非対称性を活用する。
- 過剰設計の罠 仕様の作成コストは、実装で誤解を修正するコストよりも常に低くあるべきである。それが逆転した——例えば、1か月後に削除されるかもしれない機能のJSONキーの名前について3週間議論している——時点で、磨き上げを止め、作り始めるべき合図である。網羅的で最終的な仕様より、軽量で進化していく仕方を好むべきだ。
5. ワークフロー
主要なSDDフレームワークはすべて、同じ基本ループに収斂する。名前が違っても、構造は本質的に同じである。
flowchart LR
A[憲法] --> B[仕様定義]
B --> C[明確化]
C --> D[計画]
D --> E[タスク分解]
E --> F[実装]
各フェーズで何が起きるかを示す。
- 憲法(Constitution) プロジェクト全体の不変の原則を定義する。技術スタック、コーディング規約、セキュリティルール、テストの慣行など。この文書は、その後のすべての作業に対する不変のコンテキストとなる。すべての仕様と計画が尊重すべき持続的なルールである。
- 仕様定義(Specify) 「何を」「なぜ」を捕捉する。ユーザーストーリー、受け入れ基準、機能的要件と非機能的要件を書き、範囲外を明示する。このフェーズは意図に集中し、実装には触れない。
- 明確化(Clarify) 曖昧さを残した箇所——エッジケース、空の状態、エラー処理、不明点——を体系的に洗い出す。答えを仕様に記録してから先に進む。目的は下流のリワークを最小限にすることである。
- 計画(Plan) 意図を技術的なアプローチに変換する。アーキテクチャの意思決定、データモデルとAPI設計、ライブラリとフレームワークの選定を行う。計画は憲法に基づき、すべての決定が確立されたガードレール内に収まることを保証する。
- タスク分解(Tasks) 計画を原子的で、独立して出荷可能なタスクに分解する。各タスクは単一の目的、定義された入力と出力、受け入れチェックを持つ。良いタスクリストは、ジュニアエンジニアが実行できるチェックリストのようである——まさにそれが狙いである。エージェントとは、実のところ速いジュニアエンジニアに過ぎない。
- 実装(Implement) エージェントがタスクを実行し、コードとテストを生成する。各タスクの終わりに、受け入れ基準に対する検証ステップがある。基準を満たさなければ、エージェントは反復する——仕様によって制約され、自由奔放に走るのではない。
役割分担は明快である。人間は意図を定義し、境界でレビューする。AIは生成と実行を担当する。
6. 仕様の書き方
良い仕様には、次の要素が含まれる。
- ユーザーストーリー —「[役割]として、[機能]を[結果]のために欲しい」
- 受け入れ基準 — 検証可能で曖昧でない記述(できればEARS記法、後述)
- 機能的要件 — システムが何をすべきか
- 非機能的要件 — パフォーマンス予算、アクセシビリティ目標、セキュリティ制約、オブザーバビリティ
- 範囲外の記述 — システムが何をしなかったのか、エージェントの行動範囲を絞るために
- エッジケース — 空の状態、エラー処理、境界条件
EARS記法
EARS(Easy Approach to Requirements Syntax)は、Alistair Mavin氏とロールス・ロイスの同僚らが考案した記法である。LLMが行動できるほど曖昧さを排した要件を生成する。各パターンは、スコープ、トリガー、応答のいずれについても曖昧さがなく、単一の検証可能な主張に収束する。
5つのパターンは次の通り。
- 常時(Ubiquitous) — 常に真
- 「システムはすべての認証試行をログに記録しなければならない」
- イベント駆動(Event-driven) — WHEN … THE system SHALL …
- 「WHEN ユーザーがログインフォームを送信したとき、THE システムは認証プロバイダに対して資格情報を検証しなければならない」
- 状態駆動(State-driven) — WHILE … THE system SHALL …
- 「WHILE 同期が進行中、THE システムは閉じられないプログレスインジケータを表示しなければならない」
- 望ましくない挙動(Unwanted behavior) — IF … THEN THE system SHALL …
- 「IF 資格情報の検証が60秒間に3回失敗したら、THEN THE システムはアカウントを15分間ロックしなければならない」
- 任意機能(Optional features) — WHERE … THE system SHALL …
- 「WHERE 多要素認証が有効化されている場合、THE システムはパスワード検証の後にTOTPコードを要求しなければならない」
エージェントはEARSの要件を読み、コードを生成し、それを検証するテストを書く——すべてを推測なしに行える。
憲法
憲法は、プロジェクト全体の不変の原則を記述するプロジェクトレベルの文書である。実質的に、プロジェクト自体に関する常時型EARS文のリストである。
- 「システムはTypeScriptのstrictモードを使用しなければならない」
- 「システムはテストカバレッジを下げるプルリクエストを拒否しなければならない」
- 「システムはメンテナンスされていないパッケージへのランタイム依存を避けるなければならない」
憲法は、いかなる機能仕様よりも先に書かれ、すべてのエージェントの行動に対する不変の背景となる。
スコープと軽量さ
仕様は振る舞いと制約を記述し、実装詳細は記述しない。実装を変えても外部から見える振る舞いが変わらないものは、仕様の対象ではない。
仕様は短く保つ——1〜3ページが目安である。それを超えたら分割する。良い仕様は開発を加速する。より良いコードを速く書く助けになっていなければ、誤解を減らしていなければ、それは必要以上に詳細である。
7. SDDと関連手法の比較
SDDとバイブコーディング
バイブコーディングとSDDは敵ではなく、補完関係である。
- バイブコーディング — 使い捨てスクリプト、プロトタイプ、デモに向く。速く、敷居が低く、創造的だが、幻覚、文脈の喪失、もろいコードを招きやすい。
- SDD — 本番コード、数か月単位のプロジェクト、チーム開発に向く。信頼性があり意図と整合しているが、事前の時間が必要で、小さなタスクには過剰に感じられる場合がある。
熟達したエンジニアは、プロトタイプにはバイブコーディングを、出荷するものすべてにはSDDを用いる。
SDDとTDD・BDD
三者は同じ系統を持つが、正典とする成果物が異なる。
- TDD — 正典は失敗する単体テストである。順序:テスト → コード → リファクタリング。焦点:ユニットレベルのコードの正確性。
- BDD — 正典はGherkinシナリオ(Given/When/Then)である。順序:シナリオ → ステップ定義 → コード。焦点:ユーザー視点での振る舞い。
- SDD — 正典は受け入れ基準を持つバージョン管理された仕様である。順序:仕様 → 計画 → タスク → コード(多くの場合エージェントが担当)。焦点:コーディング前の要件の明確さと追跡可能性。
SDDはBDDの一部を包含する。EARS型の受け入れ基準は、実のところGherkinのより厳密な兄弟である。良いSDDワークフローもまた単体テストと統合テストを生成するが、それらは仕様から生成されるのであり、その逆ではない。
SDDはウォーターフォールではない
SDDとは、誰も読まない網羅的な要件書を書くことではない。膨大な計画で未来を予測するのでもない。仕様は生き続ける文書であり、プロジェクトとともに進化する。各フェーズは促進器であり、ゲートではない——いつでもどの成果物にも戻れる。
仕様のスペクトラム
すべてのチームが同じレベルの仕様の権威を必要とするわけではない。スペクトラムは次のように広がる。
- Spec-first(仕様先行) — コードを生成する前に仕様を書くが、その後必ずしも維持しない。継続的なメンテナンスなしに初期の明確さを提供する。SDDへの入り口である。
- Spec-anchored(仕様に錨を打つ) — 仕様がソフトウェアとともに進化し続ける。要件が変わったら仕様を更新する。自動テストがドキュメントと実装の橋渡しとなる。多くのチームにとって実用的で拡張可能なアプローチである。
- Spec-as-source(仕方をソースとする) — 仕様の変更が自動的にコードの変更をトリガーする。人間が直接コードをリファクタリングしない。これはAIコード生成パイプラインに対する高度な信頼を必要とする。
- ハイブリッド — 仕方を積み重ね可能なバージョン管理された成果物として扱う、外部システムを信頼できる情報源とする、高複雑度プロジェクトでは重い自動化を避ける、など。文脈がどのモデルへの厳格な忠誠よりも重要である。
8. ツール
8.1 GitHub Spec Kit
GitHub Spec Kitは、Microsoftが作成し、GitHubが2025年9月にオープンソース化したツールキットである。SDDの実践を次の2つの要素によって実現する。
- Specify CLI — プロジェクトをSDD向けにブートストラップするコマンドラインツール。選択したコーディングエージェント向けの公式テンプレートをダウンロードし、SDDの足場を構築する。
- テンプレートとヘルパースクリプト — 仕様がどのような形になるか、技術計画が何を包含するか、作業をどのようにタスクに分解するかを定義する。
Spec Kitは設計上、モデル非依存である。GitHub Copilot、Claude Code、Cursor、Codex CLI、Gemini CLIなど、多くのエージェントと連携する。テンプレートは、ほとんどすべての最新のエージェントに対して修正なしで互換性を保つように設計されている。
中心的な操作は、3つの順序的なスラッシュコマンドである。
- /specify —「何を」「なぜ」を概説する。技術的な意思決定を明示的に除外する。動機と機能的要件に集中する。
- /plan —「どうやるか」を概説する。フレームワーク、ライブラリ、データベース、インフラを選定する。憲法に基づいており、すべての決定が確立されたガイドラインに収まる。
- /tasks — 仕様と計画を、エージェントが実装できる管理可能な段階的なチャンクに分解する。
思想は明快である。構造化された段階的ワークフローによって、定義されたステップの連鎖を通して意図を実装に変換する。各ステップは、次のステップが始まる前にレビュー可能な成果物を生成する。
8.2 OpenSpec
OpenSpecは軽量で、フレームワーク非依存のSDDツールである。5つの核心コンセプトから構成される。
- 仕様は真実である。 仕様は、システムが今どのように振る舞うかを記述する。
openspec/specs/ にドメインごと(例: auth/、payments/、ui/)に整理されて格納される。
- 変更は1つの作業単位である。 振る舞いの追加、変更、削除をしたいとき、変更(change)を作る。
openspec/changes/ 内のフォルダに、提案、設計、タスクリスト、デルタ仕方が収まる。
- デルタ仕様は全体ではなく変更点を記述する。 仕様全体を書き直すのではなく、小さなデルタ——ADDED、MODIFIED、REMOVEDの要件——を書く。これにより、OpenSpecはグリーンフィールドだけでなく、既存システムの編集にも適する。
- 成果物は互いに積み上がる。 変更内で、自然な順序は:提案 → 仕様 → 設計 → タスク → 実装である。各成果物が次の成果物にコンテキストを提供する。
- アーカイブで変更を真実に還す。 作業が完了したら、変更をアーカイブする。そのデルタ仕方が主要な仕方にマージされ、変更フォルダは
changes/archive/ に移動する。
OpenSpecは4つの原則に導かれる。
- 流動的で、硬直的ではない — フェーズのゲートはない;意味のあるところで作業する。
- 反復的で、ウォーターフォールではない — 作る中で学び、進む中で洗練する。
- 容易で、複雑ではない — 軽量なセットアップ、最小限の儀式。
- ブラウンフィールドファースト — 既存のコードベースで動作し、グリーンフィールドに限定しない。
指針となる言葉は「促進器であり、ゲートではない」(enablers, not gates)である。成果物の順序は、次に何が可能になるかを示すものであり、何をしなければならないかを示すものではない。自分の作業にとって理にかなった順番で、成果物を作成・修正できる。依存関係は、AIが必要なコンテキストを持つように存在するものであり、自分を枠にはめるものではない。
flowchart LR
specs["specs/ 信頼できる情報源 現在のシステムの振る舞い"]
changes["changes/ 変更ごとに1フォルダ 提案 · 設計 · タスク · デルタ仕様"]
changes -->|"アーカイブ時にマージ"| specs
日々のワークフローは次の通り。
/opsx:explore — まずAIとともにアイデアを練る(リスクのない思考相手)
/opsx:propose <名前> — AIが提案、仕様、設計、タスクを作成する。読み、調整する
/opsx:apply — AIが実装し、タスクにチェックを入れる
/opsx:archive — デルタ仕方が主要な仕方にマージされ、変更がアーカイブされる
9. OpenSpecとGitHub Spec Kitの思想の違い
両ツールともSDDを実装するが、根本的な思想が意味のある形で異なる。
- ワークフローの性格
- GitHub Spec Kitは順序的な段階的ワークフローを強制する:
/specify → /plan → /tasks → 実装。各コマンドは順番に使う必要があり、各コマンドは次のコマンドが始まる前にレビュー可能な成果物を生成する。
- OpenSpecは流動的で反復的である。成果物はいつでも作成・修正でき、順番は強制されない。順序は、次に何が可能になるかを示すだけであり、何をするべきかを示すものではない。
- 既存コードベースへの姿勢
- GitHub Spec Kitは新機能向けに設計されている。各機能に新しい仕様・計画・タスクのセットが与えられる。
- OpenSpecはブラウンフィールドファーストである。デルタ仕様によって、現在の仕様に比べて何が変わるか(ADDED、MODIFIED、REMOVED)だけ記述できるため、大規模な既存コードベースで働くのが自然である。
- 仕様の管理単位
- GitHub Spec Kitは機能ディレクトリごとに作業を整理し、仕様・計画・タスクを同じ場所に置く。修正後の「その機能全体がどうなっているべきか」を完全に書く(全量更新)。
- OpenSpecは信頼できる情報源(
specs/)と変更の提案(changes/)を分離する。変更はデルタを主要な仕方にマージしてアーカイブされ、2つの関心を清潔に保つ。「何を追加し、何が変わり、何を削除するか」だけを書く(差分更新)。
- 構造と柔軟性のトレードオフ
- GitHub Spec Kitは、構造化されたテンプレートとスクリプトを提供し、箱出しから一貫性を担保する。足場は与えられた出発点であり、修正は可能である。
- OpenSpecは構造を最小限に保ち、カスタマイズをチームに委ねる。トレードオフはガードレールの少なさだが、柔軟性は高い。
- チェックポイントの位置づけ
- GitHub Spec Kitは、フェーズ境界での人間のレビューをワークフローの明示的な内蔵要素とする。
- OpenSpecは「促進器であり、ゲートではない」という立場をとる。誰にも前進を強制しない。いつ進めるかの判断は人間に委ねられる。
どちらが絶対的に優れているわけではない。正しい選択は、チームの規模、既存コードベースで作業しているか、ツールチェーンによって変わる。
10. ベストプラクティスと落とし穴
落とし穴
- 過剰仕様化 実装詳細(「Mapを使ってObjectにしない」など)を仕様化しない。振る舞いと制約を仕様化し、実装は計画フェーズに委ねる。
- 過少仕様化「ちゃんと動くように」は要件にならない。EARSを使わない限り、要件とみなされない。
- 憲法の省略 プロジェクトレベルのルールがなければ、すべての仕方が同じ決定を繰り返すことになる。
- 仕様を不変として扱う 仕様は進化し続ける。振る舞いが変わったら、まず仕様を更新し、次にコードを更新する。
- 人間のチェックポイントの欠如 エージェントをプロンプトからマージされたプルリクエストまで、人間のレビューなしに走らせるのは、衣装を変えたバイブコーディングに過ぎない。
- 仕様がリポジトリの外にある 仕様はリポジトリ内で、コードと並んでバージョン管理されなければならない。そうでなければ腐る。
ベストプラクティス
- 1機能 = 1仕様
- 最初の仕様より先に憲法を書く
- 受け入れ基準は、常にEARSで書く
- フェーズ境界でレビューする——仕様からコードへ飛ばさない
- 仕様は短く保つ。1〜3ページ。大きくなったら分割する
- 範囲外を明記する。「範囲外」は「範囲内」と同等に重要である
- コミットとプルリクエストで仕様を参照する
- 明確化のフェーズを回す。エージェントが推測する前に、曖昧さを表面化させる
- 仕様を永続ドキュメントとして扱う。それはそこから生成されたコードよりも長く生き続ける。未来のエージェントも人間も、それを正規の参照として読む
11. まとめ
仕様駆動開発は、AI時代における意図の保全のための手法である。コードを書く前に仕様を書くことで、AIエージェントは機能し、整合した出力を生むために必要な制約を得る。同時に、何を意図したか、なぜそう했かの持続的でレビュー可能な記録が手元に残る。
SDDはバイブコーディングを代替しない。両者は補完関係である。自然言語で探索し、出荷するものを仕様で確定する。
ツールは変わるだろう。しかし——意図を明示的に定義し、レビュー可能にし、それを执行の原動力とする——この思想こそが、残るものである。
📚 参考文献
|