バージョン 0.4 | 2025年12月22日
はじめに
ChatGPT、Claude、Geminiなどのチャット型生成AIは、ソフトウェア開発の強力なパートナーとなる。しかし、これらのツールはファイルを直接編集する機能を持たないため、人間が「質問し、回答を受け取り、コードをコピーして適用する」という流れで作業を進める必要がある。
本稿では、チャット型AIとの対話を通じてアプリケーションを開発する際のベストプラクティスを解説する。設計の相談から、コード生成、デバッグ、レビューまで、実践的なプロンプトの書き方と作業の進め方を具体例とともに示す。
第1章:チャット型AIの特性を理解する
1.1 チャット型AIの強みと限界
強み:
- 自然言語で要件を伝えられる
- 複数の選択肢を比較検討できる
- コードの説明や解説を求められる
- 異なる言語やフレームワークの知識を横断的に活用できる
- 24時間いつでも相談できる
限界:
- ファイルを直接編集できない(コピペが必要)
- プロジェクト全体のコードを一度に把握できない
- 会話が長くなると以前の文脈を忘れることがある
- 最新のライブラリやフレームワークの情報が古い場合がある
- 生成されたコードが必ずしも動作するとは限らない
1.2 AIごとの特徴
各AIには微妙な違いがあるが、本稿のプラクティスはいずれにも適用できる。
| AI | 特徴 |
|---|---|
| ChatGPT | Code Interpreter機能でコード実行可能。プラグインで機能拡張 |
| Claude | 長い文脈の保持が得意。Artifacts機能でコードをプレビュー可能 |
| Gemini | Google製品との連携。大きなコンテキストウィンドウ |
1.3 基本的な作業フロー
チャット型AIとの開発は、以下のサイクルを繰り返す。
1. 要件や問題をAIに説明する
2. AIからコードや提案を受け取る
3. 内容を確認・理解する
4. ローカル環境にコードを適用する
5. 動作確認する
6. 問題があればAIに報告し、修正を依頼する
このサイクルを効率的に回すためのテクニックを、以降の章で解説する。
第2章:プロジェクト情報の伝え方
チャット型AIはプロジェクトのファイルを直接見ることができない。そのため、必要な情報を適切に伝えることが、良い回答を得るための鍵となる。
2.1 AIが得意な開発環境と苦手な開発環境
AIに開発を依頼する前に、AIが得意とする領域と苦手な領域を理解しておくことが重要である。得意な領域では積極的に活用し、苦手な領域では人間が主導権を持つことで、効率的な開発が可能になる。
AIが得意とする開発環境:
| カテゴリ | 具体例 | 理由 |
|---|---|---|
| Webフロントエンド | React, Vue.js, Angular, HTML/CSS/JavaScript | 学習データが豊富、パターンが確立している |
| Webバックエンド | Node.js/Express, Python/FastAPI/Django/Flask, Ruby on Rails | 広く使われており、ドキュメントが充実 |
| スクリプト言語 | Python, JavaScript/TypeScript, Ruby, PHP | 文法がシンプル、即座に実行確認可能 |
| データ処理 | pandas, SQL, データ変換スクリプト | 定型的な処理パターンが多い |
| API開発 | REST API, GraphQL | 設計パターンが標準化されている |
| ユーティリティ | CLIツール, 自動化スクリプト, バッチ処理 | 単機能で完結、テストしやすい |
| テスト作成 | Jest, pytest, JUnit | パターンが明確、仕様から生成しやすい |
| ドキュメント | README, API仕様書, コメント | 自然言語処理が得意 |
AIが苦手とする開発環境:
| カテゴリ | 具体例 | 理由 |
|---|---|---|
| 低レイヤー開発 | OS開発, デバイスドライバ, 組み込みシステム | ハードウェア依存、実機テスト必須 |
| リアルタイムシステム | ゲームエンジン内部, 制御システム | タイミング制約、実行環境での検証必須 |
| 大規模アーキテクチャ | マイクロサービス全体設計, 分散システム | 全体像の把握が困難、コンテキストに収まらない |
| レガシーシステム | COBOL, 古いフレームワーク, 独自DSL | 学習データが少ない、ドキュメント不足 |
| 最新技術 | リリース直後のフレームワーク/ライブラリ | 学習データに含まれていない |
| GUI/UXデザイン | 視覚的なレイアウト調整, アニメーション | 見た目の評価ができない |
| セキュリティ実装 | 暗号化, 認証基盤, ペネトレーションテスト | 専門知識必須、誤りが致命的 |
| パフォーマンスチューニング | プロファイリング, メモリ最適化 | 実行環境でのベンチマーク必須 |
プログラミング言語別の得意度:
【得意】
▲
│ Python, JavaScript, TypeScript
│
│ Java, C#, Go, Rust, Ruby, PHP
│
│ C, C++, Swift, Kotlin
│
│ Haskell, Scala, Clojure, Elixir
│
▼ COBOL, Fortran, アセンブリ, 独自DSL
【苦手】
※ 上にあるほどAIが得意(学習データが豊富で高品質なコードを生成しやすい)
得意な領域での活用例:
【依頼】Reactで検索フォームを作成してください
→ AIが得意な領域。具体的な要件を伝えれば高品質なコードが得られる
【依頼】pandasでCSVを読み込んで集計するスクリプトを作成
→ 定型的な処理。ほぼそのまま使えるコードが生成される
【依頼】REST APIのエンドポイントを追加
→ パターンが確立しており、既存コードに合わせた生成が可能
苦手な領域での対処法:
【依頼】組み込みシステムのファームウェア開発
→ AIには概念説明や擬似コードを求め、実装は自分で行う
【依頼】リリース1ヶ月の新しいフレームワークを使用
→ 公式ドキュメントのURLを提供し、それを参照させる
【依頼】本番環境のパフォーマンスチューニング
→ 一般的なベストプラクティスを聞き、実際の計測は自分で行う
判断のポイント:
AIに任せてよいか判断する際は、以下を確認する。
- 学習データの豊富さ: その技術はどれくらい広く使われているか
- パターンの確立度: 標準的な実装パターンがあるか
- 検証の容易さ: 生成されたコードを簡単にテストできるか
- リスクの大きさ: 誤りがあった場合の影響は深刻か
- 最新性の要求: 最新の情報が必要か(AIの知識は古い可能性)
最新技術への対応について:
AIは最新技術を苦手とするが、これは固定的なものではない。人気のある技術は利用者が増えるにつれて情報が蓄積され、AIモデルの更新時に学習データに含まれるようになる。
【技術の成熟度とAIの対応】
リリース直後(0-6ヶ月)
→ AIはほぼ対応不可。公式ドキュメントを直接参照する
普及期(6ヶ月-2年)
→ AIの対応は不安定。基本的な使い方は分かるが、
ベストプラクティスや細かい仕様は誤りが多い
成熟期(2年以上)
→ AIが十分に学習済み。高品質なコードが生成される
例:フレームワークの対応状況(2025年時点の目安)
| 成熟度 | 技術例 | AIの対応 |
|---|---|---|
| 成熟 | React 16-18, Vue 2-3, Django, Rails | ◎ 高品質なコード生成 |
| 普及中 | Next.js 14, Astro, SvelteKit | ○ 基本は対応、細部に注意 |
| 最新 | リリース1年未満の技術 | △ 公式ドキュメントの併用必須 |
ユーザーがAIに知識を与える方法:
AIの学習データに含まれていない情報は、会話内で教えることで一時的に対応させることができる。
1. コンテキスト内学習(例を示して学習させる):
以下のパターンに従ってコードを生成してください。
【例1】
入力: ユーザー一覧を取得
出力:
def get_users():
return db.query(User).all()
【例2】
入力: 商品一覧を取得
出力:
def get_products():
return db.query(Product).all()
【依頼】
入力: 注文一覧を取得
出力: ?
2. ファイルアップロードによる知識注入:
添付したファイルは、このプロジェクトで使用している
ユーティリティ関数です。
新しいコードを生成する際は、これらの関数を活用し、
同じスタイルで書いてください。
3. 公式ドキュメントのURLを提供:
このプロジェクトでは最新版のライブラリを使用しています。
以下の公式ドキュメントを参照して実装してください:
https://example.com/docs/v2/getting-started
特に「Authentication」セクションのパターンに従ってください。
4. 独自のパターンやルールを定義:
このプロジェクトでは、以下の形式でAPIレスポンスを返します:
{
"success": true,
"data": { ... },
"meta": {
"timestamp": "ISO8601形式",
"request_id": "UUID"
}
}
今後のAPI実装では、この形式に従ってください。
5. カスタム指示の活用(AI別):
| AI | 機能名 | 永続性 |
|---|---|---|
| ChatGPT | Custom Instructions | アカウント全体に適用 |
| ChatGPT | Memory機能 | 会話をまたいで記憶 |
| Claude | Projects | プロジェクト内の全会話に適用 |
| Claude | Memory機能 | 会話をまたいで記憶 |
| Gemini | Gems | カスタムAIとして保存 |
知識注入の注意点:
- 一時的な効果:会話やセッションが終わると忘れる(カスタム指示を除く)
- コンテキスト制限:一度に与えられる情報量には上限がある
- 検証必須:教えたパターンに従っているか必ず確認する
- 再現性の限界:同じ指示でも毎回同じ結果になるとは限らない
2.2 プロジェクト概要テンプレート
新しい会話を始める際や、複雑な質問をする際は、まずプロジェクトの背景を伝える。
テンプレート:
【プロジェクト概要】
- 目的:[何を作っているか]
- 技術スタック:[使用言語、フレームワーク、主要ライブラリ]
- 対象ユーザー:[誰が使うか]
- 現在の状況:[開発段階、直面している課題]
【今回の相談内容】
[具体的な質問や依頼]
悪い例:
ログイン機能を作りたいです。コードを書いてください。
良い例:
【プロジェクト概要】
- 目的:大学の授業で使うプログラミング課題提出システム
- 技術スタック:React 18 + TypeScript、Express、PostgreSQL
- 対象ユーザー:学生30名程度、教員2名
- 現在の状況:基本的なCRUDは完成、これから認証機能を追加
【今回の相談内容】
ログイン機能を実装したいです。
まず、認証方式(セッション vs JWT vs OAuth)の選択について
相談させてください。それぞれのメリット・デメリットを
このプロジェクトの文脈で教えてください。
2.3 コードを共有する際のコツ
AIにコードを見せる場合、関連する部分だけを抜粋して共有する。
悪い例:
以下のコードでエラーが出ます。直してください。
[500行のコードを丸ごと貼り付け]
良い例:
以下のコードでエラーが出ます。
【エラーメッセージ】
TypeError: Cannot read property 'map' of undefined
at UserList (UserList.tsx:15:23)
【該当コード】src/components/UserList.tsx
export const UserList = ({ users }) => {
return (
<ul>
{users.map(user => ( // ← 15行目:ここでエラー
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
【呼び出し元】src/pages/Home.tsx
const Home = () => {
const [users, setUsers] = useState(); // 初期値なし
useEffect(() => {
fetchUsers().then(setUsers);
}, []);
return <UserList users={users} />;
};
usersが初期状態でundefinedになっているのが原因だと思いますが、
適切な対処法を教えてください。
2.4 ディレクトリ構造の共有
ファイル構成を伝えたい場合は、tree形式で示す。
現在のディレクトリ構造は以下の通りです:
src/
├── components/
│ ├── Button.tsx
│ ├── Card.tsx
│ └── UserList.tsx
├── pages/
│ ├── Home.tsx
│ └── Login.tsx
├── hooks/
│ └── useAuth.ts
├── api/
│ └── client.ts
└── types/
└── index.ts
新しく追加する認証関連のコードは、どこに配置すべきでしょうか?
第3章:設計段階でのAI活用
設計が固まっていない段階では、AIを「壁打ち相手」として活用する。いきなりコードを書かせるのではなく、段階的に要件を明確化していく。
3.1 アイデアの言語化
漠然としたアイデアから始める場合、AIに質問させることで要件を明確化する。
プロンプト例:
以下のアプリを作りたいと考えています。
要件を明確にするために、私に質問してください。
【アイデア】
大学の授業で、学生がプログラミング課題を提出して
自動的に採点されるシステム
質問は一度に2〜3個までにして、
私の回答を待ってから次の質問をしてください。
AIは以下のような質問を返してくる:
- 対象のプログラミング言語は?
- 採点の基準は?(出力一致、テストケース、コードの品質)
- 同時に何人程度が使用する想定?
対話を通じて、自分でも気づいていなかった要件が明確になる。
3.2 ユースケースの整理
主要な機能を洗い出す際は、アクターを明示する。
プロンプト例:
このシステムのユースケースを整理してください。
【アクター】
- 学生:課題を提出し、結果を確認する
- 教員:課題を作成し、成績を管理する
- 管理者:システム設定を行う
【出力形式】
アクターごとに、以下の形式で列挙してください:
- ユースケース名
- 概要(1行)
- 優先度(高/中/低)
3.3 設計フェーズであることを明示する
AIはコードを書きたがる傾向がある。設計段階では明示的に制御する。
悪い例:
ログイン機能について相談したい
→ AIが勝手に実装コードを生成してしまう可能性がある
良い例:
【フェーズ:設計検討】
ログイン機能の認証方式について相談させてください。
この段階ではコードは不要です。
以下の3つの方式を比較してください:
1. セッションベース認証
2. JWT認証
3. OAuth(Googleログイン)
比較観点:
- 実装の複雑さ
- セキュリティ
- スケーラビリティ
- このプロジェクト(学生30名程度の小規模システム)への適合性
3.4 技術選定の相談
複数の選択肢を比較させる際は、判断基準を明示する。
プロンプト例:
状態管理ライブラリを選定しています。
以下の3つを比較してください。
【候補】
1. Redux Toolkit
2. Zustand
3. Jotai
【プロジェクトの状況】
- React 18 + TypeScript
- 中規模のSPA(画面数10程度)
- 開発者は私一人(Redux経験なし)
- グローバルな状態は「ログインユーザー」「テーマ設定」程度
【判断基準(重要度順)】
1. 学習コストの低さ
2. TypeScriptとの相性
3. ボイラープレートの少なさ
4. 将来の拡張性
表形式で比較し、このプロジェクトへの推奨を理由とともに教えてください。
3.5 画面設計・データ設計
図やテーブル形式で出力させると、認識齟齬を減らせる。
プロンプト例:
以下の機能に必要なデータベーステーブルを設計してください。
【機能】
- 学生が課題を提出する
- 提出されたコードを自動採点する
- 教員が採点結果を確認する
- 学生は自分の提出履歴と結果を確認できる
【出力形式】
各テーブルについて:
- テーブル名
- カラム一覧(名前、型、制約)
- 他テーブルとの関連
Mermaid記法でER図も作成してください。
第4章:実装フェーズでの効果的なプロンプト
設計が固まったら実装に移る。AIにコードを生成させる際は、具体的で明確な指示が重要である。
4.1 実装前に説明を求める
新しい機能の実装をAIに任せる場合、いきなりコードを書かせるのではなく、まず実装方針を説明させることが重要である。これにより、生成されるコードへの理解が深まり、問題があった場合の修正も容易になる。
なぜ説明を求めるべきか:
- コードの動作原理を事前に理解できる
- 期待と異なる実装方針を早期に発見できる
- 複数のアプローチから最適なものを選べる
- 後から修正する際の知識が身につく
プロンプト例:
以下の機能を実装したいのですが、まずコードを書く前に
実装方針を説明してください。
【機能】
ユーザーがアップロードした画像をリサイズして保存する
【説明してほしいこと】
1. 処理の全体的な流れ
2. 使用するライブラリとその選定理由
3. 考慮すべきエッジケース(大きすぎる画像、対応外の形式など)
4. エラーハンドリングの方針
5. 他の実装方法との比較(あれば)
説明を確認してから、実装を依頼します。
説明を受けた後の確認ポイント:
- 説明を読んで処理の流れを理解できたか
- 不明な用語や概念はないか
- セキュリティやパフォーマンスへの配慮があるか
- プロジェクトの既存コードと整合性があるか
説明に納得してから実装を依頼:
説明ありがとうございます。方針について質問があります:
1. 〇〇の部分について、△△ではなく□□を使う理由は?
2. エラー時は例外を投げるのではなく、Result型を返す方式にしたい
上記を踏まえて、実装をお願いします。
4.2 コード生成の基本プロンプト
テンプレート:
以下の仕様でコードを作成してください。
【機能】
[何を実現するか]
【技術要件】
- 言語/フレームワーク:[具体的に]
- 既存のコード規約:[あれば]
- 使用するライブラリ:[指定があれば]
【入力】
[関数やコンポーネントが受け取るもの]
【出力】
[期待する動作や戻り値]
【制約】
- [やってほしくないこと]
- [守ってほしいルール]
具体例:
以下の仕様でReactコンポーネントを作成してください。
【機能】
課題の提出フォーム。コードをテキストエリアに入力し、
送信ボタンを押すと親コンポーネントにコードが渡される。
【技術要件】
- React 18 + TypeScript
- スタイリングはTailwind CSS
- フォームの状態管理はuseState
【入力(props)】
- assignmentId: string - 課題のID
- onSubmit: (code: string) => Promise<void> - 送信時のコールバック
【出力】
- テキストエリア(コード入力用、等幅フォント)
- 送信ボタン(送信中は無効化してローディング表示)
- 文字数カウンター
【制約】
- any型は使用しない
- コンポーネントは1ファイルで完結させる
- 過剰なコメントは不要
4.3 段階的に実装を進める
大きな機能は一度に依頼せず、小さな単位に分割する。
悪い例:
ユーザー認証機能を全部作ってください。
ログイン、ログアウト、パスワードリセット、
メール認証、ソーシャルログイン全部お願いします。
良い例:
ユーザー認証機能を段階的に実装します。
まずはステップ1のみ作成してください。
【全体計画】
ステップ1:ログインフォームのUI(今回)
ステップ2:認証APIとの接続
ステップ3:認証状態の管理(Context)
ステップ4:ログアウト機能
ステップ5:保護されたルートの実装
【ステップ1の詳細】
メールアドレスとパスワードを入力するログインフォーム。
送信ボタンを押すとonSubmitが呼ばれる。
バリデーションはこの段階では不要。
4.4 既存コードとの統合
新しいコードを既存のプロジェクトに追加する場合、関連するコードを共有する。
プロンプト例:
既存のプロジェクトに新しいAPIエンドポイントを追加します。
【既存のAPIクライアント】src/api/client.ts
import axios from 'axios';
const apiClient = axios.create({
baseURL: '/api',
timeout: 10000,
});
export const get = <T>(url: string) =>
apiClient.get<T>(url).then(res => res.data);
export const post = <T>(url: string, data: unknown) =>
apiClient.post<T>(url, data).then(res => res.data);
【追加したい機能】
課題を提出するAPI呼び出し関数
【エンドポイント仕様】
POST /api/submissions
リクエスト: { assignmentId: string, code: string }
レスポンス: { submissionId: string, status: 'pending' | 'completed' }
この既存のクライアントを使って、submitAssignment関数を作成してください。
型定義も含めてください。
4.5 出力形式を指定する
コードだけでなく、ファイル配置や使い方も指示できる。
プロンプト例:
以下の機能を実装してください。
【機能】
フォームのバリデーション用カスタムフック
【出力形式】
以下の形式で回答してください:
1. ファイル名とパス
2. コード全文
3. 使用例(このフックを使うコンポーネントの例)
4. 注意点やベストプラクティス
第5章:エラー解決とデバッグ
AIはデバッグの強力な味方となる。エラーの原因特定から解決策の提案まで、効率的に進めるテクニックを紹介する。
5.1 エラー報告の基本形式
テンプレート:
以下のエラーの原因と解決策を教えてください。
【エラーメッセージ】
[エラーの全文をコピペ]
【発生状況】
- いつ発生するか:[操作手順や条件]
- 再現性:[常に発生/たまに発生]
【該当コード】
[エラーが発生している箇所のコード]
【試したこと】
[すでに試した解決策があれば]
【環境】
- OS: [Windows/Mac/Linux]
- 言語/フレームワークのバージョン: [具体的に]
具体例:
以下のエラーの原因と解決策を教えてください。
【エラーメッセージ】
Unhandled Runtime Error
Error: Hydration failed because the initial UI does not match
what was rendered on the server.
【発生状況】
- いつ発生するか:ページをリロードした時
- 再現性:常に発生
【該当コード】src/components/Header.tsx
export const Header = () => {
const [time, setTime] = useState(new Date().toLocaleTimeString());
useEffect(() => {
const timer = setInterval(() => {
setTime(new Date().toLocaleTimeString());
}, 1000);
return () => clearInterval(timer);
}, []);
return <header>現在時刻: {time}</header>;
};
【試したこと】
useEffectの依存配列を変更してみたが改善せず
【環境】
- Next.js 14.0.0
- React 18.2.0
5.2 動かないコードの修正依頼
AIが生成したコードが動かない場合、具体的なフィードバックを伝える。
悪い例:
動きません。直してください。
良い例:
先ほど生成してもらったコードを実行したところ、
以下の問題が発生しました。
【生成されたコード】
const fetchData = async () => {
const response = await fetch('/api/data');
return response.json();
};
【問題】
1. TypeScriptエラー:戻り値の型が推論されない
2. エラーハンドリングがない
3. ローディング状態を管理したい
【期待する動作】
- 戻り値の型を明示(Data型を返す)
- fetch失敗時はエラーをthrow
- ローディング・エラー・データの3状態を返すカスタムフックに
修正版を作成してください。
5.3 原因の切り分けを依頼する
複雑な問題では、原因の候補を列挙させる。
プロンプト例:
以下の現象について、考えられる原因を優先度順に列挙してください。
【現象】
ログイン後、5分程度経つと勝手にログアウトされる。
ブラウザのコンソールにはエラーは出ていない。
【関連情報】
- 認証方式:JWT(アクセストークン + リフレッシュトークン)
- アクセストークンの有効期限:15分
- リフレッシュトークンの有効期限:7日
- トークンはlocalStorageに保存
【確認済みの点】
- サーバー側のログではトークンの期限切れは記録されていない
- 他のブラウザでも同様の現象が発生
各原因について、確認方法も教えてください。
5.4 パフォーマンス問題の相談
プロンプト例:
以下のコードでパフォーマンス問題が発生しています。
原因と改善策を教えてください。
【現象】
ユーザー一覧画面(100件表示)でスクロールがカクつく
【コード】src/components/UserList.tsx
const UserList = ({ users }) => {
const [filter, setFilter] = useState('');
const filteredUsers = users.filter(user =>
user.name.toLowerCase().includes(filter.toLowerCase())
);
return (
<div>
<input value={filter} onChange={e => setFilter(e.target.value)} />
{filteredUsers.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
);
};
const UserCard = ({ user }) => {
// 複雑な計算処理
const stats = calculateUserStats(user);
return (
<div className="card">
<h3>{user.name}</h3>
<p>スコア: {stats.score}</p>
</div>
);
};
React DevToolsのProfilerで確認したところ、
UserCardが毎回再レンダリングされているようです。
第6章:改修時の複数案検討
既存コードを改修する際は、単一の解決策をそのまま採用するのではなく、複数の選択肢を比較検討することが重要である。
6.1 改修案の依頼テンプレート
以下の問題に対する改修案を複数提示してください。
【問題の概要】
[何が問題か]
【現状のコード】
[該当部分のコード]
【依頼】
改修案を3つ提示し、それぞれについて以下を評価してください:
1. 改修内容の概要
2. 変更の規模(小/中/大)
3. メリット
4. デメリット
5. リスク
この段階ではコードは不要です。方針を比較したいです。
具体例:
以下の問題に対する改修案を複数提示してください。
【問題の概要】
ユーザーが同時に同じフォームを送信すると、
データが重複して登録されることがある。
【現状のコード】
const handleSubmit = async (data: FormData) => {
setLoading(true);
await api.createItem(data);
setLoading(false);
router.push('/items');
};
【依頼】
改修案を3つ提示し、それぞれについて以下を評価してください:
1. 改修内容の概要
2. 変更の規模(小/中/大)
3. メリット
4. デメリット
5. リスク
この段階ではコードは不要です。方針を比較したいです。
6.2 選択後の詳細依頼
方針を決めたら、詳細な実装を依頼する。
案Bの「ボタン無効化 + サーバー側での重複チェック」で進めます。
以下の形式で具体的な実装を示してください:
1. フロントエンド側の変更(ボタン無効化)
2. バックエンド側の変更(重複チェック)
3. テストで確認すべき観点
6.3 影響範囲の確認
改修前に影響範囲を確認させる。
この改修を行う場合、他にどのファイルや機能に
影響が出る可能性がありますか?
現在のコードベースの構造:
- src/api/items.ts:API呼び出し
- src/pages/items/new.tsx:新規作成画面
- src/pages/items/[id]/edit.tsx:編集画面
- src/components/ItemForm.tsx:共通フォーム
同様のパターンを使っている箇所があれば、
一緒に修正すべきでしょうか?
第7章:AI生成コードの検証
AI生成コードの最大の落とし穴は、「動くから正しい」という錯覚である。テストケースを通過し、期待通りの出力が得られたとしても、そのコードが本当に意図した通りに動作しているとは限らない。本章では、AI生成コードを実務で活用する際に行うべき検証手順を解説する。
7.1 コードを理解しているか確かめる
理解せずにコピペしてはいけない理由:
- 後からバグが発生しても修正できない
- セキュリティ上の問題を見落とす
- パフォーマンス問題に気づかない
- 類似の機能を作る際に応用が利かない
変数追跡法:
紙とペンを用意し、具体的な入力値を設定して、1行ずつ変数の値を書き出す。
# AIが生成した二分探索のコード
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
変数追跡表を作成する:
入力: arr = [1, 3, 5, 7, 9], target = 7
| ステップ | left | right | mid | arr[mid] | 判定 | 次の動作 |
|---------|------|-------|-----|----------|-----------|-------------|
| 初期 | 0 | 4 | - | - | - | ループ開始 |
| 1回目 | 0 | 4 | 2 | 5 | 5 < 7 | left = 3 |
| 2回目 | 3 | 4 | 3 | 7 | 7 == 7 | return 3 |
理解度を確認する質問:
- なぜ
left <= rightであってleft < rightではないのか? - targetが存在しない場合、ループはどう終了するか?
- 計算量(O(log n))を説明できるか?
言い換えテスト:
コードを自然言語で説明してみる。プログラミング用語を使わずに「この関数は何をしているのか」を説明できるか試す。説明に詰まる箇所があれば、そこは理解が不十分な部分である。
プロンプト例:
以下のコードについて教えてください。
[生成されたコードを貼り付け]
1. このコードが何をしているか、処理の流れを説明してください
2. 各変数の役割を説明してください
3. なぜこの実装方法が選ばれたか、他の方法との比較を教えてください
4. 計算量とメモリ使用量を説明してください
5. 注意すべきエッジケースはありますか?
7.2 セキュリティの検証
AI生成コードは「動作する」ことを優先し、セキュリティを後回しにする傾向がある。以下の観点で必ずチェックする。
インジェクション攻撃のチェック:
# 危険なコード(SQLインジェクション脆弱性あり)
def get_user(username):
query = f"SELECT * FROM users WHERE name = '{username}'"
cursor.execute(query)
# 安全なコード(パラメータ化クエリを使用)
def get_user(username):
query = "SELECT * FROM users WHERE name = ?"
cursor.execute(query, (username,))
チェックポイント:
- 文字列連結でSQL/コマンドを構築していないか
- ユーザー入力を直接使用していないか
- プレースホルダー/パラメータ化を使用しているか
認証情報のハードコード:
# 危険なコード
API_KEY = "sk-abc123xyz789"
DATABASE_PASSWORD = "admin123"
# 安全なコード
import os
API_KEY = os.getenv("API_KEY")
DATABASE_PASSWORD = os.getenv("DATABASE_PASSWORD")
危険な関数の使用:
以下の関数が含まれていたら要注意:
- Python:
eval(),exec() - JavaScript:
eval(),Function() - PHP:
eval()
プロンプト例:
以下のコードにセキュリティ上の問題がないか確認してください。
[生成されたコードを貼り付け]
特に以下の観点でチェックしてください:
1. SQLインジェクション
2. XSS(クロスサイトスクリプティング)
3. コマンドインジェクション
4. 認証情報のハードコード
5. 危険な関数(eval等)の使用
6. 入力値の検証漏れ
問題があれば、修正版も示してください。
7.3 入力検証の確認
AIが生成するコードは、入力検証が不十分なことが多い。
確認すべき項目:
| データ種類 | チェック項目 |
|---|---|
| 文字列 | 空チェック、長さ上限、許可文字種、形式(メール等) |
| 数値 | 数値変換可能か、範囲内か、ゼロ除算の可能性 |
| ファイル | 拡張子、サイズ上限、パストラバーサル(..を含まないか) |
| 配列 | 空配列、要素数上限、要素の型 |
プロンプト例:
以下のコードに入力検証を追加してください。
[生成されたコードを貼り付け]
【検証要件】
- usernameは3〜20文字の英数字のみ
- emailは有効なメールアドレス形式
- ageは0〜150の整数
- 検証失敗時は適切なエラーメッセージを返す
7.4 パフォーマンスの確認
小さなデータでは問題なくても、データ量が増えると急激に遅くなるコードは珍しくない。
確認すべき観点:
- 計算量(O(n)、O(n²)、O(2^n)など)
- ループの入れ子構造
- 不必要なデータのコピー
- メモリ使用量
プロンプト例:
以下のコードのパフォーマンスを評価してください。
[生成されたコードを貼り付け]
1. 時間計算量はどれくらいですか?
2. 空間計算量(メモリ使用量)はどれくらいですか?
3. 10万件のデータを処理する場合、問題はありますか?
4. より効率的な実装方法はありますか?
7.5 検証チェックリスト
AI生成コードを適用する前に、以下を確認する。
必須チェック:
- コードの各行を理解している(口頭で説明できる)
- 入力検証が適切に行われている
- SQLインジェクション対策済み(該当する場合)
- 認証情報がハードコードされていない
- リソース(ファイル、接続)が適切に解放される
- 例外処理が適切に実装されている
追加チェック(状況に応じて):
- パフォーマンステスト実施(大規模データ処理時)
- セキュリティスキャン実施(Web/ネットワーク関連)
- 使用ライブラリのライセンス確認
第8章:テストの設計と実施
改修が完了したら、動作確認のためのテストを体系的に検討する。
8.1 テストケースの洗い出し
プロンプト例:
先ほど実装した「フォーム二重送信防止」機能の
テストケースを提案してください。
【観点】
- 正常系:通常の送信フローが動作すること
- 異常系:二重送信が防止されること
- 境界値:連打した場合の挙動
- エラー時:API失敗後に再送信できること
まずテストケースを日本語で列挙してください。
コードはその後で依頼します。
8.2 手動テストの手順書
自動化が難しいテストは手順書を作成させる。
この機能を手動でテストする手順書を作成してください。
【形式】
1. 事前条件
2. 操作手順
3. 期待する結果
4. 確認ポイント
【カバーすべきケース】
- 正常なフォーム送信
- 送信ボタン連打
- ネットワークエラー後の再送信
- 別タブで同時に送信
8.3 テストコードの生成
テストケースが決まったら、コードを生成させる。
以下のテストケースをJest + React Testing Libraryで
実装してください。
【テストケース】
1. フォーム入力後、送信ボタンを押すとAPIが呼ばれる
2. 送信中はボタンが無効化される
3. 送信完了後、ボタンが再度有効になる
4. 連続クリックしてもAPIは1回しか呼ばれない
【テスト対象】
// ItemForm.tsx のコードを貼り付け
【注意点】
- API呼び出しはモック化する
- 非同期処理はwaitForを使用する
第9章:会話の管理とコンテキストの維持
チャット型AIとの開発では、会話が長くなるほど文脈が失われやすい。効率的に作業を進めるためのテクニックを紹介する。
9.1 会話を分ける判断基準
同じ会話で続けるべき場合:
- 同じ機能の設計→実装→デバッグ
- 密接に関連するファイルの作成
- 一連のリファクタリング
新しい会話を始めるべき場合:
- 別の機能に取り掛かるとき
- 現在の会話が非常に長くなったとき(目安:20往復以上)
- 前の会話の文脈がノイズになるとき
9.2 要約を依頼する
長い会話の途中で、現状を整理させる。
ここまでの議論を要約してください。
【要約してほしい内容】
1. 決まったこと(技術選定、設計方針など)
2. 作成したコード(ファイル名と概要)
3. 残っている課題
4. 次にやるべきこと
9.3 新しい会話での引き継ぎ
新しい会話を始める際は、前回の成果を簡潔に伝える。
前回の会話で以下まで完了しています。続きを進めたいです。
【完了したこと】
- ユーザー認証のJWT方式で実装
- ログイン・ログアウト機能は完成
- 認証状態はContextで管理
【作成済みファイル】
- src/contexts/AuthContext.tsx
- src/hooks/useAuth.ts
- src/pages/login.tsx
【今回やりたいこと】
保護されたルートの実装(未ログイン時はログイン画面にリダイレクト)
9.4 メモを取る習慣
AIとの会話から得た重要な決定事項は、ローカルにメモを残す。
プロジェクトメモの例(DECISIONS.md):
# 技術的意思決定の記録
## 2024-01-15: 認証方式の選定
- 決定:JWT認証
- 理由:小規模プロジェクトでセッション管理のサーバー負荷を避けたい
- 代替案:セッション認証(将来的にスケールする場合は再検討)
## 2024-01-16: 状態管理ライブラリ
- 決定:Zustand
- 理由:学習コストが低く、ボイラープレートが少ない
第10章:バージョン管理との連携
チャット型AIはファイルを直接操作しないため、バージョン管理は自分で行う必要がある。AIが生成したコードを安全に統合するためのプラクティスを紹介する。
10.1 AIにバージョン管理を指示する方法
チャット型AIは会話をまたぐと文脈を忘れるため、バージョン情報を明示的に伝える必要がある。AI別に効果的なプロンプトを紹介する。
共通の基本プロンプト:
【バージョン管理ルール】
1. コードやドキュメントを更新する際は、バージョン番号を付与してください
2. バージョン形式: X.Y(X=メジャー、Y=マイナー)
- 大きな構造変更: メジャー番号を上げる(1.0 → 2.0)
- 機能追加・修正: マイナー番号を上げる(1.0 → 1.1)
3. 更新時は以下を明記してください:
- 変更前のバージョン
- 変更後のバージョン
- 変更内容の要約
ChatGPT向け:
カスタム指示(Custom Instructions)に設定しておくと、毎回指示する必要がなくなる。
コードやドキュメントを作成・更新する際は、以下のルールに従ってください:
1. ファイルの先頭にバージョン情報を含める
例: # Version 1.0 | 2025-01-15
2. 更新時は必ず変更点を箇条書きで報告する
3. 大きな変更の場合は、変更前後の差分を示す
Code Interpreter使用時:
以下のファイルを更新してください。
【現在のバージョン】1.2
【更新内容】○○機能の追加
更新後:
1. バージョンを1.3に上げる
2. 更新履歴セクションに変更内容を追記
3. 変更したファイルをダウンロード可能な形式で提供
Claude向け:
Projects機能のカスタム指示に設定:
このプロジェクトでは以下のバージョン管理ルールを適用してください:
【バージョン形式】
- セマンティックバージョニング: MAJOR.MINOR.PATCH
- 例: 1.2.3
【更新時の手順】
1. 変更内容に応じてバージョン番号を更新
2. ファイル先頭のバージョン表記を更新
3. 更新履歴テーブルに行を追加
4. Artifactとして更新版を出力
【現在の状態】
- メインドキュメント: v1.2.0
- 設定ファイル: v1.0.0
Artifacts活用時:
現在のドキュメント(v1.2)を更新してください。
【変更内容】
- 第5章に新しいセクションを追加
- 誤字を3箇所修正
【依頼】
1. バージョンを1.3に更新
2. 更新履歴に変更内容を追記
3. Artifactとして完全な更新版を出力してください
(差分ではなく、全体を出力)
Gemini向け:
以下のバージョン管理ルールに従ってドキュメントを管理してください:
【ルール】
1. 各ファイルの先頭にYAMLフロントマターでバージョン情報を記載
---
version: "1.2"
last_updated: "2025-01-15"
---
2. 更新時は変更履歴セクションを更新
【現在のバージョン】1.2
【今回の更新内容】○○の追加
10.2 会話内でのバージョン管理テクニック
会話の最初にバージョンを宣言:
これから「ユーザー管理モジュール」の開発を続けます。
【現在の状態】
- main.py: v1.3
- config.py: v1.0
- utils.py: v1.1
今回は main.py を更新して v1.4 にします。
更新前後の確認を依頼:
更新を適用する前に、以下を確認させてください:
1. どのファイルが変更されるか
2. バージョンがいくつからいくつに変わるか
3. 主な変更点は何か
確認後、更新を実行します。
ロールバック用の情報を保持:
この更新を適用します。ロールバックが必要になった場合に備えて、
以下の情報を会話内に残してください:
- 更新前バージョン: 1.2
- 更新前の該当コード: [コードブロック]
- 更新理由: ○○のバグ修正
複数ファイルの整合性管理:
以下のファイル群は相互に依存しています。
更新時はバージョンの整合性を保ってください。
| ファイル | 現在ver | 依存関係 |
|---------|--------|---------|
| main.py | 1.3 | config, utils |
| config.py | 1.0 | なし |
| utils.py | 1.1 | なし |
main.py を更新する場合、依存先に影響がないか確認してください。
長いドキュメントの差分管理:
ドキュメント全体を毎回出力すると非効率なため、差分形式で報告させる。
ドキュメント全体を出力すると長いので、以下の形式で報告してください:
【更新サマリー】
- バージョン: 1.2 → 1.3
- 変更ファイル: guide.md
- 変更セクション: 第5章
【差分】
変更前:
[該当部分のみ]
変更後:
[該当部分のみ]
【更新履歴に追加する行】
| 1.3 | 2025-01-15 | 第5章にセクション追加 |
10.3 コード適用前のチェックリスト
AIが生成したコードをコピペする前に確認すべきこと:
- コードの内容を理解したか
- 既存のコードと整合性があるか
- プロジェクトのコーディング規約に合っているか
- 不要な依存関係が追加されていないか
- セキュリティ上の問題はないか
10.4 細かくコミットする
AIからコードを受け取ったら、機能単位でコミットする。
# 1つの機能が完成したらコミット
git add src/components/LoginForm.tsx
git commit -m "feat: ログインフォームを追加"
# 次の機能
git add src/hooks/useAuth.ts
git commit -m "feat: 認証用カスタムフックを追加"
これにより、問題があった場合に特定の変更だけを取り消せる。
10.5 AIにコミットメッセージを考えさせる
変更内容を伝えて、適切なコミットメッセージを提案させる。
以下の変更に対する適切なコミットメッセージを
Conventional Commits形式で提案してください。
【変更内容】
- LoginForm.tsxを新規作成
- useAuth.tsを新規作成
- AuthContext.tsxを新規作成
- App.tsxにAuthProviderを追加
【形式】
<type>(<scope>): <description>
types: feat, fix, refactor, docs, test, chore
10.6 問題があった場合の対処
AIのコードで問題が発生したら、すぐにロールバックできる。
# 直前のコミットを取り消す(変更は保持)
git reset --soft HEAD~1
# 特定のファイルだけ元に戻す
git checkout HEAD~1 -- src/components/LoginForm.tsx
# 完全に取り消す
git reset --hard HEAD~1
第11章:効果的なプロンプトの原則
ここまでの各章で示したプロンプト例に共通する原則をまとめる。
11.1 具体的に書く
悪い例:
きれいなコードを書いて
良い例:
以下のルールに従ってコードを書いてください:
- 関数は20行以内
- 変数名は英語で意味がわかるように
- マジックナンバーは定数化
- 早期リターンを活用
11.2 コンテキストを与える
悪い例:
ボタンコンポーネントを作って
良い例:
ECサイトの購入確認画面で使うボタンコンポーネントを作ってください。
既存のボタンはsrc/components/Button.tsxにあり、
同じスタイルガイドに従う必要があります。
11.3 制約を明示する
悪い例:
認証機能を実装して
良い例:
認証機能を実装してください。
【制約】
- 外部ライブラリは使用しない(自前実装)
- パスワードはbcryptでハッシュ化
- トークンの有効期限は15分
- any型は使用しない
11.4 出力形式を指定する
悪い例:
選択肢を比較して
良い例:
以下の選択肢を表形式で比較してください。
列:方式名 / メリット / デメリット / 推奨度(★1-5)
最後に、このプロジェクトへの推奨を理由とともに述べてください。
11.5 段階的に進める
悪い例:
アプリを全部作って
良い例:
アプリを以下の順序で作成します。今回はステップ1のみ実施してください。
ステップ1:データモデルの設計(今回)
ステップ2:API設計
ステップ3:バックエンド実装
ステップ4:フロントエンド実装
ステップ5:テスト
ステップ1が完了したら確認しますので、次に進む前に待ってください。
11.6 フィードバックを具体的に伝える
悪い例:
なんか違う
良い例:
生成されたコードについてフィードバックです:
【良かった点】
- 関数の分割が適切
- エラーハンドリングが丁寧
【修正してほしい点】
1. TypeScriptの型がanyになっている箇所がある(L15, L23)
2. コンポーネント名がButtonになっているが、SubmitButtonにしたい
3. ローディング中のスピナーのサイズが指定されていない
上記を修正した版を作成してください。
おわりに
チャット型AIを活用した開発は、「AIに丸投げ」するのではなく、「AIと対話しながら協力して進める」姿勢が重要である。
本稿で紹介したベストプラクティスの要点を改めて整理する。
- プロジェクト情報を適切に伝える:AIは文脈がないと良い回答ができない
- フェーズを明確にする:設計と実装を混同させない
- 実装前に説明を求める:コードを書かせる前に方針を確認する
- 具体的なプロンプトを書く:曖昧な指示は曖昧な結果を生む
- 複数案を比較検討する:最初の提案を鵜呑みにしない
- 生成コードを必ず検証する:理解・セキュリティ・パフォーマンスを確認
- エラーは詳細に報告する:情報が多いほど正確な回答が得られる
- 段階的に進める:大きなタスクは分割する
- バージョン管理を怠らない:いつでも戻れる状態を維持する
AIは強力なツールだが、最終的な判断と責任は開発者にある。AIの提案を批判的に検討し、自分のプロジェクトに最適な形で活用していただきたい。
本稿は、ChatGPT、Claude、Geminiなど主要なチャット型AIを対象として執筆された。AIの機能は日々進化しているため、最新の情報は各サービスの公式ドキュメントを参照されたい。
更新履歴
| バージョン | 日付 | 変更内容 |
|---|---|---|
| 0.4 | 2025-12-22 | 第2章に最新技術への対応とAIへの知識注入方法を追加 |
| 0.3 | 2025-12-22 | 第2章にAIが得意/苦手な開発環境を追加 |
| 0.2 | 2025-12-22 | 第10章にAI種類別バージョン管理のプロンプトを追加 |
| 0.1 | 2025-12-22 | 初版作成 |