仕様駆動開発ワークフロー:要件からコードまで

「意図から検証済みコードまでの5つのフェーズ」

目次

仕様駆動開発(SDD)が機能するのは、仕様が単にキックオフ後に棚上げされる文書ではなく、ワークフローそのものである場合です。目的は、膨大な製品要件定義書を作成することではありません。

目的は、人間やAIエージェントが本番環境のコードを変更する前に、曖昧さを段階的に解消するためのレビュー可能な成果物の連鎖を、次々と進めていくことです。

SDDの概念的な定義がわからない場合は、定義やTDD・BDDとの比較、仕様をソースオブトゥルース(唯一の事実源)とすることの根拠については、仕様駆動開発とは? から始めましょう。本記事は、アプリケーションアーキテクチャ ドキュメント群の中で、運用に関するガイド 역할을担っています。ここでは、5つのフェーズを解説し、各フェーズの成果物に何が含まれるべきかを示し、AIエージェントがどこに位置づけられるかを説明し、今日すぐにリポジトリにコピーできる再利用可能なテンプレートを提供します。

仕様駆動開発のワークフロー – 要件、設計、タスク、実装、検証

SDDは文書ではなく、ワークフローである

仕様駆動開発において最も一般的な失敗パターンは、仕様を事務的な書類として扱うことです。チームが長い要件定義書を作成し、Wikiに保存し、その後は記憶やチャットスレッドに頼ってコーディングするというケースです。仕様は存在しますが、何も導きません。これは「文書の虚飾」であり、偽の安心感を生むため、仕様がない状態よりも悪影響を及ぼします。

機能するSDDワークフローは、各フェーズの開始前にレビューされる成果物の連鎖を生成します。要件は製品の曖昧さを削減します。設計は技術的な曖昧さを削減します。タスクは実行の曖昧さを削減します。実装は、既知の目標に対してコードを生成します。検証は、その連鎖が機能したことを証明します。あるフェーズで間違いが発見された場合、成果物を修正し、その時点からやり直します – mainブランチに3000行もの乖離(ドリフト)が反映されてからではありません。

flowchart LR A[仕様定義] --> B[計画] B --> C[タスク分解] C --> D[実装] D --> E[検証] E -->|ドリフト発見| A E -->|リリース| F[完了]

このワークフローはツール非依存(ツールニュートラル)です。GitでのMarkdownファイル、GitHub Spec Kit、より軽量で変更志向のCLIである OpenSpec、Cursorのプラン、Superpowers のような強制スキルパッケージ、あるいはテキストエディタと規律あるレビュアーの組み合わせなど、様々なツールで実行できます。重要なのは、ツールのブランドではなく、順序とレビューゲートです。

フェーズ 1 – 要件を仕様化する

仕様定義フェーズは、解決する問題が何か、そして「完了」の状態がどのようなものかを答えます。意図的に、どのように構築するか(How)は避けます。要件仕様で「Redisのソートド使用セットを使用する」と記述した時点で、仕様定義を終え、誤った文書で設計を始めてしまったことになります。実装の詳細は要件から外し、計画(Plan)に記述してください。

問題文とユーザー

まず、問題を平易な言葉で記述した1段落から始めます。影響を受けるユーザーの役割名と、問題が深刻な状況(コンテキスト)を特定します。良好な問題文は、プランニング会議に参加していなかったレビュアーが、提案された解決策がその痛み(ペイン)に実際にアプローチしているかどうかを判断できるようにします。

APIレートリミット機能の例:

フリーティアのAPI消費者は無制限のリクエストを送信でき、コストの急増や有料テナントへのノイズネイバー効果(隣人効果)を引き起こします。プラットフォームオペレータは、手動介入なしにキーごとの強制可能な上限が必要です。

目標、非目標、受入基準

目標は、提供される成果(アウトカム)を記述します。非目標は、誘惑的な隣接業務だが、明示的に行わないものを記述します。これらは一緒に、エージェントの創造性を制限します。これは、AIツールが「親切に」スコープを拡大させないために不可欠です。

セクション 良い例 弱い例
目標 キーごとの上限を超えたリクエストをHTTP 429で拒否する APIを高速化する
非目標 テナントごとの請求ダッシュボード すべてのAPI性能を改善する
受入基準 未認証のリクエストはレートチェック実行前に401を受け取る エンドポイントは安全である

受入基準は、各々が少なくとも1つのテストにマッピングされるほど正確でなければなりません。「エンドポイントは安全である」は受入基準ではありません。「未認証のリクエストはHTTP 401を受け取る」です。具体的な基準を書けなければ、その要件はまだ実装するには曖昧すぎます。

未解決の問題

まだ決まっていないすべての決定事項をリストアップしてください。明確でない質問があることは、失敗の兆候ではありません。それは、仕様定義フェーズがその役割を果たしているということです。設計計画を書く前にこれらを解決しなければ、実装時の手直しで曖昧さの代価を払うことになります。

最小構成の要件テンプレート:

## 問題
[1段落: 誰が痛んでいるか、なぜか、痛みをトリガーするのは何か。]

## ユーザー
- [プライマリユーザーロール]
- [セカンダリーユーザーロール]

## 目標
1. [測定可能な成果]
2. [測定可能な成果]

## 非目標
- [明示的にスコープ外]
- [明示的にスコープ外]

## 受入基準
- [ ] [検証可能な動作]
- [ ] [検証可能な動作]

## 未解決の問題
- [ ] [計画をブロックする質問]

フェーズ 2 – 設計を計画する

計画フェーズは、意図を技術的な決定に変換します。ここでRedisソートドセットが属する場所です。モジュール境界、スキーマ変更、APIコントラクト、マイグレーション手順、セキュリティ制約、テスト戦略も含まれます。計画は、要件仕様に加えて、プロジェクトの既存の制約 – スタックの選択、意思決定記録AGENTS.md やプロジェクト憲章のようなファイルに保存された慣習 – から導出されます。

アーキテクチャと影響を受けるモジュール

変更されるモジュール、サービス、またはパッケージの名称を特定し、統合パターンを要約します。機能がサービス境界を横断する場合、両側のコントラクトを文書化します。コントラクトが暗黙のとき、エージェントはAPIを幻視(ハルシネーション)します。計画でそれらを明示にすることで、でっち上げのエンドポイントや誤ったレスポンス形状を防ぎます。

データモデル、APIコントラクト、マイグレーション

スキーマ変更、新しいテーブルやフィールド、インデックス要件、後方互換性ルールを文書化します。HTTP APIの場合、メソッド、パス、リクエスト形状、レスポンス形状、エラーコードを記載します。イベントの場合、トピック名、ペイロードスキーマ、配信セマンティクスを記載します。データモデルが変更される場合、マイグレーション手順とロールバックに関する注意事項を含めます。

セキュリティ、オブザーバビリティ、テスト戦略

セキュリティ制約は、コードレビュー時の事後検討事項ではなく、計画に属します。認証要件、認可ルール、入力バリデーションの境界、ログに表示してはならないデータを注記します。オブザーバビリティは、本番環境で機能が正常に動作することを確認するために必要なメトリクス、ログ、トレースをカバーすべきです。

テスト戦略は受入基準と結びついています。どの基準に単体テストが必要か、どの基準に統合テストが必要か、どの基準に手動検証が必要かを特定します。GoでのユニットテストPythonでのユニットテスト を使用する場合、追加する予定のパッケージとテストファイル名を特定します。テスト戦略のない計画は、本番環境で発見されるギャップを伴ってリリースされる計画です。

flowchart TB subgraph plan [設計計画の内容] R[要件仕様] C[プロジェクト憲章 / ADR] R --> D[アーキテクチャ決定] C --> D D --> M[データモデルとマイグレーション] D --> A[APIコントラクト] D --> S[セキュリティ制約] D --> T[テスト戦略] end

フェーズ 3 – 実装タスクに分解する

タスクフェーズは、計画を、独立して実装、レビュー、検証できるほど十分に小さいスライスに分解します。これにより、エージェント支援開発がレビュー可能になります。1つの巨大な差分(diff)の代わりに、名前の付いた要件にそれぞれマップされる、焦点の絞られた変更の連鎖が得られます。

タスクのサイズと依存関係

良好なタスクは、限定されたファイル集合に触れ、1回のエージェントセッションで完了し、検証ステップで終わります。タスクは依存関係を明示的に宣言すべきです。マイグレーションタスクは、新しいスキーマを読むコードの前に実行されます。共有ライブラリの変更は、それを使う側(コンシューマ)の前に実行されます。認証ミドルウェアの変更は、新しい動作に依存するエンドポイントの前に実行されます。

flowchart TD T1[タスク 1 -- スキーママイグレーション] --> T2[タスク 2 -- リポジトリレイヤー] T2 --> T3[タスク 3 -- HTTPハンドラー] T2 --> T4[タスク 4 -- メトリクスの計装] T3 --> T5[タスク 5 -- 統合テスト] T4 --> T5

ファイル、検証、レビューチェックポイント

各タスクは、変更されそうなファイル、満たす受入基準、完了を検証する方法をリストアップすべきです。検証は、テストコマンド、curlの例、あるいはコピー&ペースト可能な手順で記述された手動チェックであっても構いません。すべてのタスクは、人間によるレビューチェックポイントで終わります。レビュアーは、次のタスクが始まる前に、差分がタスク説明と一致していることを確認します。

最小構成のタスクエントリ:

### タスク 3 -- レートリミットミドルウェアの追加

**依存関係:** タスク 1 (スキーマ), タスク 2 (リポジトリ)
**ファイル:** middleware/ratelimit.go, middleware/ratelimit_test.go, server.go
**満たす基準:** AC-2 (上限超過時の429), AC-3 (レスポンスの上限ヘッダー)
**検証:** `go test ./middleware/...` がパスすること; 上限超過時のcurlでRetry-After付き429が返ること
**レビューチェックポイント:** ミドルウェアが認証の後、ハンドラーの前で実行されることを確認

生成タスクの爆発(タスクの無意味な増殖)に注意してください。AIエージェントは数秒で50個のタスクを含む計画を生成できます。これらのタスクの多くは、冗長か、効率的にレビューするには細分すぎるものです。中規模な機能のための有用なタスクリストには、50個ではなく、通常5から15項目があります。

フェーズ 4 – 一度に1つのタスクを実装する

実装は意図的に狭い範囲に限定されます。1つのタスクを選び、そのタスクに必要なコンテキストのみをエージェントに与え、検証がパスしたら停止します。タスク間のコンテキストリセットは、バグではなく機能です。これにより、以前の前提が後の作業を汚染するのを防ぎ、差分をレビュー可能な状態に保ちます。

仕様スタックからの制約を適用する

実装するエージェントは、要件仕様、設計計画、現在のタスク説明、プロジェクトレベルの制約を読むべきです。制約は、多くのチームがスキップしがちだが、最もROI(投資利益率)が高いセクションです。制約は、エージェントに「何をしてはいけないか」を伝えます – 関連のないモジュールのリファクタリングをしない、この機能以外でパブリックAPIのシグネチャを変更しない、計画を更新せずに新しい依存関係を導入しない、などです。

現実が異なる場合、計画を更新する

実装によって予想外のことが明らかになります。ライブラリが想定された動作をサポートしない、マイグレーションが予想以上に時間がかかる、受入基準からエッジケースが漏れていた、などです。そのような場合は、続ける前に仕様を更新してください。要件または計画を修正し、迅速なレビューを得て、修正された成果物に対して実装を再開します。仕様に黙って乖離するコードは、ドリフトが恒久的になる方法です。

sequenceDiagram participant H as 人間レビュアー participant A as AIエージェント participant S as 仕様成果物 H->>S: タスク N を承認 A->>S: タスク + 計画 + 制約を読む A->>A: タスク N を実装 A->>A: タスク検証を実行 A->>H: レビュー用の差分を提出 H->>H: タスクに対する差分のレビュー alt ドリフトまたは予想外の状況 H->>S: 仕様/計画を更新 H->>A: 修正後のコンテキストで再実行 else 承認 H->>S: タスク N を完了としてマーク H->>A: タスク N+1 に進む end

フェーズ 5 – 仕様に対して検証する

検証は、SDDがその価値を証明する場所です。検証がなければ、仕様は単なる計画練習になります。検証があれば、仕様は、リリースされたコードに対してチェックできる契約になります。

自動チェック

CI上で、完全なテストスイート、Lint、型チェックを実行します。実用的な出発点が必要な場合は、GitHub Actions チートシート のパターンを使ってパイプラインに組み込みます。自動チェックはリグレッション(機能劣化)を検出します。しかし、正しく構築された間違った機能は検出できません。だからこそ、受入基準のレビューがいまだに重要なのです。

受入基準と手動レビュー

要件仕様から各受入基準を順番に確認してください。各基準を、満足、失敗、または理由を付けて延期、とマークします。手動レビューは、UXの問題、セキュリティの欠陥、テストが欠陥のある仕様に合わせられていたために見逃した誤った動作を検出します。

仕様からコードへの差分

最終的な検証ステップでは、実装を設計計画と比較します。変更されたファイルは、計画が予測したファイルと一致しましたか? コード中のアーキテクチャ決定は、記録された決定と一致しましたか? 差分に予期しないファイルがあることはシグナルです – 計画が不完全だったか、エージェントが寄り道したかのどちらかです。マージの前に、どちらの場合でも注意が必要です。AI開発における仕様、テスト、コードの同期を取る は、この使い捨ての差分レビューを、再利用可能なトレーサビリティテーブルとCIチェックのセットに変換し、ドリフトが誰かが見にいくことを思い出すときだけでなく、すべてのPRで検出されるようにします。

検証レイヤー 検出できるもの
単体テストと統合テスト スコープ内のリグレッションと誤ったロジック
Lintと型チェック スタイルの問題と型エラー
受入基準の確認 仕様に従って構築された誤った動作
仕様からコードへの差分 アーキテクチャのドリフトとスコープクリープ

AIエージェントがワークフローにどう位置づくか

AIエージェントは各フェーズの加速剤であり、レビューの代替ではありません。生産的なパターンは、下書き、レビュー、洗練、そして進める、というものです。エージェントに問題記述から要件仕様の下書きを依頼し、次に目標、非目標、受入基準が正しくなるまで意図を編集します。承認された要件から設計計画の下書きを依頼し、コードが存在する前にアーキテクチャ決定をレビューします。エージェントにタスクリストを生成を依頼し、タスクスライスを1つずつ実装させ、次のタスクが開始される前に各差分を承認します。

flowchart LR subgraph human [人間が所有] H1[意図と優先順位] H2[アーキテクチャ承認] H3[チェックポイントでの差分レビュー] H4[最終受入] end subgraph agent [エージェントが加速] A1[要件の下書き] A2[設計計画の下書き] A3[タスクリストの生成] A4[タスクスライスの実装] A5[テストの下書き] end H1 --> A1 --> H1 A1 --> A2 --> H2 H2 --> A3 --> A4 --> H3 H3 --> A4 A4 --> A5 --> H4

エージェントは、最初の草稿やボイラープレート(定型)テストの生成に特に役立ちます。人間は、誤った目標、不安全なアーキテクチャ、微妙なスコープクリープの検出に特に役立ちます。どちらかの側がスキップされると、ワークフローは失敗します – エージェントが仕様なしで実装する場合、または人間がコードに対して検証することなく仕様を書く場合です。

このワークフロー記事は、意図的にツール非依存(ツールニュートラル)です。ツール固有の実行ガイド – エディタのセットアップ、スラッシュコマンド、エージェント設定 – は、AI開発ツール クラスターの下に属します。プロセスの柱は、ベンダーよりも成果物の方が重要であるため、ここドキュメントプラクティスの下にあります。

仕様駆動開発を殺す一般的な間違い

検証前の巨大な仕様。 プロトタイプやスパイク(探索的実装)の前に書かれた30ページの要件定義書は、SDDではなくウォーターフォールの事務作業です。次のフェーズの曖昧さを解消するために必要な最小限の仕様を書き、早めに仮説を検証してください。すべての機能が完全な5フェーズのループを必要とするわけではありません – 仕様駆動開発 vs バイブコーディング は、より軽量な構造で十分である場合にいつそうなるかを説明します。

曖昧な受入基準。 「高速」、「クリーン」、「ユーザビリティが高い」といった形容詞は受入基準ではありません。測定可能な動作に置き換えてください。テストできないものは、確実に実装できません – 特にAIエージェントと作業する場合です。

非目標の欠如。 非目標がなければ、エージェントはデフォルトでスコープを拡大します。キャッシュレイヤーを追加し、隣接モジュールをリファクタリングし、要求していない依存関係を導入します。非目標とは、事前に「ノー」と言う方法です。

設計フェーズでのテスト計画の欠如。 実装の後にのみ書かれたテストは、構築されたものを確認する傾向があり、意図されたものを確認するわけではありません。最初の本番ファイルが変わる前に、計画はどの受入基準がどのテストタイプにマップされるべきかを特定すべきです。

フェーズ境界でのレビューのスキップ。 仕様は計画の前にレビューされる。計画はタスクの前にレビューされる。タスクは実装の前にレビューされる。各ゲートは安価です。大きなマージ後にドリフトを修正するのは高価です。

生成タスクの爆放を許す。 50項目のAI生成タスクリストをスケジュールではなく、最初の草稿として扱いなさい。冗長な項目をマージし、巨大なものを分割し、要件にマップされないタスクを削除してください。

却下された調査を記録せずに削除する。 フェーズ2のレビューで、ある方向に構築する価値はないと結論づけられた場合、反射的には仕様を削除して次へ進みます。それは推論を消去し、同じアイデアが翌四半期に、人間やエージェントの誰かが再びそれに遭遇したとき、ゼロから調査されることになります。却下を承認された決定と同じ厳密さで記録するのは、比較的低コストです; OpenSpec 却下された提案: 意思決定メモリの慣例 は、再提案する前にエージェントが以前の決定を検索するようにする指示を含む、これを具体的な1つの方法で実行します。

SDDが機能するのは、各フェーズが曖昧さを削減する場合です。文書を作成する場合、それは失敗します。

再利用可能なテンプレート

これらをリポジトリにコピーし、適応させなさい。仕様は機能ブランチと一緒に保存し、プルリクエストでレビューし、エージェントと人間が同じソースを読むようにするためにバージョン管理下に保ちなさい。

要件テンプレート

# 機能 -- [名]

## 問題
## ユーザー
## 目標
## 非目標
## 受入基準
## 未解決の問題

設計テンプレート

# 設計 -- [機能名]

## 概要
## 影響を受けるモジュール
## データモデル変更
## APIコントラクト
## マイグレーション
## セキュリティ
## オブザーバビリティ
## テスト戦略
## リスクと緩和策

タスクリストテンプレート

# タスク -- [機能名]

## タスク 1 -- [タイトル]
依存関係:
ファイル:
満たす基準:
検証:
レビューチェックポイント:

## タスク 2 -- [タイトル]
...

検証チェックリスト

# 検証 -- [機能名]

## 自動
- [ ] すべてのテストがパス
- [ ] Lintがクリーン
- [ ] 型チェックがクリーン

## 受入基準
- [ ] AC-1 --
- [ ] AC-2 --

## 仕様からコードへ
- [ ] 変更されたファイルは計画と一致
- [ ] 文書化されていないアーキテクチャ変更がない
- [ ] 実装が異なる場合、仕様を更新

結論

仕様駆動開発は、より多くの文書を書くことについてではありません。仕様定義、計画、タスク、実装、検証を通じて、各ステップでレビューゲートを設けて進んでいくことについてです。各フェーズは、次のアクター – 人間またはエージェント – に、前のフェーズよりも少ない推測を残すべきです。

小さく始めなさい。中規模な1つの機能で完全なワークフローを実行しなさい。成果物をリポジトリ内のMarkdownとして保ちなさい。現実が乖離したときに仕様を更新しなさい。マージの前に検証しなさい。連鎖が機能すれば、ドリフトが減り、レビュー可能な小さな差分が得られ、セッションリセットやチームの引き継ぎを超えて生き残る意図の永続的な記録が得られます。

連鎖が事務作業に変わった場合、スコープを切り詰めなさい – レビューを切り詰めなさいなさい。30ページも誰も読んだことのない仕様よりも、検証された2ページの仕方が勝ちです。

有用なリンク

購読する

システム、インフラ、AIエンジニアリングの新記事をお届けします。