10
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[スペック駆動開発] ウォーターフォール回帰を避け、サイクルを回し続けるための「Docs-as-Code」設計

10
Last updated at Posted at 2026-03-01

前回の記事では、スペック駆動開発(SDD)がウォーターフォール回帰になるかどうかは「仕様を先に書くか」では決まらず、反復ループとして運用できているか、そしてテスト/契約/CIに接続できているかが分岐点だ、という話をしました。

今回はその続編として、SDDを「重い設計書運用」に落とさず、アジャイルのリファインメント成果物に寄せたまま、検証に接続できる仕様を作り、運用サイクルを維持するためのドキュメント構成と運用の型を提案します。

この記事の構成は、私が開発しているQFAIで採用している specs/(仕様レイヤー)と contracts/(契約レイヤー)をベースにしています。
ただしQFAIは運用補助が厚めなので、ここでは ツールなしでも回る最小の形に抽象化して紹介します。

SDDの「サイクル」を先に固定する

前回記事で示した、SDDの運用サイクルは以下の通りでした。

ドキュメント構成は「きれいな置き場所」ではなく、A→E→A が回り続けるようにする仕掛けとして設計する必要があります。
逆に言えば、ここが外れると「仕様作成 → 承認 → 実装 → 乖離」の流れになり、ウォーターフォール回帰の失敗パターンに寄っていきます。

ドキュメントが壊れる典型パターン

SDDのドキュメントが破綻するときは、テンプレの良し悪しよりも次の崩れ方が原因になりがちです。

  • 仕様が一箇所に集約されて肥大し、読む/直すコストが上がる
  • 議論と決定が混ざり、何が確定で何が未確定か分からなくなる
  • 仕様がテストや契約に接続されず、実装とのドリフトを検知できない
  • 整合の維持が人手レビューだけに依存して破綻する(レビューがボトルネックになる)

そこで、構成は次の原則に寄せると壊れにくくなります。

  • 仕様は一冊にまとめず、関心ごと(concerns)ごとに「小さい成果物」に分割する
  • 議論と決定を分離し、決定は短く固定する(ADR)
  • 仕様は「機械検査できる資産」(テスト、契約)に接続する
  • Docs-as-Codeとして、変更はPRで、整合はCIで見る

この原則を、アジャイルのリファインメント成果物に寄せて具体化すると、次の「レイヤー構造」が扱いやすい、というのがこの記事の提案です。

提案するドキュメント構成

仕様(specs)は、次の5レイヤーを「標準形」として置きます。

  • Business Flow(上位の業務フロー)
  • User Story(Why/What)
  • Acceptance Criteria(受け入れ条件、Gherkin推奨)
  • Rules(ACを満たすためのロジック。必要ならHowも含める)
  • Examples(Rulesを具体ケースに落とす。テストケース母集団)

この5レイヤーは「唯一の正解」ではありません。
ただ、導入期に「どこに何を書くか」を迷うと、仕様が混ざって短期間で崩れます。まずは骨格を置き、サイクルを回しながら増減させる方が回ります。

加えて、運用の摩擦を下げるために次を同梱します。

  • glossary.md(用語のプロトコル)
  • decisions/(議論ログと決定ログ)

そして、検証へ接続するために次を用意します。

  • contracts/(境界の実行可能仕様: OpenAPI / DDL など)

全体ディレクトリ構成

まず回すための最小構成です。最初は「分ける」だけでも効果が出ます。

specs/
  _shared/
    business-flows/
      bf-0001-order-to-cash.md
    glossary.md
  spec-0001-checkout/
    user-stories.md
    acceptance-criteria.md
    rules.md
    examples.md
contracts/
  api/
    api-0001-order.yaml
  db/
    db-0001-order.sql
decisions/
  README.md
  threads/
  adr/

スケールしてきたら、1ファイルに集約せず「単位ごとに分割」します(差分が読みやすく、レビューもしやすい)。

specs/spec-0001-checkout/
  user-stories/
    us-0001-confirm-order.md
    us-0002-cancel-order.md
  acceptance-criteria/
    ac-0001-confirm-order.md
    ac-0002-out-of-stock.md
  rules/
    br-0001-shipping-address-required.md
    br-0002-out-of-stock-reject.md
  examples/
    ex-0001-missing-shipping-address.md
    ex-0002-out-of-stock-one-item.md

重要なのは「ファイル数」ではなく、隣接レイヤーだけを辿れば理解できることです。

  • BF → US → AC → Rules → Examples(隣接参照)
  • 各成果物はIDで参照する(参照切れはCIで検知する)
  • 変更の単位が小さくなり、PRのレビューも小さくなる

運用の型

「構成」だけではサイクルは回りません。
次の運用ルールをセットにすると、A→E→A が回りやすくなります。

リファインメントで作るもの

  • Business Flow を更新する(上位の地図。例外フローも含める)
  • Flowを分解して User Story(Why/What)を作る
  • User Story ごとに AC(Gherkin)を書く(判定可能な条件に落とす)

Doneの目安(リファインメント)

  • BFに、主要分岐と失敗パスが描かれている
  • すべてのUSに Why/What があり、Non-goals がある
  • ACは「テスト可能な条件」になっている(曖昧語が残っていない)

プランニング〜実装で増やすもの

  • ACを満たすための Rules を分解する(1 AC → 複数Rulesが自然)
  • Rulesから Examples を展開する(1 Rule → 複数Examplesが自然)
  • 境界が変わるなら contracts/ を更新する(API/DBなど)

Doneの目安(実装に入れる状態)

  • ACからRulesへの分解が終わり、重要な不変条件がRulesに落ちている
  • 少なくとも「拒否条件」「境界値」にはExamplesがある
  • 影響するcontractsが紐づいている(または「影響なし」と明示できる)

検証で戻すもの

  • テスト/契約/レビューで見つかったギャップを、AC/Rules/Examplesへ戻す
  • 迷いどころが生まれたら decisions/ に固定する
  • 言葉の解釈が割れたら glossary.md に固定する

Doneの目安(学びの反映)

  • 実装の例外対応が、ExamplesかRulesに取り込まれている
  • 同じ議論を繰り返しそうな点は、ADRに短く固定されている
  • 用語の揺れが、glossaryで収束する

レイヤーごとの役割とフォーマット例

ここからが具体例です。
各レイヤーは「何を書くか」と「何を書かないか」を曖昧にすると、すぐに混ざって破綻します。

Business Flow

Business Flowは「プロダクトの統括的な業務フロー」です。
複数のUser Storyを束ねるもので、逆に言うと、ここを分解すると複数のUser Storyができます。

  • 表現は Mermaid を推奨(sequenceDiagram / flowchart)
  • 例外フロー(ALT/EX)を先に書くと、後段のAC/Rulesが漏れにくい
  • ファイル末尾に「分解したUser Story(US-ID)」を列挙する

例(sequenceDiagram)です。

```mermaid
sequenceDiagram
  participant Customer as 顧客
  participant Web as Web
  participant OMS as 受注システム
  participant WMS as 倉庫

  Customer->>Web: 注文する
  Web->>OMS: 注文作成
  OMS->>WMS: 出荷依頼
  WMS-->>OMS: 出荷完了
  OMS-->>Web: ステータス更新
``` 

mermaidをレンダリングすると以下のようになります。

User Story

User StoryはBusiness Flowを「ストーリー単位(=機能単位)」に分解したものです。
ここで不可欠なのは、Why と What です。

  • Why: 価値、理由、誰のどんな困りごと
  • What: 何ができるようになるか
  • How: 基本は書かない(ただし後述の Rules に How を書くことは許容)

テンプレ例です。

US-0001: 注文を確定できる

Why
- 顧客が購入を完了できないと売上が成立しない

What
- カート内容を確定し、注文が作成される
- 注文番号が払い出され、以降の照会ができる

Non-goals
- 決済手段の追加は今回やらない

Links
- BF-0001
- AC-0001, AC-0002

Acceptance Criteria(AC)

ACは「そのUser Storyが受け入れ可能かどうか」を判定する条件です。
Gherkin は相性が良いので、ACは Gherkin に寄せるのが扱いやすいです。

Cucumber のGherkinリファレンスによると、Example/Scenario は「ビジネスルールの具体例」であり、同時に「テスト」でもあると言われています。

An example is also a test.

テンプレ例です(1 Scenario = 1 AC として扱うと運用が楽です)。

# AC-0001
Scenario: 注文が確定できる
  Given カートにSKUが1つ以上入っている
  And 配送先が入力済みである
  When 顧客が「注文確定」を実行する
  Then 注文が作成され、注文番号が発行される

# AC-0002
Scenario: 在庫が不足している場合は確定できない
  Given カートに在庫不足SKUが含まれている
  When 顧客が「注文確定」を実行する
  Then 注文は作成されず、在庫不足の理由が表示される

運用の勘所です。

  • ACは「要件の言い換え」ではなく、判定可能な条件に落とす
  • 例外・境界値・拒否条件をACに含める
  • ACは後段の Rules / Examples に分解される前提で、粒度はやや粗くてよい

Rules

Rulesは、ACを満たすために必要なロジックを定義します。
ACは受入条件なので、そこから必要なルールが複数に分解されるのが自然です。

本来、リファインメントではHowを成果物にしない(プランニングで決める)運用が多いと思います。
ただ、AI実装や分業が進むほど「振る舞いとしての不変条件」を先に固定した方が安全な局面もあります。そこで、Rulesに How を含めてもよい、という方針にします。

ただし「実装詳細のメモ帳」になりやすいので、How は次に限定するのが安全です。

  • 仕様として固定したいHow(採番、丸め、優先順位、例外扱い、整合制約)
  • 実装方式の選択肢ではなく、振る舞いとしての不変条件

テンプレ例です。

BR-0001: 注文確定には配送先が必須
- AC-Refs: AC-0001
- Rule: 配送先が未入力なら注文確定は拒否する

BR-0002: 在庫不足SKUがあれば確定不可
- AC-Refs: AC-0002
- Rule: 在庫不足が1件でもあれば注文は作成しない

BR-0003: 注文番号の採番規則
- AC-Refs: AC-0001
- Rule: 注文番号は YYYYMMDD + 連番(6桁) とする
- How: 連番は日次でリセットする

Examples

Examplesは、抽象化されたRulesを具体的なケースに落とし込むものです。
ここが「テストケース母集団」であり、Examplesの網羅率が、そのままテスト網羅率に直結します。

Specification by Example は、具体例を仕様とテストの橋渡しにすることで、ステークホルダーと実装の間のコミュニケーションギャップを埋めると言われています。

bridge the communication gap between stakeholders and implementation teams

テンプレ例です。

EX-0001: 配送先未入力は拒否される
- BR-Ref: BR-0001
- Input:
  - cart_items: 1
  - shipping_address: null
- Expected:
  - order_created: false
  - error: "shipping_address_required"

EX-0002: 在庫不足SKUが1件でもあれば拒否される
- BR-Ref: BR-0002
- Input:
  - cart_items: [ { sku: "A", qty: 1, stock: 0 } ]
- Expected:
  - order_created: false
  - error: "out_of_stock"

運用の勘所です。

  • 1 Rule から複数 Examples を作る(境界値/例外/代表値)
  • Examples は「UI手順」ではなく「入力と期待結果」で書く
  • Examples を増やすほど、AI実装でも人間実装でもブレにくくなる

glossary.md(用語のプロトコル)

用語ぶれは、一定規模を超えると速度を殺し始めます。
そこで glossary.md を「定義の単なる一覧」ではなく、言葉のプロトコルとして用意します。

  • 仕様・議論・実装・テストで使う語を固定する
  • 同義語や禁止語を決め、曖昧な言い回しを減らす

テンプレ例です。

用語: 注文確定
定義: カート内容を注文として作成し、以降の状態遷移を開始すること
含む: 注文番号の発行
含まない: 決済の完了(別の概念)
同義語: 注文作成(ただしUI表示は「注文確定」を優先)
禁止語: 確定処理(曖昧なので禁止)

ポイントは「薄く始めて、議論になった単語だけ追加する」ことです。
最初から完璧な辞書にする必要はありません。

decisions/(議論ログと決定ログ)

迷いどころが増えるほど、合意形成のコストが積み上がります。
decisions/ を意思決定ログとして置き、決めたことを短く固定します。

ここで重要なのは「議論ログ」と「決定ログ」を分離することです。

  • threads/: 議論ログ(背景、論点、選択肢、懸念、却下理由)
  • adr/: 決定ログ(決定、背景、影響、代替案、結果)

adr.github.io によると、ADRは決定の記録であり、決定に至る議論の記録ではないと言われています。

It is a record of the decision, not a record of the discussion that led to the decision.

テンプレ例です。

adr/2026-02-26-order-numbering.md
Title: 注文番号の採番規則を YYYYMMDD+連番 にする

Context
- 受注と出荷の照合で、日付粒度の識別が必要

Decision
- 注文番号は YYYYMMDD + 連番(6桁) とする

Consequences
- 日次リセットが必要
- 連番の一意性を保証する必要がある

Links
- BR-0003

contracts/ は「境界の実行可能仕様」にする

contracts/ は、仕様を検証に接続する“橋”です。
APIなら OpenAPI、DBなら DDL といった 機械検査可能な契約 を置きます。

  • contracts/api/: OpenAPI など
  • contracts/db/: DDL、マイグレーション仕様など

SpecとContractは相互参照します。

  • Spec側から「このRule/Exampleは、どのContractに影響するか」を貼る
  • Contract側から「どのSpec(US/AC)で必要になったか」を貼る

導入初期は、次の最小ルールだけでも効きます。

  • Contractファイル名にIDを振る(API-0001など)
  • SpecからContract-IDを箇条書きで参照する
  • CIで「契約の差分」と「参照切れ」を検知する(まずは軽いスクリプトでよい)

CIで最低限やりたいチェック

高度なトレーサビリティ基盤がなくても、最初は「壊れ方を早期に検知する」だけで十分効果があります。

  • 参照切れ(USが参照するACが存在しない、など)
  • 期待するリンクが欠けている(ACにRulesが紐づかない、など)
  • contractsの差分が出たのに、Specに影響が書かれていない
  • Mermaidの構文エラー(図がレンダリングできない)

最初は grep + 簡単なスクリプトで十分で、運用が回り始めてから自動化を厚くしていけばよいです。

この構成がウォーターフォール回帰しにくい理由

サイクル図の A(短い仕様)と E(検証)を、成果物として“接続”しているのがポイントです。

  • Aに相当する成果物を、US/ACとして明示する
    • intent = Why/What
    • acceptance = Gherkin
  • Eに相当する検証資産を、Examples/Contractsとして明示する
    • Examples = テストケース母集団
    • Contracts = 境界の実行可能仕様(ドリフト検知の基点)
  • A←Eの戻り(ギャップ/学び)を、decisions/glossaryに吸収する
    • 迷いどころは decisions/ で固定する
    • 言葉の解釈は glossary.md で固定する

この“接続”があると、仕様は「読み物」ではなく「更新され続ける資産」になります。
更新され続ける資産になれば、doc rot(陳腐化)しにくく、承認ゲート化もしにくい。

QFAIならすべてAIが対応

本記事で紹介した提案(BF/US/AC/Rules/Examples、glossary、decisions、contracts、参照整合)は、QFAIではすべて実現されています。
さらに、構造化されたドキュメント構成そのものを AIが作成・更新 し、運用フォローまで回すための仕組み(skills と agents)が揃っています。

利用者側の体験は次のイメージです。

  • 変更の意図(何を変えたいか)を入力する
  • AIが Business Flow / User Story / AC を生成・更新する
  • ACから Rules を分解し、Rules から Examples を展開する
  • 境界(API/DBなど)に必要な contracts を生成・更新する
  • トレーサビリティ(参照切れ、未リンク、影響漏れ)をAIがチェックする
  • 人間は、所定の流れで skills を呼び出して、レビューする
  • AIがspecの通りに実装する

この記事では「ツールなしでも回る形」に抽象化しましたが、QFAIではこの一連を 仕組みとして実装済み です。

まとめ

この記事は「これが唯一の正解」というテンプレを押し付けたいわけではありません。
SDDは、サイクルを回しながら ドキュメントを成長させていく営み です。

その上で、導入期に効くのは次です。

  • リファインメント成果物(BF/US/AC)を、そのまま仕様の中心に据える
  • Rules と Examples で「検証へ接続する形」に落とす
  • 用語(glossary)と決定(decisions)を、短く固定して再解釈コストを下げる
  • 境界は contracts として機械検査可能な形にし、CIへ寄せる

5レイヤー(BF/US/AC/Rules/Examples)は、あくまで「回り始めるための骨格」です。
プロダクトやチームの成熟に応じて、分割したり統合したり、追加のビュー(非機能、運用、アーキ)を足したりして構いません。

重要なのは、テンプレの正しさではなく、A→E→A の反復が回り続けることです。

10
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?