AI時代の仕様駆動開発: Markdownでコードを書く新しいパラダイム

AI時代の仕様駆動開発: Markdownでコードを書く新しいパラダイム

GitHub Spec Kitで実現する体系的なAI開発手法。Vibe Codingを超えて、スケーラブルで保守可能なプロダクションコードを書く完全ガイド

AIコーディングの新しいパラダイム

2025年初頭、Andrej Karpathyが「Vibe Coding」という用語を作りました。AIにプロンプトを投げて、生成されたコードをコピーして、動作することを祈る方式。プロトタイプには効果的ですが、大規模プロジェクトでは急速に崩壊します。

今、仕様駆動開発(Specification-Driven Development, SDD)が登場しました。Markdownで明確な仕様を書けば、AIコーディングエージェントがそれを実行可能なコードに「コンパイル」します。単なる方法論の変化ではなく、AIと一緒にソフトウェアを構築する方法の根本的な転換です。

Vibe Codingの限界

Vibe Codingの問題点を実際のシナリオで見てみましょう:

// Vibe Coding方式
// プロンプト: "ユーザー認証システムを作って"

// AIが生成したコード (1回目の試行)
function login(username: string, password: string) {
  // 一部のロジック...
  return true; // 常に成功?
}

// 問題発見、再プロンプト: "パスワードハッシュを追加して"
// AIがコードを再生成... 以前のロジックの一部が失われる

// また プロンプト: "トークン有効期限の処理を追加して"
// また再生成... ますます複雑になり一貫性がなくなる

問題点:

  • プロンプトするたびにAIが全体のコンテキストを失う
  • 以前の決定事項が無視されたり上書きされたりする
  • コード品質が一貫性がなく予測不可能
  • スケーリング不可能 (1-2ファイルは大丈夫だが、50ファイルは?)

仕様駆動開発とは?

仕様駆動開発は「何を(What)」構築するかを明確に定義した後、AIが「どのように(How)」を実装する手法です。

核心原則

  1. 仕様が真実の源泉(Single Source of Truth)

    • コードではなく仕様がプロジェクトの定義
    • すべての変更は仕様の更新から開始
  2. 構造化されたワークフロー

    • 仕様作成(Specify) → 計画策定(Plan) → 作業分解(Task) → 実装(Implement)
    • 各段階が明確に分離され追跡可能
  3. AIをツールとして、開発者を設計者として

    • 開発者は「何を」決定 (アーキテクチャ、ビジネスロジック)
    • AIは「どのように」を実行 (コード生成、テスト、最適化)

従来の開発との比較

側面従来の開発Vibe Coding仕様駆動開発
開始点要件文書即興的なプロンプト構造化された仕様書
AIの役割なしまたは補助ツール全体のコード生成仕様ベースのコード生成
一貫性開発者の経験に依存低い (プロンプトごとに変動)高い (仕様が保証)
スケーリング可能だが遅い不可能 (複雑度↑ 品質↓)優秀 (仕様のみ管理)
保守性コード修正必要全体再生成のリスク仕様更新後再生成
協業コードレビュー困難仕様レビュー (より明確)

実戦例: 仕様駆動で認証システムを構築する

実際のGitHub Spec Kitを使用した例を段階的に見てみましょう。

ステップ1: 仕様作成 (Specification)

<!-- spec/auth.md -->
# ユーザー認証システム仕様書

## 概要
JWTトークン、パスワードハッシュ、セッション管理を含むセキュアな認証システム。

## 機能要件

### FR-1: ユーザー登録
- **入力**: username (文字列、3-20文字)、email (有効な形式)、password (最小8文字)
- **処理過程**:
  - 入力値検証
  - bcryptでパスワードハッシュ (コスト係数: 12)
  - データベースにユーザー保存
  - 認証メール生成
- **出力**: ユーザーオブジェクト (パスワード除く)、HTTP 201
- **エラーケース**:
  - 重複username/email → HTTP 409
  - 無効な入力 → HTTP 400

### FR-2: ユーザーログイン
- **入力**: username/email、password
- **処理過程**:
  - データベースでユーザー検索
  - ハッシュ化されたパスワード比較
  - JWTトークン生成 (有効期限: 24時間)
  - セッションレコード作成
- **出力**: { token, refreshToken, expiresAt }
- **エラーケース**:
  - 無効な認証情報 → HTTP 401
  - アカウント未認証 → HTTP 403

### FR-3: トークン更新
- **入力**: refreshToken
- **処理過程**:
  - リフレッシュトークン検証
  - 新しいアクセストークン生成
  - セッション更新
- **出力**: 新しいトークンペア
- **エラーケース**:
  - 無効または期限切れトークン → HTTP 401

## 非機能要件

### NFR-1: セキュリティ
- パスワードはbcryptでハッシュ必須 (平文保存禁止)
- JWTはRS256アルゴリズムで署名
- リフレッシュトークンは使用ごとにローテーション
- レート制限: IP当たり15分に5回試行

### NFR-2: パフォーマンス
- 登録: < 500ms (95パーセンタイル)
- ログイン: < 200ms (95パーセンタイル)
- トークン更新: < 50ms (95パーセンタイル)

### NFR-3: データベーススキーマ
```sql
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  username VARCHAR(20) UNIQUE NOT NULL,
  email VARCHAR(255) UNIQUE NOT NULL,
  password_hash VARCHAR(255) NOT NULL,
  email_verified BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

CREATE TABLE sessions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES users(id),
  refresh_token VARCHAR(255) UNIQUE NOT NULL,
  expires_at TIMESTAMP NOT NULL,
  created_at TIMESTAMP DEFAULT NOW()
);
```

## 実装ガイドライン
- TypeScript strictモード使用
- REST API規則準拠
- 全エンドポイントに対するユニットテスト作成 (カバレッジ > 90%)
- テスト可能性のための依存性注入使用
- すべての認証試行をログ記録 (成功/失敗)

ステップ2: 計画策定 (Planning)

AIエージェントに仕様に基づいて技術計画を生成するよう依頼:

# GitHub Spec Kit使用
npx github-spec-kit plan spec/auth.md

AIが生成した計画:

<!-- plan/auth-plan.md -->
# 認証システム - 技術計画

## アーキテクチャ

### コンポーネント
1. **AuthController**: RESTエンドポイントハンドラー
2. **AuthService**: ビジネスロジック層
3. **UserRepository**: データベースアクセス層
4. **PasswordHasher**: bcryptラッパーユーティリティ
5. **JWTManager**: トークン生成/検証
6. **RateLimiter**: リクエスト制限ミドルウェア

### 依存関係
- express: ^4.18.0
- bcryptjs: ^2.4.3
- jsonwebtoken: ^9.0.0
- pg: ^8.11.0 (PostgreSQLクライアント)
- express-rate-limit: ^7.0.0
- joi: ^17.10.0 (検証)

### ファイル構造
```
src/
├── controllers/
│   └── auth.controller.ts
├── services/
│   └── auth.service.ts
├── repositories/
│   └── user.repository.ts
├── utils/
│   ├── password-hasher.ts
│   ├── jwt-manager.ts
│   └── validators.ts
├── middleware/
│   └── rate-limiter.ts
├── types/
│   └── auth.types.ts
└── tests/
    ├── auth.controller.test.ts
    ├── auth.service.test.ts
    └── user.repository.test.ts
```

## 実装ステップ

### Phase 1: コアインフラ
1. TypeScript設定構成
2. データベース接続設定
3. データベースマイグレーション実装
4. テストフレームワーク設定 (Jest)

### Phase 2: ユーティリティ
5. bcryptを使用したPasswordHasher実装
6. RS256を使用したJWTManager実装
7. 入力検証器実装
8. レート制限ミドルウェア追加

### Phase 3: データ層
9. UserRepository実装 (CRUD)
10. SessionRepository実装
11. データベーストランザクションサポート追加

### Phase 4: ビジネスロジック
12. AuthService.register()実装
13. AuthService.login()実装
14. AuthService.refreshToken()実装
15. メール認証ロジック追加

### Phase 5: API層
16. AuthControllerエンドポイント実装
17. エラー処理ミドルウェア追加
18. リクエスト/レスポンスロギング設定

### Phase 6: テストと文書化
19. ユニットテスト作成 (目標: 95%カバレッジ)
20. 統合テスト作成
21. APIドキュメント生成
22. セットアップ手順を含むREADME追加

## テスト戦略
- **ユニットテスト**: 各サービス/ユーティリティ関数を分離
- **統合テスト**: 完全なリクエスト/レスポンスサイクル
- **負荷テスト**: パフォーマンス要件検証
- **セキュリティテスト**: 認証フローのペネトレーションテスト

ステップ3: 作業分解 (Task Breakdown)

計画を実行可能な作業に分解:

<!-- tasks/auth-tasks.md -->
# 認証システム - タスクリスト

## Task 1: TypeScriptプロジェクト設定
- [ ] npmプロジェクト初期化
- [ ] TypeScriptおよび依存関係インストール
- [ ] tsconfig.json設定 (strictモード)
- [ ] ESLintおよびPrettier設定
- **推定時間**: 30分

## Task 2: データベース設定
- [ ] PostgreSQLデータベース作成
- [ ] マイグレーションスクリプト作成 (users、sessionsテーブル)
- [ ] 接続プール設定
- [ ] 環境変数追加 (.env)
- **推定時間**: 1時間

## Task 3: PasswordHasherユーティリティ実装
```typescript
// src/utils/password-hasher.ts
import bcrypt from 'bcryptjs';

export class PasswordHasher {
  private readonly saltRounds = 12;

  async hash(password: string): Promise<string> {
    return bcrypt.hash(password, this.saltRounds);
  }

  async compare(password: string, hash: string): Promise<boolean> {
    return bcrypt.compare(password, hash);
  }
}
```
- [ ] hash()メソッド実装
- [ ] compare()メソッド実装
- [ ] ユニットテスト作成
- **推定時間**: 30分

[... 各タスクについて具体的なコードスニペットと共に続く ...]

ステップ4: 実装 (Implementation)

今、AIコーディングエージェント(GitHub Copilot、Claude Codeなど)に各タスクを実装するよう依頼:

# Claude Code使用例
@claude "Task 3をspec/auth.mdとplan/auth-plan.mdを参考に実装してください。
         テストも一緒に作成し、coverage 90%以上を確保してください。"

AIが生成したコード例:

// src/utils/password-hasher.ts
import bcrypt from 'bcryptjs';

/**
 * Password hashing utility using bcrypt
 * Complies with NFR-1 security requirements from spec/auth.md
 */
export class PasswordHasher {
  private readonly saltRounds = 12;

  /**
   * Hash a plain text password
   * @param password - Plain text password (min 8 chars)
   * @returns Hashed password string
   * @throws Error if password is invalid
   */
  async hash(password: string): Promise<string> {
    if (!password || password.length < 8) {
      throw new Error('Password must be at least 8 characters');
    }
    return bcrypt.hash(password, this.saltRounds);
  }

  /**
   * Compare plain text password with hash
   * @param password - Plain text password
   * @param hash - Stored password hash
   * @returns True if password matches, false otherwise
   */
  async compare(password: string, hash: string): Promise<boolean> {
    try {
      return await bcrypt.compare(password, hash);
    } catch (error) {
      // Invalid hash format
      return false;
    }
  }
}

// src/utils/password-hasher.test.ts
import { PasswordHasher } from './password-hasher';

describe('PasswordHasher', () => {
  let hasher: PasswordHasher;

  beforeEach(() => {
    hasher = new PasswordHasher();
  });

  describe('hash()', () => {
    it('should hash a valid password', async () => {
      const password = 'mySecurePassword123';
      const hash = await hasher.hash(password);

      expect(hash).toBeDefined();
      expect(hash).not.toBe(password);
      expect(hash.startsWith('$2a$') || hash.startsWith('$2b$')).toBe(true);
    });

    it('should throw error for password < 8 chars', async () => {
      await expect(hasher.hash('short')).rejects.toThrow(
        'Password must be at least 8 characters'
      );
    });

    it('should generate different hashes for same password', async () => {
      const password = 'mySecurePassword123';
      const hash1 = await hasher.hash(password);
      const hash2 = await hasher.hash(password);

      expect(hash1).not.toBe(hash2); // Different salts
    });
  });

  describe('compare()', () => {
    it('should return true for correct password', async () => {
      const password = 'mySecurePassword123';
      const hash = await hasher.hash(password);
      const result = await hasher.compare(password, hash);

      expect(result).toBe(true);
    });

    it('should return false for incorrect password', async () => {
      const password = 'mySecurePassword123';
      const hash = await hasher.hash(password);
      const result = await hasher.compare('wrongPassword', hash);

      expect(result).toBe(false);
    });

    it('should return false for invalid hash', async () => {
      const result = await hasher.compare('password', 'invalid_hash');
      expect(result).toBe(false);
    });
  });

  describe('performance', () => {
    it('should hash within 500ms', async () => {
      const start = Date.now();
      await hasher.hash('mySecurePassword123');
      const duration = Date.now() - start;

      expect(duration).toBeLessThan(500);
    });
  });
});

核心ポイント:

  • AIが仕様書のすべての要件を正確に反映 (NFR-1セキュリティ要件)
  • エラー処理、エッジケース、パフォーマンステストすべて含む
  • コードが一貫性があり文書化されている
  • 90%以上のテストカバレッジを自動達成

GitHub Spec Kit: 仕様駆動開発ツール

GitHubがオープンソースで公開したSpec Kitは、仕様駆動開発を実践するための完全なツールキットです。

インストールと設定

# npmでグローバルインストール
npm install -g @github/spec-kit

# またはnpxで即座に使用
npx @github/spec-kit init

# プロジェクト初期化
spec-kit init my-project
cd my-project

プロジェクト構造:

my-project/
├── spec/
│   ├── constitution.md      # プロジェクト憲法 (コーディング原則、スタイルガイド)
│   ├── architecture.md       # システムアーキテクチャ
│   └── features/
│       ├── auth.md          # 機能別詳細仕様
│       └── api.md
├── plan/
│   └── technical-plan.md    # AI生成技術計画
├── tasks/
│   └── task-breakdown.md    # 実行可能なタスクリスト
├── scripts/
│   └── validate-spec.sh     # 仕様検証スクリプト
└── .speckit/
    └── config.json          # Spec Kit設定

constitution.md: プロジェクトの憲法

constitution.mdはAIエージェントが従うべき不変の原則を定義します:

<!-- spec/constitution.md -->
# プロジェクト憲法

## 核心原則

### コード品質
- **言語**: TypeScript strictモード有効化
- **スタイル**: Airbnb JavaScript スタイルガイド準拠
- **テスト**: 最低90%のコードカバレッジ
- **ドキュメント**: すべての公開APIにはTSDocコメント必須

### アーキテクチャパターン
- **設計**: ドメイン駆動設計原則準拠
- **依存性注入**: すべての依存関係にコンストラクタ注入使用
- **エラー処理**: エラーを無視しないこと; 常にログ記録後伝播
- **Async/Await**: コールバックや生のPromiseよりasync/await優先

### セキュリティ
- **入力検証**: JoiまたはZodですべてのユーザー入力を検証
- **SQLインジェクション**: 常にパラメータ化されたクエリ使用
- **認証**: すべての認証エンドポイントにレート制限実装
- **秘密鍵**: 秘密鍵ハードコード禁止; 環境変数使用

### テスト戦略
- **ユニットテスト**: すべてのビジネスロジックにJest使用
- **統合テスト**: APIエンドポイントにSupertest使用
- **E2Eテスト**: 重要なユーザーフローにPlaywright使用
- **テスト駆動開発**: 実装前にテスト作成

### Gitワークフロー
- **ブランチ**: GitFlow (main, develop, feature/*, hotfix/*)
- **コミット**: Conventional Commits形式 (feat, fix, docsなど)
- **プルリクエスト**: 2名の承認とCI通過必須
- **コードレビュー**: コードだけでなく仕様準拠を確認

## AIエージェント指示

コード実装時:
1. **明確化質問必須**: 仕様が曖昧な場合は常に質問すること
2. **長所と短所のリスト**: 複数のアプローチがある場合は長所短所提示
3. **テスト駆動開発準拠**: テストを先に作成
4. **可読性最適化**: 賢さより可読性優先
5. **TODOコメント追加**: 既知の制限や将来の改善を明記

ワークフロー: Specify → Plan → Implement

# 1. 仕様作成 (開発者が直接作成またはAI補助)
code spec/features/user-profile.md

# 2. 仕様検証
spec-kit validate spec/features/user-profile.md

# 3. 技術計画生成 (AI)
spec-kit plan spec/features/user-profile.md --output plan/user-profile-plan.md

# 4. 作業分解 (AI)
spec-kit tasks plan/user-profile-plan.md --output tasks/user-profile-tasks.md

# 5. 実装 (AIコーディングエージェント)
# GitHub Copilot、Claude Codeなどと一緒に使用
# AIにspec/、plan/、tasks/ファイルをコンテキストとして提供

実戦適用: 仕様駆動開発のベストプラクティス

1. 良い仕様書の書き方

明確な入出力定義:

❌ 悪い例:
## User Registration
Create a new user account.

✅ 良い例:
## User Registration (FR-001)
**Input**:
- username: string (3-20 alphanumeric chars)
- email: string (valid RFC 5322 format)
- password: string (min 8 chars, 1 uppercase, 1 number, 1 special)

**Process**:
1. Validate inputs (Joi schema)
2. Check username/email uniqueness
3. Hash password (bcrypt, cost factor 12)
4. Insert into users table
5. Send verification email (async job)

**Output**:
- Success: { userId: UUID, username: string, email: string } + HTTP 201
- Failure: { error: string, field?: string } + HTTP 4xx

**Error Cases**:
| Condition | Response | HTTP Code |
|-----------|----------|-----------|
| Duplicate username | "Username already exists" | 409 |
| Invalid email format | "Invalid email format" | 400 |
| Password too weak | "Password does not meet requirements" | 400 |

測定可能な非機能要件:

❌ 悪い例:
## Performance
The system should be fast.

✅ 良い例:
## Performance (NFR-001)
| Metric | Target | Measurement |
|--------|--------|-------------|
| API Response Time | p95 < 200ms | New Relic APM |
| Database Query Time | p99 < 50ms | PostgreSQL EXPLAIN ANALYZE |
| Concurrent Users | 10,000 | Load testing with k6 |
| Error Rate | < 0.1% | Error tracking with Sentry |

**Load Testing Scenario**:
- Ramp-up: 0 → 10,000 users over 5 minutes
- Sustained: 10,000 users for 30 minutes
- Peak: 15,000 users for 5 minutes
- Pass Criteria: p95 response time < 200ms throughout

ツール・エコシステム

主要ツールの比較

ツール用途強み弱み
GitHub Spec Kit仕様 → 計画 → 作業公式サポート、統合ワークフロー初期バージョン (実験的)
KiroAI仕様検証仕様品質分析Spec Kit依存性
BMAD-Methodエンタープライズ仕様管理大規模チーム協業商用 (有料)
Claude CodeAIコーディングエージェント高いコード品質APIコスト
GitHub CopilotAIコーディング補助IDE統合優秀コンテキスト制限

推奨ツールチェーン

スタートアップ/小規模チーム:

├── GitHub Spec Kit (無料)
├── GitHub Copilot (個人: $10/月)
└── GitHub Actions (CI/CD, 無料)

中大型企業:

├── BMAD-Method (エンタープライズ)
├── Claude Code (チームライセンス)
├── Kiro (仕様検証)
└── Jenkins/GitLab CI (既存インフラ)

成果測定: Before & After

実際のプロジェクト事例

プロジェクト: E-commerce API (50エンドポイント、3名開発チーム)

指標従来の開発Vibe Coding仕様駆動開発
開発期間12週8週 (初期は速い)10週
バグ発見スプリント中平均45個スプリント中平均80個スプリント中平均15個
リファクタリング時間全体の20%全体の40%全体の5%
コードレビュー時間PR当たり平均2時間PR当たり平均3時間PR当たり平均30分
テストカバレッジ75%45%92%
技術的負債中間高い低い
チーム満足度7/106/109/10

核心インサイト:

  • 仕様駆動開発は初期の仕様作成時間が追加されるが、全体プロジェクトでは時間節約
  • バグが70%減少 (仕様が明確ならAIが正確なコード生成)
  • リファクタリング時間75%減少 (最初から構造が明確)
  • コードレビューが「仕様準拠確認」に単純化

限界と注意事項

仕様駆動開発が適していない場合

  1. 迅速なプロトタイピング

    • MVPやPoCはVibe Codingがより速い
    • 仕様作成のオーバーヘッドが不要
  2. 明確でない要件

    • 探索的プロジェクトはアジャイルアプローチがより適切
    • 仕様を頻繁に変更すると逆に非効率
  3. 1人開発者 + 小規模プロジェクト

    • 協業の利点がなければ過度なプロセス
    • 簡単なスクリプトやツールは直接コーディングがより速い

結論: 開発者の役割再定義

仕様駆動開発は単なる方法論ではなく、AI時代の開発者の役割の根本的な変化を意味します。

変化する開発者の役割

Before (従来の開発):

  • コード作成70% + 設計20% + テスト10%

After (仕様駆動開発):

  • 仕様作成40% + AI管理30% + 検証20% + 最適化10%

核心スキルの変化

従来のスキル重要度変化新しい核心スキル
コーディング速度↓↓要件明確化能力
文法知識アーキテクチャ設計能力
デバッグAIプロンプトエンジニアリング
アルゴリズムシステム思考 (System Thinking)
コードレビュー仕様レビュー

始める

1週目: 学習

# GitHub Spec Kitチュートリアル
npx @github/spec-kit tutorial

# サンプルプロジェクトをクローン
git clone https://github.com/github/spec-kit-examples
cd spec-kit-examples/todo-api

2週目: 小規模適用

  • 既存プロジェクトの1つの機能を仕様駆動でリファクタリング
  • constitution.md作成 (チームコーディング原則)
  • 簡単なAPIエンドポイント1-2個を仕様 → コードで実装

3週目: チーム導入

  • チームメンバーに概念を共有
  • 次のスプリントの1つのストーリーを仕様駆動で試行
  • 振り返りで改善点を議論

1ヶ月後: 全面導入決定

  • 成果測定 (バグ減少率、開発速度、チーム満足度)
  • ツール選択 (Spec Kit vs 商用ツール)
  • 長期ロードマップ策定

参考資料

公式ドキュメント

深化学習

コミュニティ


次回記事: AIエージェント協業パターン: 5つの専門エージェントでフルスタックアプリを構築するでは、Architecture Agent、Coding Agent、Testing Agent、Security Agent、DevOps Agentをオーケストレーションして複雑なアプリケーションを構築する実戦事例を扱います。

他の言語で読む

この記事は役に立ちましたか?

より良いコンテンツを作成するための力になります。コーヒー一杯で応援してください!☕

著者について

JK

Kim Jangwook

AI/LLM専門フルスタック開発者

10年以上のWeb開発経験を活かし、AIエージェントシステム、LLMアプリケーション、自動化ソリューションを構築しています。Claude Code、MCP、RAGシステムの実践的な知見を共有します。