1. はじめに
Claude Code や GitHub Copilot などのAIエージェントが当たり前になった今、開発のスタイルは大きく変わりました。指示を出せばコードはどんどん書き上がっていきます。しかしその一方で、「AIに何を作ってほしいか」を毎回口頭やチャットで説明し直していないでしょうか。
これは、いわば行き先を伝えずに運転手(AI)に指示を出し続けている状態です。その場では動くコードができても、少し時間が経つと「なぜこの実装になっているのか」「本来の仕様はどうだったのか」が分からなくなり、コードと仕様がどんどんズレていく。多くの現場で起きているのではないのでしょうか?
実際、「仕様書がそもそも存在しない」「仕様書があるにはあるが更新されておらず最新版とは呼べない」「気づけば誰も全体像を追跡できず、もはやブラックボックス化していて何がどう動いているのか分からない」といった状況は、規模の大小を問わずどの現場でも割とよく起きています。仕様書は「作って終わり」の一度きりのドキュメントになりがちで、実装が進むにつれて実態とのズレが積み重なり、最終的には「コードが仕様書」という状態に陥ってしまうのです。
そこで本記事では、まずAIに読ませるための設計書(仕様書)を用意し、その仕様書を軸にAIへ実装を指示する仕様駆動開発をベースに、そこへ 実装した内容に合わせて仕様書を書き足していくコード先行仕様追記型開発(Code-First Spec-Backfill Development) を組み合わせて運用していく方法を紹介します。仕様書がすべての起点になりながらも、実装の結果を仕様書側にも反映し続けることで、コードと仕様書のどちらも常に最新の状態で保たれる開発サイクルを目指します。
ちなみに「コード先行仕様追記型開発(Code-First Spec-Backfill Development)」という名称は、この記事のために筆者が独自に考えたものです。もし既に同じような考え方を指す名称がすでに存在するようであれば、ぜひ教えてください。
今回の記事は以下のような読者を対象にしています。
- Claude Code や GitHub Copilot を使って日常的に開発している
- 気づけば仕様書よりも先にコードができあがっている、という進め方になっている
- 仕様書を書くこと自体が正直めんどくさく、後回しにしがち
- 「仕様書、気づいたら全然更新してなかった…」という経験がある
- 仕様書が存在しない、もしくはあっても最新版とは呼べない状態になっている
- コードと仕様の対応関係が追えず、ブラックボックス化してしまっている
- コードと仕様のトレーサビリティを確保したい
- そもそも開発が初めてで、仕様書をどう書けばいいか分からない
2. 仕様駆動開発とコード先行仕様追記型開発、2つのアプローチ
最近巷ではAIに詳細な仕様を渡さず、雰囲気(Vibe)だけを伝えてコードを書き進めてもらう「バイブコーディング」という進め方もありますが、これは簡単なプロトタイピングには強い一方、大規模なアプリケーションには不向きだと言われています。本記事では、これとは対照的に仕様書をベースにAIを動かす進め方を紹介します。ただしこの進め方にも、実は1つではなく2つの方向性があります。ここでその両方を整理しておきます。
2.1. 仕様書がコードを導く「仕様駆動開発」
1つは、これまで紹介してきた 仕様駆動開発(Spec Driven Development) です。要件定義・基本設計・詳細設計・実装計画といった「仕様書」を先に用意し、それをベースにAIエージェントを動かしていくワークフローです。
考え方はシンプルです。
事前に詳細な仕様書を用意しておくことで、AIエージェントの振る舞いを正確に制御する
バイブコーディングが「AIに雰囲気で動いてもらう」アプローチであるのに対し、仕様駆動開発は 「設計書でAIを導く」 アプローチです。特にアプリの土台をまだ何もない状態から作り始める最初のタイミングでは、この「仕様書 → コード」という順序がもっとも威力を発揮します。
2.2. コードが仕様書を更新する「コード先行仕様追記型開発」
一方で、実際に開発を進めていくと、細かな修正や機能追加のたびに「必ず先に仕様書を直してから実装する」を毎回きっちり守るのは、正直かなり窮屈です。小さな変更であればあるほど、先に手を動かしてコードを直し、それで問題なければ後から仕様書に反映する、という逆方向の流れの方が現実的な場面が多くなります。
これが、本記事でもう1つの軸として使う コード先行仕様追記型開発(Code-First Spec-Backfill Development) です。「コード → 仕様書」という、仕様駆動開発とは逆の順序で進めながらも、最終的には仕様書とコードを一致させることを目指す、という考え方です。
ちなみに「コード先行仕様追記型開発(Code-First Spec-Backfill Development)」という名称は、この記事のために筆者が独自に考えたものです。もし既に同じような考え方を指す名称がすでに存在するようであれば、ぜひ教えてください。
2.3. 2つの開発手法をフェーズに応じて使い分ける
これらは対立するものではなく、プロジェクトの状況やフェーズに応じて使い分けるものだと捉えてください。
-
アプリの土台をまだ何もないところから作るとき
→ 仕様駆動開発(仕様書 → コード) -
すでにアプリは存在するものの、仕様書がない・不足している・最新ではないとき
→ まずコードを解析して仕様書(spec.yaml)を生成する(コード → 仕様書) -
できあがったアプリを少しずつ改修していくとき
→ コード先行仕様追記型開発(コード → 仕様書)
既存のアプリケーションでは、「仕様書が存在しない」「仕様書はあるが実装と一致していない」というケースも少なくありません。そのような場合は、現在のコードをAIに解析させ、実装内容をもとに spec.yaml を生成するところから始めます。その後、人間が内容をレビューと修正し、その仕様書を起点として仕様駆動開発やコード先行仕様追記型開発へ移行します。
どのアプローチでも最終的な目的は同じで、コードと仕様書を常に一致させ続けること です。
2.4. 仕様書のフォーマットにはYAMLを使う
そしてこの記事では、仕様書のフォーマットとして YAML を採用します。
近年では、LLMに対してJSONやYAMLなどの構造化フォーマットで情報を与える手法が盛んに研究されています。Elnasharら(2025)は、GPT-4oを対象にJSON・YAML・Hybrid CSV/Prefixの3種類のプロンプトスタイルを比較し、プロンプトの形式が出力品質やトークンコスト、処理時間に影響を与えることを示しました。また、YAMLは可読性と効率のバランスに優れたフォーマットであると報告されています。
本記事では、人間が読み書きしやすく、AIにも構造を伝えやすいという点から、仕様書のフォーマットとしてYAMLを採用します。
理由は次の通りです。
- 構造がシンプルで、階層関係を表現しやすい
- コメントが書ける(JSONにはできない)
- 人間が読み書きしやすく保守しやすい
- AIへ構造化された情報を渡しやすい
3. Step 1:YAMLで設計書(spec.yaml)を書く
まずは Claude Code や GitHub Copilot を使って、spec.yaml という設計書を作成します。
ここで重要なのは、書く粒度です。この仕様書をAIに読み込ませるだけで、そのままアプリを実装できるレベルまで具体的に記述します。曖昧な表現は極力避け、「AIが迷わない設計書」を目指しましょう。
また、APIやデータベース設計だけでなく、コントローラー・サービス・リポジトリの責務や、クラス名・関数名(メソッド名)まで設計書に含めることをおすすめします。 ここまで定義しておくことで、AIが独自の命名規則やアーキテクチャで実装してしまうことを防ぎ、コードと仕様書のトレーサビリティも確保しやすくなります。
とはいえ、何もないところから急にこのレベルの設計書を書き上げるのは、正直かなり難易度が高いです。そこでおすすめしたいのが、この設計書自体もAIと対話しながら一緒に作っていくという進め方です。「こういうアプリを作りたい」という大まかなイメージだけをまず伝え、必要な項目を1つずつAIと整理しながらYAMLへ落とし込んでいきます。この作業は一見手間に感じますが、その後の実装フェーズではAIへの指示が非常にシンプルになり、修正の手戻りも少なくなります。
また、既存のアプリケーションから始める場合も考え方は同じです。 仕様書が存在しない、あるいは古くなっている場合は、まずAIに現在のコードを解析させ、spec.yaml のたたき台を生成してもらいます。ただし、一度生成しただけで完成とせず、「この機能の仕様は?」「このAPIの責務は?」「このクラス構成で問題ないか?」といったようにAIと何度も対話を重ねながら内容をブラッシュアップし、実際の仕様に合わせて育てていきます。
つまり、新規開発であっても既存アプリであっても、最初から完璧な仕様書を作るのではなく、AIとの対話を繰り返しながら仕様書を完成させていくという進め方が重要です。仕様書の品質が高くなるほど、その後のAIによる実装品質や保守性も向上します。
このとき、使用する言語やフレームワーク、データベースなどの技術選定についても、AIに相談しながら決めるのがおすすめです。ただし、AIの提案をそのまま鵜呑みにするのではなく、「本当にこの構成で問題ないか」「他に選択肢はないか」を自分でも調査・検証してください。AIはあくまで設計を支援するパートナーであり、最終的な設計・技術選定の責任は開発者自身にあります。
最低限、以下の項目は明記しておくことをおすすめします。
- アプリの目的・概要
- 使用する言語(フロントエンド/バックエンド)
- 使用するフレームワーク
- 使用するDB(種類、テーブル構成など)
- API設計(エンドポイント、リクエスト/レスポンス)
- 画面構成、機能一覧
- クラス設計(Controller / Service / Repository など)
- 関数名(メソッド名)と責務
- ディレクトリ構成
- 認証・認可方式
- 環境変数一覧
- 外部サービス・API連携
- テスト方針(Unit / Integration / E2E)
- コーディング規約・命名規則
- 制約事項(非機能要件・性能要件・セキュリティ要件など)
- 変更履歴(Changelog)
- 未実装・今後の課題(TODO / Backlog)
3.1. spec.yaml の一例
project:
name: TaskManagerApp
version: 1.0.0
purpose: "個人・チーム向けのシンプルなタスク管理アプリ"
tech_stack:
frontend:
language: TypeScript
framework: Next.js
styling: Tailwind CSS
backend:
language: TypeScript
framework: NestJS
database:
type: PostgreSQL
orm: Prisma
architecture:
pattern: MVC
directories:
controllers: src/controllers
services: src/services
repositories: src/repositories
models: src/models
tests: tests
database_schema:
tables:
- name: users
columns:
- { name: id, type: uuid, primary_key: true }
- { name: email, type: string, unique: true }
- { name: password_hash, type: string }
- name: tasks
columns:
- { name: id, type: uuid, primary_key: true }
- { name: user_id, type: uuid, foreign_key: users.id }
- { name: title, type: string }
- { name: status, type: enum, values: [todo, in_progress, done] }
controllers:
AuthController:
methods:
- login
- register
TaskController:
methods:
- list
- create
- update
- delete
services:
AuthService:
methods:
- authenticate
- createUser
TaskService:
methods:
- getTasks
- createTask
- updateTask
- deleteTask
repositories:
UserRepository:
methods:
- findByEmail
- create
TaskRepository:
methods:
- findAllByUserId
- create
- update
- delete
api:
- method: POST
path: /auth/login
controller: AuthController
action: login
service: AuthService.authenticate
- method: GET
path: /tasks
controller: TaskController
action: list
service: TaskService.getTasks
- method: POST
path: /tasks
controller: TaskController
action: create
service: TaskService.createTask
dto:
LoginRequest:
email: string
password: string
LoginResponse:
accessToken: string
CreateTaskRequest:
title: string
TaskResponse:
id: uuid
title: string
status: string
features:
- ユーザー登録
- JWTログイン
- タスクCRUD
- タスクステータス管理
coding_rules:
naming:
controller: PascalCase
service: PascalCase
repository: PascalCase
method: camelCase
comments:
language: Japanese
testing:
framework: Jest
unit:
- AuthService
- TaskService
integration:
- AuthController
- TaskController
constraints:
- パスワードはbcryptでハッシュ化する
- APIはRESTで実装する
- Controllerにビジネスロジックを書かない
- Service経由でRepositoryを呼び出す
ai_rules:
- spec.yamlを仕様の唯一の正とする
- 命名規則を変更しない
- テストコードも同時に生成する
- 実装後はspec.yamlとの差分を報告する
changelog:
- version: 1.0.1
date: "2026-07-20"
author: yamada
summary: "priorityフィールドを追加"
- version: 1.0.0
date: "2026-07-15"
author: suzuki
summary: "初版作成"
backlog:
- id: TASK-101
title: タスク検索機能
priority: High
- id: TASK-102
title: メール通知
priority: Low
このYAMLはあくまで一例です。よりAIが理解しやすい設計書の書き方や、「こんな項目も入れると便利」というアイデアがあれば、ぜひコメントで教えていただけるとうれしいです。
このように「何を」「どの言語・技術で」「どういう構造で」作るのかを事細かに書くことがポイントです。この仕様書があれば、AIに何度も同じ説明をし直す必要がなくなり、結果的にトークンの節約にもなります。
4. Step 2:開発環境を整える
仕様書ができたら、実際に開発を進める環境を整えましょう。
4.1. Gitを使える環境にする
コードの変更履歴を管理・追跡できるように、まずはGitを導入します。GUIで扱いたい場合は GitHub Desktop などのツールが便利です。
- GitHubでアカウントを作成する
- リポジトリを作成する(Privateにしておくのがおすすめです)
このあたりのセットアップ方法は世の中に詳しい記事がたくさんあるので、この記事では割愛します。
4.2. エディタを用意する
次に Visual Studio Code などのエディタを用意し、Claude Code や GitHub Copilot の拡張機能・CLIをインストールします。こちらもインストール方法は公式ドキュメントを参照してください。
5. Step 3:仕様書をもとにAIに実装させる
環境が整ったら、いよいよAIエージェントに実装をお願いします。ここからが仕様駆動開発の本番です。なお、このStepは新規にアプリを開発する場合を想定しています。すでにアプリが存在する場合は、この手順はスキップし、Step 4の「仕様と実装の差異をチェックする」 から始めてください。
5.1. まずはアプリを作成する
@spec.yaml
の内容を漏れなく読み込んで、アプリを実装してください。
5.2. テストコードも一緒に書いてもらう
@spec.yaml
の内容を漏れなく読み込んで、さらにテストコードも書いてください。
このプロンプトを投げたら、あとは待つだけです。私の経験上、規模によってはそこそこ時間がかかるので、気長に待ちましょう。
6. Step 4:仕様と実装の差異をチェックする
実装が完了したら、仕様書と実際のコードに差異がないかAIに確認させます。これがトレーサビリティ確保の重要なポイントです。
@spec.yaml
と現状のコードに差異があれば教えてください。
差異の報告が来たら、その内容を踏まえて次の指示を出していきます。差異が見つかった場合は、「実装がspec.yamlと異なるのか」「spec.yamlが実装と異なるのか」を判断し、どちらを修正すべきかを決めます。
実装側に問題がある場合(コードがspec.yamlに従っていない)
さきほど指摘してくれた差異を修正してください。
コードを@spec.yamlに合わせてください。
仕様書側に問題がある場合(spec.yamlが実装と異なる)
さきほど言ってくれた変更点を以下のドキュメントに反映させて、@spec.yaml
を更新してください。
このように、常にコードと仕様書の内容を同期させることで、次のステップへの準備が整います。
7. Step 5:レビュー → 修正 or 仕様更新のループ
できあがったアプリは、最初のイメージと少しズレていることが多いはずです。ここからは次のループを回していきます。
7.1. まずコミットする
その時点の状態を一旦記録しておくために、コミットしておきましょう。
7.2. イメージと違う場合 → プロンプトで修正する
(修正内容)に合わせてコードを修正してください。
修正結果に問題がなければ、その変更分に対するテストコードも書いてもらいます。
今回の変更分を読み取って、テストコードを書いてください。
7.3. イメージ通りの場合 → 仕様書側を更新する
逆に、実装がイメージ通り(=仕様書よりも実装の方が正しい)だった場合は、コードに合わせて仕様書側を更新します。
今回の変更分を読み取って、
@spec.yaml
の内容を変更してください。
気に入った変更であれば、ここでもコミットします。
7.4. 繰り返す
あとは以下のループをひたすら回し続けます。
- コードを修正・追加する
- テストコードを書く
- 気に入ったら仕様書を更新する
- コミットする
このサイクルを何度も繰り返すことで、コードと仕様書が常に最新の状態で同期される開発が実現できます。
7.5. 今後の機能追加・改修でも同じループを回し続ける
ここまでの流れは、最初のアプリ立ち上げ時のプロセスですが、その後の機能追加や改修でも、このサイクルはまったく同じです。ここからが本当の意味でコード先行仕様追記型開発の威力が発揮されます。
新しい機能を追加したいときや、修正・改良が必要なときは、まずコードから始めるというコード先行仕様追記型開発のアプローチで進めます。
(修正・追加内容)に合わせてコードを修正してください。
修正結果に問題がなければ、その変更分に対するテストコードも書いてもらいます。
今回の変更分を読み取って、テストコードを書いてください。
実装がイメージ通りだった場合は、コードに合わせて仕様書側を更新します。
今回の変更分を読み取って、
@spec.yaml
の内容を変更してください。
最後にコミットして完了です。
このように、まずコードで試し、気に入ったら仕様書に反映させるというコード先行仕様追記型開発のサイクルを何度も繰り返していくのです。これまで「仕様書を書くのは面倒」と感じていた人も、この仕組みに乗せてしまえば、機能追加や修正のたびに自然と仕様書が更新されていきます。もう「仕様書を手動で更新する」という独立した作業は存在しません。すべての変更がコードと仕様書に同時に反映され、常に両者が一致した状態が保たれます。
8. チーム開発への応用
複数人で開発する場合は、README.md にどのようなプロンプトを使うかをまとめておくのがおすすめです。
## AIへの指示テンプレート
### 機能追加・修正時
(修正・追加内容)に合わせてコードを修正してください。
### テストコード作成時
今回の変更分を読み取って、テストコードを書いてください。
### 仕様書更新時(実装がspec.yamlより優れている場合)
今回の変更分を読み取って、
@spec.yaml の内容を変更してください。
### 差異確認時
@spec.yaml と現状のコードに差異があれば教えてください。
こうしておくことで、チームメンバー全員が同じ手順・同じ品質で開発を進められます。誰が担当しても、常に最新の仕様書とトレーサビリティが確保されたコードを保てるのが、この開発手法の大きなメリットです。新規開発から機能追加・修正まで、すべてのフェーズで一貫したプロセスを使えるため、プロジェクト全体の品質が大幅に向上します。
9. まとめ
この記事の内容をまとまると以下の通りです。
- 仕様駆動開発(Spec Driven Development):spec.yamlをベースにAIを導き、「仕様 → コード」で新規アプリを構築するアプローチ
- コード先行仕様追記型開発(Code-First Spec-Backfill Development):機能追加・修正時に「コード → 仕様書」で進める、実務的なアプローチ
- YAML仕様書には、目的・使用言語・フロント/バック・DB・API・クラス設計・関数名・テスト方針などを事細かに書く
- 既存アプリがある場合は、AIにコードを解析させてspec.yamlのたたき台を生成してもらう
- Git/GitHub + VS Code + Claude Code(or Copilot)で開発環境を整える
- 新規開発フェーズ:仕様駆動開発で堅牢な土台を作る
- 運用・改修フェーズ:コード先行仕様追記型開発で「コード → テスト → 仕様書」のサイクルを回す
- spec.yamlを活用して、誰が・いつ・何を変更したかを関数単位まで追跡可能にする
- README に使用するプロンプトをまとめておけば、チーム開発でも全員が同じ品質で開発できる
この2つのアプローチを組み合わせることで、仕様書がコードの変化に自動的に追従し、常に最新の状態が保たれる開発が実現できます。もう「仕様書を書くのは面倒」という悩みはなくなります。
おわりに
多くのエンジニアが、心のどこかで感じていることがあるはずです。仕様書を書いて、常に最新に保つことの重要性は理解している。でも、実際のところ、仕様書を書き続けるのは退屈だし、楽しくない。 なぜなら、コードの挙動こそが真実であり、仕様書はあくまでそれを後付けで説明しているに過ぎないからです。だから心理的には、「コードに仕様書を合わせるべき」と思っているのではないでしょうか。このジレンマを、従来の開発手法では解決できていません。
また、チーム開発の現場では別の課題が生じています。「〇〇さんがいないと、プロジェクトの全体像が分からない」という属人性の問題。仕様書が完備されていない、誰も内容を正確に把握していないという状況。こうした問題は、規模の大小を問わず、業界全体でよく起きています。
そして、私たちの開発現場は大きく変わりました。AIを使えば、正確でボリュームのあるコードを素早く生成できる時代です。それに伴い、人間の役割も変わらざるを得ません。これまで大人数のエンジニアチームが必要だった開発も、AIと少人数で進められるようになってきています。既存の開発手法にただ従うだけでは、この急速な変化についていけません。
もちろん、従来の開発手法が悪いわけではありません。何十年も実践されてきた手法には、多くのケーススタディと知見が蓄積されています。しかし、「今、この瞬間」の最適な手法と、「これからの時代」の最適な手法は異なるかもしれないのです。
実は、アジャイル開発も最初は「やりすぎだ」「規律が足りない」と批判されていました。 しかし今では、多くのプロジェクトで採用される開発手法になり、さらにはスクラムやカンバンなど、様々な派生形が生まれています。同じような進化が、コード先行仕様追記型開発にも起きることを期待しています。
本記事で紹介した「コード先行仕様追記型開発」という考え方を聞いて、「なるほど」と納得する人がいる一方で、否定的な意見を持つ人も少なくないと思います。むしろ、最初は否定的な反応の方が多くなるかもしれません。それは当然です。なぜなら、この手法にはまだ弱い点や改善の余地があるからです。完璧な開発手法など存在しません。
本記事が、これまで述べてきた課題に直面しているエンジニアたちの助けになれば、これ以上の喜びはありません。