タスクグラフと依存関係
Claude Code が依存関係エッジを持つ複数のタスクをどのように調整し、複雑なワークフローを実現するかを学ぶ。
学ぶこと
セッション3では、TodoWrite がフラットなタスクリストを作成する方法を学びました。しかし、実際のプロジェクトはフラットではありません。タスクは互いに依存し合います。API が存在する前に統合テストを書くことはできませんし、テストが通る前にデプロイすることもできません。
このセッションが終わるまでに、以下のことを理解できるようになります:
- タスクが依存関係エッジを持つ有向非巡回グラフ(DAG)をどのように形成するか
- Claude Code がどのタスクを並列実行でき、どのタスクを逐次実行すべきかをどのように判断するか
- 正しい順序でタスクを実行するためのグラフ走査アルゴリズム
- 適切に構造化された依存関係グラフを生成するプロンプトの書き方
問題
フラットなタスクリストは以下のようになります:
□ データベースマイグレーションの作成
□ API ルートの追加
□ 認証ミドルウェアの作成
□ 統合テストの作成
□ フロントエンドの更新
AI はこれらを上から下へ順番に処理します。しかし、これでは重要な情報が欠落しています:
- 無駄な逐次処理 — 「データベースマイグレーションの作成」と「API ルートの追加」は並列実行できるのに、フラットリストでは逐次処理を強制される
- 不正な順序 — API ルートが存在する前に「統合テストの作成」が実行されることを防ぐ仕組みがない
- 連鎖的な失敗 — 「認証ミドルウェアの作成」が失敗した場合、AI はどの下流タスクがブロックされるか分からない
これらの問題はタスクリストが大きくなるにつれて倍増します。隠れた依存関係を持つ15タスクの実装計画は、手戻りとコンテキストの無駄使いの原因となります。
仕組み
DAG としてのタスク
Claude Code が複雑な作業を計画する際、タスクは自然に有向非巡回グラフを形成します。各タスクはノードで、依存関係はエッジです:
┌──────────────┐
│ Analyze │
│ Requirements│
└──────┬───────┘
│
┌────────┴────────┐
│ │
▼ ▼
┌────────────────┐ ┌────────────────┐
│ DB Migration │ │ Route Handlers│
│ (users table) │ │ (auth routes) │
└────────┬───────┘ └────────┬───────┘
│ │
└────────┬──────────┘
│
▼
┌────────────────┐
│ Auth │
│ Middleware │
└────────┬───────┘
│
┌────────┴────────┐
│ │
▼ ▼
┌────────────────┐ ┌────────────────┐
│ Integration │ │ Update │
│ Tests │ │ Frontend │
└────────────────┘ └────────────────┘
このグラフでは:
- DB Migration と Route Handlers は独立しており、並列実行できる
- Auth Middleware は両方に依存しており、両方が完了するまで開始できない
- Integration Tests と Update Frontend は Auth Middleware に依存しているが、互いには依存していない
依存関係エッジ
各タスクは2つの関係フィールドを持ちます:
Task: "Auth Middleware"
status: pending
blockedBy: ["DB Migration", "Route Handlers"]
blocks: ["Integration Tests", "Update Frontend"]
これらのエッジがグラフ全体をエンコードします:
| フィールド | 意味 |
|---|---|
blockedBy | このタスクが開始する前に完了しなければならないタスク |
blocks | このタスクが完了するまで開始できないタスク |
blockedBy / blocks の関係は対称的です。タスク A がタスク B をブロックしている場合、タスク B はタスク A にブロックされています。
グラフ走査アルゴリズム
Claude Code はシンプルだが効果的なアルゴリズムでタスクグラフを走査します:
REPEAT:
1. Scan all tasks
2. Find tasks where:
- status = "pending"
- ALL blockedBy tasks have status = "completed"
3. These are "ready" tasks -- execute them
(If multiple tasks are ready, run in parallel)
4. Mark completed tasks
5. Check: did completing these unlock new tasks?
6. If no tasks remain, DONE
アルゴリズムを時間軸に沿って可視化すると以下のようになります:
Time ──────────────────────────────────────────────►
Round 1: [Analyze Requirements]
status: pending → in_progress → completed
Round 2: [DB Migration]────────┐ (parallel)
[Route Handlers]──────┘
Round 3: [Auth Middleware]
(unlocked because both blockers completed)
Round 4: [Integration Tests]───┐ (parallel)
[Update Frontend]─────┘
DONE ✓
6つの逐次ステップの代わりに4ラウンドで完了。グラフにより、2つのラウンドでタスクを並列実行でき、総実行時間を短縮できることが明らかになります。
AI がグラフを構築する方法
Claude Code に複雑な機能を依頼すると、サブタスク間の自然な依存関係を分析します。計画フェーズは以下のようになります:
User: "Add authentication to the Express app"
AI internal reasoning:
"I need to break this down. Let me think about what
depends on what..."
1. Analyze requirements → nothing depends on, everything starts here
2. DB migration (users table) → needs requirements analysis
3. Route handlers (login/signup) → needs requirements analysis
4. Auth middleware (JWT validation) → needs both DB and routes
5. Tests → needs middleware
6. Frontend login page → needs middleware
TodoWrite output:
Task 1: Analyze requirements blockedBy: []
Task 2: Create users table migration blockedBy: [1]
Task 3: Create auth route handlers blockedBy: [1]
Task 4: Implement auth middleware blockedBy: [2, 3]
Task 5: Write integration tests blockedBy: [4]
Task 6: Update frontend with login blockedBy: [4]
重要なのは、タスク2と3が同じブロッカー(タスク1)を共有しているが、互いをブロックしていないことです。AI はこれらが独立しており、同時に実行できることを認識します。
サブエージェントによる並列実行
複数のタスクが同時に準備完了状態になると、Claude Code はそれらを並列サブエージェントに委任できます:
Round 2 — Two tasks ready:
Parent Agent
│
├──► Subagent A: "Create users table migration"
│ └── Works in isolated context
│
└──► Subagent B: "Create auth route handlers"
└── Works in isolated context
Both return results → Parent continues to Round 3
これは本コースの2つの概念を組み合わせたものです:タスクグラフが並列化可能な作業を特定し、サブエージェント(セッション4)がそれらを実行するための隔離されたコンテキストを提供します。
キーインサイト
タスクグラフにより、AI は並列化可能なサブタスクを特定することで、1ターンあたりにより多くの作業を行えます。 グラフがなければ、AI はタスクを1つずつ線形に処理します。グラフがあれば、独立したタスクをバッチ処理し、同時に実行できます。
しかし、より深いインサイトは速度ではなく正確性にあります。フラットなタスクリストには「あれが終わるまでこれを始めない」ことを表現する方法がありません。依存関係グラフは順序制約を明示的にし、AI がまだ存在しないコードに対してテストを書いたり、依存関係が準備できる前にミドルウェアを統合したりすることを防ぎます。
ビルドシステムに例えると分かりやすいでしょう。make はファイルをランダムにコンパイルしません。依存関係グラフを読み、リーフを最初にビルドし、上に向かって作業します。Claude Code のタスクグラフも同じように動作します。そして make -j4 が独立したコンパイルユニットを並列化できるように、Claude Code も独立したタスクを並列化できます。
実践例
良い依存関係グラフを生成するためのプロンプト構造化
プロンプト内で関係を明示的にすることで、Claude Code に適切に構造化されたタスクグラフを生成させることができます:
Add a notification system to the app. Break it into tasks
with clear dependencies:
Phase 1 (no dependencies):
- Design the notification data model
- Research WebSocket libraries
Phase 2 (depends on Phase 1):
- Create notifications table migration
- Set up WebSocket server
Phase 3 (depends on Phase 2):
- Build notification API endpoints
- Implement real-time push via WebSocket
Phase 4 (depends on Phase 3):
- Create frontend notification component
- Write end-to-end tests
Use TodoWrite with blockedBy edges. Run parallel tasks
where possible.
依存関係パターンの認識
よく見かける依存関係パターン:
Linear Chain: Fan-Out: Fan-In:
A → B → C A → B D ←─ A
A → C D ←─ B
A → D D ←─ C
Diamond: Independent:
A A B C
/ \ (no edges)
B C
\ /
D
ダイヤモンドパターンは実際のプロジェクトで最も一般的です。1つの分析タスクが並列の実装タスクにファンアウトし、統合タスクに収束します。
グラフにおける失敗の処理
タスクが失敗すると、その下流の依存タスクがブロックされます:
Before failure:
✓ Analyze requirements
→ DB Migration (in progress)
→ Route Handlers (in progress)
□ Auth Middleware (blocked by 2, 3)
DB Migration fails:
✓ Analyze requirements
✗ DB Migration (FAILED)
✓ Route Handlers
⊘ Auth Middleware (BLOCKED — dependency failed)
Recovery:
The AI diagnoses the failure, fixes the migration,
re-runs it, and then Auth Middleware becomes unblocked.
グラフにより、失敗の影響範囲が可視化されます。グラフがなければ、AI は Auth Middleware の処理を進めようとし、データベーステーブルが存在しないために暗号的なエラーに遭遇する可能性があります。
グラフの一目での確認
実行中、タスクリストはライブダッシュボードになります:
Task Graph Status:
✓ [1] Analyze requirements
✓ [2] Create users table migration
✓ [3] Create auth route handlers
→ [4] Implement auth middleware (blockedBy: 2✓, 3✓)
□ [5] Write integration tests (blockedBy: 4)
□ [6] Update frontend with login (blockedBy: 4)
Progress: 3/6 tasks completed | 1 in progress | 2 blocked
Next parallel batch: [5, 6] when [4] completes
変更点
| フラットなタスクリスト | 依存関係付きタスクグラフ |
|---|---|
| 逐次実行のみ | 独立タスクの並列実行 |
| 順序保証なし | 明示的な依存関係エッジが不正な順序を防止 |
| 失敗するとすべてがブロック | 失敗は下流の依存タスクのみをブロック |
| 現在のタスク以外の進捗が見えない | グラフ全体で完了済み・実行中・待機中が分かる |
| AI がコンテキスト内で順序を記憶する必要あり | 依存関係がデータにエンコードされ、圧縮を超えて存続 |
| 一度に1タスク | 独立タスクに複数のサブエージェント |
次のセッション
セッション8ではバックグラウンドタスクを扱います。Claude Code が長時間実行される操作(ビルド、テストスイート、デプロイメント)をバックグラウンドで起動し、結果を待つ間も生産的な作業を継続する方法を学びます。