はじめに
最近では、GitHub公式は革新的な手法を提案しました:Markdownをプログラミング言語として用いた仕様駆動開発(Spec-Driven Development)です。
原文参考:Spec-Driven Development Using Markdown as a Programming Language
この手法では、Markdownを単なるドキュメントとしてではなく、AIが解析・実行可能な仕様ソースとして利用し、コード・設定・ドキュメントなどの成果物を生成することで、開発プロセスの自動化と標準化を実現します。
├── .github/
│ └── prompts/
│ └── compile.prompt.md
├── main.go
├── main.md
└── README.md
- README.md:ユーザー向けのドキュメント
- main.md:AI コーディングエージェントの仕様書
- compile.prompt.md:AI コーディングエージェントへのプロンプト
- main.go:最終成果物
例えによる理解
- README.md:レストランのチラシのようなもの、顧客向けの説明
- main.md:料理のレシピのようなもの、AI に麻婆豆腐の作り方を教える
- compile.prompt.md:簡単な手順、例えば料理の準備、火をつける、材料を取る、片付けなど
- main.go:もちろん、実際に出来上がった料理そのもの
この設計のメリット
- 変更がある場合、main.md を修正してプロンプトを実行するだけで異なる成果物を作れる。
- 他のドキュメントを変更する必要がない
- AI との対話効率が向上
注意点 / デメリット
-
1つの main.md に複数のモジュール、API、データモデルが記載されている場合、
AI またはジェネレーターが文書全体を解析する必要があり、
プロジェクト規模が大きくなると性能が急激に低下する。 -
複数人で開発する場合、全員が同じ main.md を編集するのは困難。
- 自然言語ベースのため解釈の違いが生じやすい
- 他のメンバーの参加感が薄くなる
今回主要課題
-
解析の複雑性
AIや生成器が非構造化Markdownを正確に解釈する必要があり、意味の曖昧さで結果が変わる可能性があります。 -
厳格なフォーマット制約
Markdownの内容はテンプレート化された構造に従う必要があり、逸脱すると生成結果が予測できません。 -
保守性・進化コスト
- 単一ファイル
main.mdの変更は全体の生成チェーンに影響し、効率が低下します。 - 複数人での協業時、編集衝突が頻発し、解釈の差異によりエラーが発生しやすいです。
- 古いバージョンの仕様が新しい生成器で互換性を保てない可能性があります。
- 単一ファイル
-
性能ボトルネック
main.mdが複数モジュールやAPIを含む場合、順次解析・生成では性能が急激に低下し、大規模プロジェクトに不向きです。
改善アプローチ
-
モジュール化された仕様(Modular Specs)
-
main.mdを複数のモジュールに分割:APIモジュール、データモデルモジュール、共通列挙モジュールなど - モジュールごとに独立生成可能とし、AIが並列解析できるようにすることで効率向上
-
-
生成器のバージョン管理(Versioned Generators)
- 異なるバージョンの生成器
.Gemini/v1、.Gemini/v2を共存させる - 古いバージョン仕様も生成可能にし、長期互換性を確保
- 異なるバージョンの生成器
-
キャッシュと検証(Cache & Validation)
- 微調整生成結果を
cache/に保存 -
tests/validate_spec.pyによりモジュールの形式と正確性を検証 - 変更モジュールのみの単体・統合テストを実施可能
- 微調整生成結果を
-
Gemini CLIとの統合
- 生成指令テンプレート:
.gemini/commands/prompt.toml - モジュール化された生成タスクをAIに実行させ、差分生成や並列生成を実現
- 生成指令テンプレート:
システムアーキテクチャ設計(説明付きディレクトリ構造例)
project-root/
├── specs/ ← プロジェクトの仕様ソース(source of truth)
│ ├── api/ ← 各 API モジュールの仕様
│ │ ├── PRP1.md ← 第1の API モジュール仕様(例:業務機能A)
│ │ └── PRP2.md ← 第2の API モジュール仕様(例:業務機能B)
│ ├── data/ ← データモデル定義
│ │ ├── product.yml ← 製品モデルのフィールド、型、自然キー等
│ │ └── store.yml ← 店舗モデルのフィールド、型、自然キー等
│ ├── common/ ← 共通列挙型、ポリシー、ルール
│ │ └── enums.yml ← 全体で共有する列挙型や設定
│ └── index.md ← 仕様の総覧、各モジュール概要
│
├── .Gemini/ ← 生成器およびバージョン管理
│ ├── v1/
│ │ ├── compile_prompt.toml ← AI実行ルールテンプレート
│ │ └── run_generate.py ← MCPサービス(仕様から成果物生成)
│ └── v2/
│ ├── compile_prompt.toml ← 新バージョン生成ルールテンプレート
│ └── run_generate.py ← 新バージョン生成サービス
│
├── output/ ← AIまたは生成器生成の成果物
│ ├── graphql/ ← 自動生成 GraphQLスキーマ
│ ├── backend_stub/ ← バックエンド stub コード
│ ├── frontend_types/ ← フロントエンド型同期ファイル
│ └── docs/ ← 自動生成ドキュメント(API文書/README等)
│
├── cache/ ← キャッシュディレクトリ
│ └── inventory.md ← 対話や微調整生成キャッシュ、差分生成高速化用
│
├── tests/ ← 検証およびテスト
│ └── validate_spec.py ← 新モジュール仕様のフォーマット・正確性検証
│
└── README.md ← ユーザー向けプロジェクト説明ドキュメント
比較
| 項目 | 従来(単一 main.md) | 改善後(モジュール化 + バージョン生成器) |
|---|---|---|
| 性能 | 単一ファイル順次生成、規模拡大で遅延 | モジュール独立生成、並列化可能で高速化 |
| 保守性 | 修正で全体に影響、回帰リスク大 | モジュール単位で修正可能、回帰リスク低減 |
| 協業性 | 多人数編集で衝突発生 | モジュールごとに担当割り当て、衝突回避 |
| 拡張性 | ファイル規模増大で解析負荷増 | 新規モジュール追加のみで対応可能 |
実践と検証
Gemini CLI 実行例
gemini /prompt.toml
- PRP1.md / PRP2.md:モジュール化された API 仕様
- Data.md:データモデルのフィールドや制約
- GEMINI.md:特殊ルールや利用者好みの記録
- tests/validate_spec.py:生成前に仕様の形式と正確性を検証
- cache/:対話や中間生成結果のキャッシュ、差分生成に活用
これにより、変更があったモジュールのみを生成し、大規模プロジェクトでも性能低下を防ぎます。
結論
モジュール化仕様 + バージョン生成器 + 検証・キャッシュの組み合わせにより、Markdownは単なる文書ではなくAIが実行可能なシステム設計言語となります。
- 開発者にとって:協業しやすく、変更が局所化され管理容易
- AIにとって:解析効率が高く、並列生成・差分生成に対応
- プロジェクト長期運用:バージョン互換性を保ちつつ、保守性向上
Markdownは、人間の設計思考とAI生成成果物をつなぐ橋渡しとして、拡張性・可用性の高い仕様駆動開発の基盤となります。
最後
最近、AI開発におけるパフォーマンスへの影響について考えています。例えば:
- レシピを先に学ぶ → 材料を揃える
- 材料を先に揃える → レシピを学ぶ
順番はAI開発におけるパフォーマンスへの影響がある?
そして、「レシピ」自体も、コードのように反復させる方法検証したい。例えば:
- 第1版を書く、核心的なステップだけをカバーする
- 素早く効果をテストする
- 結果に基づいて改良を重ね、成熟させるまで続ける
また、以前から取り組みたいと思っている「プロンプトエンジニアリング:哲学的思考とプロンプトの深い融合」についても引き続き探求したい。例えば:
- オッカムの剃刀(倹約の原理)
- 仕様書 / プロンプト / 設計において、不必要な複雑さや冗長性を追加しない。最も必要な説明部分のみを残す。
- 対話 / 弁証法(ソクラテス式問答)
- 仕様書 / プロンプトを作成する際、反例や反対方向の限定条件を能動的に記述する。例:「入力が空の場合どうするか」「このコマンドが対応しないシナリオは何か」「特定の操作を禁止する」など。
目指すのは、AIがより「深みがあり、論理的な」結果を出力できるようにすることです。
ご興味のある方は、いいねをお願いします!