AIは単一ファイルの生成は得意ですが、複数ファイルにまたがる設計の一貫性・依存関係の維持が苦手です。「とりあえずAIに投げる」だけでは、後から修正も拡張もできない壊れやすいコードが生まれます。この記事では、それを防ぐための具体的な方法論を解説します。

⚠️ まず知っておくべき:AIへの矛盾した指令は危険

AIは「矛盾をエラーで止める」コンパイラではありません。矛盾した指令を与えると、次のような問題が起きます。

パターン AIの実際の挙動 危険度
矛盾に気づいて質問する 「どちらを優先しますか?」と聞いてくれる(理想)
どちらかを黙って優先する 後に書いた方・強調した方を無断で選択。人間は気づかない 🔴 高
両方を中途半端に満たす どちらの要件も中途半端に満たした「なんとなく動く」コードが生成される 🔴 高
古いルールを上書きする 長い会話の後に新しい指令が入ると、最初のルールを静かに破壊する 🔴 高
⚡ 本質的な問題

AIは「矛盾を解決する」のではなく「それっぽい出力を生成する」モデルです。
コンパイラと違って「矛盾を検出して止まる」という保証がありません。

Phase 1 設計フェーズ(コードを書かせる前)

ここが最も重要です。手を抜くと後で崩壊します。

1. 仕様を人間が先に決める

AIに渡す前に、以下を自分で決めます。

  • 何をするソフトか(1〜3行で言えるレベル)
  • 主要なエンティティ(データ構造)
  • 外部依存(DB、API、ライブラリ)
  • 非機能要件(パフォーマンス、認証など)

2. AIにアーキテクチャ設計をさせる(まだコードは書かせない)

以下のようなプロンプトで、構造だけを先に設計させます。

「以下の仕様のWebアプリを作ります。
コードは書かずに、まず:
  1. ディレクトリ構成
  2. 各ファイルの責務
  3. ファイル間の依存関係
  4. データモデル定義
のみを提案してください」
💡 ポイント

このアウトプットを人間がレビュー・確定させることが絶対条件です。省略しないでください。

3. ARCHITECTURE.md を作成・固定する

AIが会話を通じて参照し続ける「憲法」になります。以下のような内容をMarkdownファイルにまとめます。

# ARCHITECTURE.md
## 技術スタック
- Backend: FastAPI + Python 3.11
- DB: PostgreSQL (SQLAlchemy ORM)
- Frontend: React + TypeScript

## ディレクトリ構成
src/
  api/        # ルーティング層(DBに直接触らない)
  services/   # ビジネスロジック(唯一DBを触る)
  models/     # SQLAlchemyモデル定義
  schemas/    # Pydanticスキーマ(API入出力)

## 重要なルール
- serviceはDBセッションを引数で受け取る(DI)
- apiレイヤーはserviceのみ呼ぶ

Phase 2 実装フェーズ

実装順序:依存の「根っこ」から上へ

上位層から書くと「まだ存在しない関数」を呼ぶコードが生まれ、AIが幻覚を起こしやすくなります。

1. models/    → DBスキーマ(何にも依存しない)
2. schemas/   → データ型
3. services/  → ロジック(modelsに依存)
4. api/       → ルーティング(servicesに依存)
5. tests/     → 全てに依存

1ファイル1プロンプトの原則

AIに実装を依頼するときは、「1回のプロンプトで1ファイル」を守ります。ただし、ただ指定するだけでなく、人間が事前に把握・判断した依存関係も一緒に渡します。

❌ 間違った使い方

「ECサイトのバックエンドを作ってください」

→ AIがファイル構成・依存関係・実装を全部決める
→ 人間が把握できない構造になる

 

✅ 正しい使い方

「services/order_service.py を実装してください。依存するファイル:models/order.py(内容↓)、models/product.py(内容↓)。実装する関数はこの3つのみ:create_order / cancel_order / get_order_summary」

人間がすべての依存関係を把握しきれない場合は、実装プロンプトを投げる前に「このファイルを変える前に、依存するファイルを教えて」とAIに先に確認させるのが現実的な対処法です。

各ファイルへのプロンプト構造

【コンテキスト】
- ARCHITECTURE.md の内容(貼り付け)
- 既存の関連ファイル(貼り付け)

【タスク】
`services/user_service.py` を実装してください

【制約】
- 既存の models/user.py の User クラスを使うこと
- schemas/user.py の UserCreate を入力型とすること
- DBセッションは引数で受け取ること(グローバルに持たない)
- このファイル単体で完結させること(新しいファイルを作らない)

Phase 3 整合性の維持

変更時は「影響チェック → 確認 → 修正」の3ステップを守る

「user_service.py の get_user の返り値を
 User から UserWithProfile に変えました。

 この変更の影響を受けるファイルをリストアップし、
 必要な修正箇所を指摘してください(まだ修正しないで)」
💡 修正と確認は必ず分ける

修正を一気にやらせず、影響範囲の確認 → 人間がGO → 修正実行の3ステップを守ります。

定期的な「整合性監査」

数ファイル実装するごとに以下を実行します。

「以下のファイル群を読んで、
 1. インターフェースの不整合(型の不一致など)
 2. ARCHITECTUREのルール違反
 3. 重複している処理
を報告してください。修正はしないでください」

※なぜ「AIが作ったバグ」の修正は特に難しいか

人間が書いたコードのバグは:

書いた人に意図がある
→ 「なぜそう書いたか」を聞ける
→ デバッグの手がかりがある

AIが書いたコードのバグは:

意図がない(確率的に生成された)
→ 「なぜそう書いたか」が存在しない
→ 手がかりがコードそのものしかない

しかもAIは自信満々に間違えるので、バグがあっても一見正しそうに見えるのが最悪の組み合わせです。

実際に起きるパターン

パターン1:AIが直し続けるが永遠に直らない

バグ報告 → AIが修正案を出す
→ 別の場所が壊れる → また修正
→ 最初の問題が再発 → また修正
→ ループ

AIは「それっぽい修正」を出し続けるので、 堂々巡りに気づきにくい。

現実的な対策

対策1:「AIに直させる」のに時間制限を設ける

AIに同じバグを3回直させて直らなければ
→ 人間がゼロから読む
(これを決めておかないと無限にループする)

対策2:AIが生成した怪しいコードは最初から小さく保つ

後でデバッグできる量にしか作らせない。 理解できないコードを大量生成させるのが最大のリスク

1ファイルを理解してからでないと
次のファイルを生成させない

対策3:バグの「観測」だけAIに任せる

修正ではなく診断だけに使う:

「このバグの原因として考えられる
 可能性を全部列挙してください。
 修正はしないでください」

→ 人間がリストを見て判断する
→ 有望な仮説だけ人間が調査する

対策4:理解できないコードをそもそも採用しない

AIが出したコードを
自分が説明できない → 採用しない

これを守るだけで
デバッグ不能なバグの大半は防げる

現状のAI開発は:

✅ 得意:定型的な処理・テストが書きやすい領域
✅ 得意:仕様が明確で境界が小さいコード
❌ 苦手:複雑な状態管理・並行処理・環境依存
❌ 苦手:自分が生み出したバグのデバッグ

「AIで全部作る」ではなく「AIが得意な領域だけAIに任せる」 という使い方が、今の技術レベルでは生産性が最大化します。

Phase 4 テストとバックアップ

テストは実装直後に書く

「今書いた user_service.py のユニットテストを
 tests/test_user_service.py に書いてください。
 DBはモックを使い、以下のケースを網羅:
 - 正常系
 - ユーザーが存在しない場合
 - DB接続エラー時」

バックアップは「動作確認済み」のタイミングで

「プロンプトごと」より「動作確認してOKだった時点」がバックアップの正しい粒度です。Gitを使ってこまめにコミットするのが最も合理的です。

# 1ファイル実装して動作確認できたら即コミット
git add src/services/user_service.py
git commit -m "add user_service: get/create/delete(動作確認済み)"

特に以下のタイミングは必ずバックアップします。

  • 大きなリファクタを頼む前(影響範囲が読めない)
  • 「複数ファイルをまとめて修正して」と頼む前
  • 長い会話が続いてAIのコンテキストが怪しくなってきた時

ツール選択の指針

ツール 向いているケース
Claude Code ターミナル作業・コマンド実行が必要、ローカル環境での開発
Cursor / Windsurf エディタ上で会話しながら書きたい
Claude.ai(チャット) 設計・レビュー・複雑な相談
GitHub Copilot 補完メイン、自動化より手動が好み

実践的な組み合わせ例:設計 → Claude.ai / 実装 → Claude Code or Cursor / レビュー → Claude.ai

🏆 まとめ:失敗しないための鉄則

  • コードより先に設計を固める(ARCHITECTURE.mdが「憲法」)
  • 依存の根っこから実装する(モデル → サービス → API)
  • 1回のプロンプトで1ファイル(依存関係を人間が把握・明示してから渡す)
  • 変更前に影響範囲を確認する(修正と確認を分ける)
  • 動作確認済みの状態をこまめにGitコミット
  • AIを信用しすぎない(整合性チェックは人間が主導)

AIでのチーム開発ではAIの使い方を全員が守らないと深刻な結果に

通常のチーム開発なら「ルール違反」は人間が書くので比較的ゆっくり広がります。ところがAI開発では:

ルールを守らない開発者
↓
AIが大量のコードを一気に生成
↓
矛盾が広範囲に高速で伝播
↓
気づいた時には手遅れ

人間が手で書く10倍のスピードで壊れが広がります。

まだまだAI開発の方法論は発展段階で、AIの方も進歩が著しいです。

ご参考になりましたら幸いです。