logoChibiham
cover
⚖️

AI時代の「仕様」問題:翻訳方向の非対称性とSSoTの所在

導入:AI開発が「仕様」を再発明した

以前、「仕様」の正体で、「仕様」という言葉がRequirements・Contract・Implementationの異なるレイヤーを無区別に指している問題を整理した。そしてその延長で、仕様駆動開発(SDD)がウォーターフォールの再来であり、フィードバックループの軽視が本質的な問題だという疑念を持っていた。

本稿では、それらを踏まえてさらに一歩進み、仕様駆動開発が抱える構造的問題と、SSoT(Single Source of Truth)は何に置くべきかを考える。

きっかけは、AI開発コミュニティにおける「仕様駆動」という言葉の使われ方への違和感だった。設計思想・アーキテクチャ・インターフェース——あらゆるものを「仕様」と呼び、それを書き下せば開発が回るという主張。しかし調べてみると、AI開発文脈の「仕様」は、ソフトウェア工学における「仕様」とは根本的に異なる概念だった(仕様の多義性)。

Kiroの「仕様」とは何か

AWSがリリースしたKiroにおける仕様駆動開発の定義を見てみよう。Marc Brooker(AWSのVP/Distinguished Engineer)はこう述べている。

A specification is simply a description of what a program should do, and what needs it should meet.

一見するとRequirementsレベルの話に聞こえる。しかし実際のKiroのワークフローでは、ユーザーストーリー(Requirements)、システムアーキテクチャやtech stack(Implementationの構造)、インターフェース設計(Contract)がすべてspecの中に含まれる

つまりKiroにおける「spec」とは、ソフトウェア工学的な「仕様」ではない。「バイブコーディングのアンチテーゼとしての、書き下された意図の総体」だ。Kiro公式ブログでも、specificationの最大の価値として挙げられているのは「書き下すことで永続化する」「バージョン管理できる」「AIエージェントが参照できるNorth Starになる」という点であり、これは本質的には構造化されたスーパープロンプトにほかならない。

ThoughtworksのMartinFowler.comの分析記事も、「これら3つのツール(Kiro、spec-kit、Tessl)はすべてspec-driven developmentの実装だと名乗っているが、互いにかなり異なる」と指摘しており、SDDの定義自体がまだ流動的だと述べている。

AI開発文脈が「仕様」という言葉を別の意味で再発明してしまったのだ。

なぜレイヤーの区別が溶けるのか

AI開発文脈で「仕様」のレイヤー区別が溶ける理由は、LLMへのプロンプトという媒体にある。プロンプトには以下が混在しうる。

  • Requirements的な「こういう結果がほしい」
  • Contract的な「入出力はこの形式で」
  • Implementation的な「こういうアルゴリズムで」

これらがすべてテキストという同一のメディアに乗るから、レイヤーの区別が本質的に曖昧になる。プログラミング言語では型システムやモジュール境界がレイヤーを強制的に分離するが、自然言語にはそのメカニズムがない。

自然言語SSoTの本質的不完全性

Kiro的SDDの核心は、「自然言語で書かれたspecをSSoT(Single Source of Truth)にする」というアプローチだ。しかし、これは本質的に不完全である。

自然言語は曖昧性を排除できない。requirements.mdに書いた文章と実際のコードの間には常に解釈のギャップがあり、**そのギャップを埋めるのは結局AIの「よしなに」**だ。これはvibe codingの構造化版であって、厳密なSSoTではない。

一方、Implementationは意図を含有する。プログラミング言語で書かれたコードは単なる実装ではなく、型制約や不変条件を通じて「こうあるべき」という意図を形式的に表現している。

typescript
// 型がStructureの制約を伝えている = 意図が形式化されている
type Order =
  | { status: "draft" }
  | { status: "paid"; paidAt: Date }
  | { status: "shipped"; paidAt: Date; shippedAt: Date };

「出荷済みには支払い日時が必ず存在する」という意図がコード自体に埋め込まれている。自然言語のspecでこれを書いても、それは単なるドキュメントであって強制力がない。コードは制約を強制し、違反をコンパイル時に検出する。自然言語はそれができない。

意図と実装の非対称性

ここに、仕様駆動開発への懐疑の根拠がある。意図と実装の間には、方向による決定的な非対称性があるのだ。ただしこの非対称性の本質は、従来「情報量の差」として語られることが多いが、より正確には確定性と反証可能性の差にある。

意図 → Implementation:非決定的な変換

自然言語の意図からImplementationへの変換は本質的に非決定的だ。同じ意図から無数の異なる実装が生成されうる。LLMの非決定性がそこに乗るから、生成のたびに異なるStructureが出てきて、そのStructureが暗黙に含意するBehaviorも毎回違う。

specをSSoTにしても、そこからの射影が安定しない。自然言語の意図は具体的な実装を一意に決定するための情報が不足しており、不足分をどこかから補わなければならない。その「どこか」がLLMの確率的な推論になる。

さらに、自然言語には振る舞いの確定性がない。「ユーザーが商品を検索できる」という記述からは、具体的にどう動くかが確定しない。解釈のたびに異なる振る舞いが想定されうる。

Implementation → 意図:確定的だが一意ではない

では逆方向——Implementationから意図を読み取る——はどうか。

ここで正直に認めるべきことがある。Implementationから意図への変換も、一意には定まらない。同じソート関数が「UIの見やすさのため」にも「バイナリサーチの前処理のため」にも使われうる。コードからは「ソートしている」ことは分かるが、なぜソートしているかは一意に読み取れない。

したがって、「Implementation→意図は多対一で収束的、意図→Implementationは多対多で非決定的」という単純な図式は正確ではない。両方向とも多対多だ。

非対称性の本質:確定性と反証可能性

では、Implementationの優位性はどこにあるのか。それは振る舞いの確定性反証可能性にある。

振る舞いの確定性。 コードは実行すれば振る舞いが一意に確定する。自然言語は解釈が確定しない。意図の読み取りが一意でなくとも、「このコードが具体的に何をするか」は議論の余地がない。

自然言語:振る舞いも意図も不確定 コード :振る舞いは確定的、意図は不確定(だが制約される)

反証可能性。 コードがあれば「この振る舞いは意図と合っているか?」という問いにYes/Noで答えられる。自然言語のspecだけでは「そもそもこのspecが言っていることは何か?」の段階で解釈が分かれる。意図の抽出が容易なのではなく、意図とのズレの検出が容易なのだ。

フィードバックの起点としての具体性。 実装があれば「これを使ってみて、違うと思ったところを教えて」と言える。自然言語のspecに対しては「これを読んで、違うと思ったところを教えて」としか言えない。前者のフィードバックの質は圧倒的に高い。

つまり、Implementationの優位性は「意図を正確に伝達できる」ことではなく、**「意図との乖離を発見できるフィードバックの起点になる」**ことにある。

翻訳可能性:フィードバックループの速度パラメータ

ここで、Implementationの質が問題になる。

振る舞いの確定性と反証可能性は、実装の質に依存しない。どんなに汚いコードでも、実行すれば振る舞いは確定するし、意図とのズレは検出できる。非対称性の方向はImplementationの質に関わらず保たれる。

しかし、フィードバックの速度は実装の質に大きく依存する。

Contractの推論可能性フィードバックの速度
高い(判別共用体、宣言的構造、明確な命名)型・I/Fを見るだけで構造が分かる → 「これは意図と合っているか?」への判断が速い
低い(手続き的記述、暗黙の状態管理)実行してトレースしないと分からない → 判断に時間がかかる。ただし、判断自体は可能

Contractの推論可能性は、フィードバックループの速度を規定するパラメータだ。推論可能性が高いImplementationほど、フィードバックループが速く回り、意図と実装の乖離を早期に発見・修正できる。

Implementationの優位性(なぜSSoTに適するか) ← 振る舞いの確定性・反証可能性(実装の質に依存しない) フィードバックの速度(SSoTとしての効率) ← Contractの推論可能性(実装の質に依存する)

ここから導かれるのは、「フィードバックループこそが本質」という主張だ。ImplementationをSSoTにすべき理由は、意図の抽出が容易だからではなく、フィードバックループの起点として最も優れているからだ。

AIの有効な使い所

この枠組みを認めるなら、AIの最も有効な使い所は「意図からコードを生成する」よりも、以下の方向ではないか。

  • フィードバックの翻訳 — コードの振る舞いを観察し、意図とのズレを検出・言語化する
  • コードのStructureを分析してContractやRequirementsとの乖離を検出する
  • 人間が設計したStructureの制約の中でBehaviorを埋める

最後の使い方は、仕様と実装が対立するのではなく共に進化する——「仕様・実装共進化」とでも呼ぶべきアプローチの延長線上にある。人間が構造を設計し、AIがその構造の制約の中で振る舞いを実装する。「構造を先に、振る舞いを後に」という原則だ。

SSoTはどこに置くべきか

以上の議論から、SSoTの所在について一つの結論が導かれる。

SSoTは自然言語のspecではなく、Implementationに置くべきだ。

理由を整理する。

  1. 振る舞いの確定性 — コードは実行すれば振る舞いが一意に定まる。自然言語にはこの確定性がない
  2. 反証可能性 — 「この振る舞いは意図と合っているか?」にYes/Noで答えられる。自然言語のspecでは問い自体が曖昧になる
  3. フィードバックの起点 — 具体的なアーティファクトがあるからこそ、「使ってみて違うところを指摘する」というフィードバックループが回る
  4. 強制力 — コンパイラやランタイムが制約違反を検出する。自然言語にはその力がない
  5. 二重管理の回避 — specとcodeの両方をメンテナンスすると「どちらが正しいか」という認知負荷が生じる

これはDomain-Driven Designの思想とも整合する。ユビキタス言語はドメインエキスパート・開発者・コードの間で共有されるものであり、仕様とコードが分離していないことを前提としている。

仕様記述言語という構想とその困難

とはいえ、現在のプログラミング言語が完璧にSSoTの役割を果たせているわけではない。フィードバックループの起点にはなれるが、推論可能性が低い実装では意図の確認に時間がかかる。

理想を言えば、仕様記述と実装が同一のアーティファクトになる言語が欲しい。コードそのものが読み手に対して「なぜこうなっているか」をContractレベルで自己説明でき、かつAIが自然言語から生成・自然言語へ翻訳するときにも情報が落ちない程度に構造化されている言語。Contractの推論可能性が極めて高い——すなわち、フィードバックループが最速で回る言語だ。

歴史的試みと部分的成功

歴史的にはTLA+やAlloy、Z notationのような形式仕様言語がこの問題に取り組んでいたが、学習コストの高さと実用性のギャップで普及しなかった。しかし、仕様と実装を統合する方向の試みは部分的に成功している例もある。

  • 依存型言語(Idris、Agda)— 型レベルで不変条件を表現可能。「長さNのリスト」のような仕様が型に埋め込まれる
  • 篩型(Refinement Types)(Liquid Haskell、F*)— 既存の型に述語を付加し、{x: Int | x > 0} のように制約を型に乗せる
  • 契約による設計(Eiffel、Ada/SPARK)— 事前条件・事後条件・不変条件が言語レベルでサポートされている

今はTypeScriptの判別共用体やRustの代数的データ型あたりが、より軽量にこの役割を部分的に担っている。

成立条件と本質的困難

仕様記述言語が実用的に成立するには、少なくとも以下の条件が必要になる。

  1. 実行可能であること — 記述がそのまま動くこと。記述と実装が別アーティファクトなら二重管理問題が残る
  2. 型システムが十分に豊か — ドメインの不変条件を型レベルで表現でき、違反をコンパイル時に検出できる
  3. 学習コストが既存言語と同程度 — 歴史的に最大のボトルネック。依存型言語は強力だが、証明を書く負担が大きすぎる
  4. 既存エコシステムとの接続 — 孤立した言語は採用されない
  5. AIによる双方向変換が高品質 — 自然言語↔この言語の変換が情報の損失なくできる

条件2と3のトレードオフが本質的な困難だ。表現力を上げれば学習コストが上がる。学習コストを下げれば、既存のプログラミング言語と大差なくなる。

ただし、条件5がこのトレードオフを変える可能性がある。従来は人間が直接書く前提で学習コストが障壁だったが、AIが変換を担うなら、言語自体は人間にとって読みやすくさえあればよく、書きやすさの重要性が下がる。読解容易性と表現力を両立する言語は、書きやすさも求められる場合より設計空間が広い。

とはいえ現時点でそのような中間言語は存在しない。であれば、SSoTはImplementationに置き、推論可能性の高い実装を書くことでフィードバックループを高速化する——これが現時点での最善手だと考える。

認知限界の制約が緩和されたとき

ここまでの議論は、現時点の技術的制約を前提としている。しかし、根本的な制約は認知限界——人間の認知能力と、AIのコンテキストウィンドウの双方——にある。この制約が大きく緩和されたとき、何が変わるだろうか。

非決定性の縮小

意図→Implementationが非決定的なのは、意図だけでは実装を一意に決定する情報が足りないからだ。しかし実際の開発では、意図以外にも膨大な制約がある。

  • 既存コードベースの構造とコンベンション
  • アーキテクチャパターンと技術スタックの選択
  • 依存ライブラリのAPI
  • チームの過去の設計判断の履歴
  • テストスイートが定義する振る舞いの制約

これらの制約がすべてコンテキストに入れば、意図→Implementationの解空間は劇的に狭まる。コンテキスト長の拡大は、意図→実装の変換精度を向上させ、SDDの弱点である非決定性を緩和する可能性がある。 ただしこれは、参照されるコンテキストの大部分がImplementation側のアーティファクト(既存コード、テスト、設計判断の履歴)であることに注意が必要だ。SSoTの所在がImplementationにあるという構造自体は変わらず、自然言語specの精度が上がるのではなく、AIがImplementationをより広く参照できるようになることで変換の実用精度が上がるという話だ。

それでも残る2つの問題

ただし、コンテキストが無限に拡大しても解消されない問題が2つある。

  1. グリーンフィールド問題 — 既存コードベースがない新規開発では、制約が少ないから非決定性は依然として大きい。最初の一歩において「意図→Implementation」は本質的に非決定的なままだ
  2. 自然言語の本質的曖昧性 — 「ユーザーにとって使いやすい」のような要求は、どれだけコンテキストを追加しても一意に解釈できない。自然言語が仕様記述の媒体である限り、この問題は残り続ける

対立の解消:仕様駆動 vs 実装駆動を超えて

認知限界の制約が十分に緩和された世界では、興味深い可能性が開ける。

ImplementationがSSoTであり続けながら、AIがそこからリアルタイムに各レイヤーの情報をオンデマンドで抽出・説明する世界だ。Requirements・Contract・Implementationの区分をAIが即座に分解して提示する。「仕様書」という独立したアーティファクトは不要になり、コードベースそのものが「読めばすべてわかる」状態になる。

皮肉なことに、コンテキスト長の拡大は仕様記述言語の成立条件を緩和すると同時に、その必要性も減じる。AIが既存のプログラミング言語から十分に構造と振る舞いを把握できるなら、新しい中間言語を設計する動機が薄れるからだ。

さらに言えば、「仕様駆動 vs 実装駆動」という対立構図自体が、人間の認知限界に由来する区別かもしれない。Requirements・Contract・Implementationの枠組み自体が、人間が複雑なソフトウェアを分割して理解するための認知的道具であり、それらを一度に把握できる知性にとっては不要な区別となる。

その未来において、本稿で整理した枠組みの価値は「真理の記述」ではなく「人間の認知を補助する道具」として残ることになる。

結論

AI開発文脈の「仕様駆動開発」は、ソフトウェア工学における「仕様」の概念を別の意味で再発明した。その本質は「構造化されたスーパープロンプト」であり、RequirementsContract・Implementationのレイヤー区別には関心がない。

しかし、レイヤーを区別しないことの代償は大きい。意図からImplementationへの変換は本質的に非決定的であり、自然言語のspecをSSoTにしても、そこからの射影は安定しない。

Implementationの優位性は、「意図を正確に読み取れる」ことではない。振る舞いの確定性と反証可能性——実行すれば何が起こるかが一意に定まり、意図とのズレをYes/Noで判定できること——にある。これによりImplementationはフィードバックの起点として機能する。

そしてフィードバックの速度は、Contractの推論可能性——型やI/Fから構造が推察可能であること——に依存する。推論可能性が高いImplementationほど、フィードバックループは速く回る。

SSoTはImplementationに置き、推論可能性の高い実装を書くことでフィードバックループを最大化する。AIは「意図からコードを生成する」方向ではなく、「コードの振る舞いを観察し、意図との乖離を検出し、構造の制約の中で振る舞いを実装する」方向で活用する。それが、vibe codingでもspec-driven developmentでもない、仕様と実装が共進化する第三の道への足がかりになるだろう。


参考文献