はじめに
「GPT-4」の有料版公開から2年弱が経ちました。
みなさん、AIとペアプログラミングしていますか?
本記事では、私がAIとペアプロする際に気をつけている3つのことをご紹介します。
利用するAI
どんなAIを使っている?
- もっとも使う:Claude 3.5 Sonnet(有料)
- 次に、Github Copilot(GPT4o)(有料)
- その次に、ChatGPT OpenAI o1-preview、o1-mini(有料)
どんな使い分けをしている?
基本的にClaude 3.5 Sonnetを使ってできるだけ進めます。理由は出力精度が良いのと個人的に使い慣れているからです。Claude 3.5 Sonnetをゴリゴリ使っているとすぐトークン制限に到達するので、その際にはChatGPTに移って作業したりもします。
AI ツール | 主な用途 |
---|---|
Claude 3.5 Sonnet | •設計・ディレクトリ検討 • 処理順序検討 • ベースラインコード生成 • 実行エラー解析・修正コード提案 |
GitHub Copilot | • インラインコメント追加(自分のコード理解のために) • READEME作成 • mkdir touchコマンド生成 • テスト生成 • ファイル間の依存関係のエラー解消 • コードレビュー |
ChatGPT (o1-preview, o1-mini) | Claude 3.5 Sonnetと同じ。 Claudeの時間制限に到達したら次点で使用する |
AIによるコードレビュー
IDE側で実施した方がその後の修正が行いやすいものは、GitHub Copilotを使用します。
特にコードレビューでは、Github CopilotのVS Code Extension「Promptis」を利用しています。
- 主なメリット
- プロンプト入力の手間を軽減: プロンプトの自動実行により、手動での入力作業を減らし、開発に集中できる
- 一貫性のあるコードレビュー: プロンプトの統一により、コードの品質と一貫性を向上
- 迅速なフィードバック: コードレビューの速度が向上し、開発サイクルが短縮される
本題:AIとのペアプロで気をつけていること
1:ファイルパスをコメントに書く
AIはファイル単体のコーディングは得意ですが、複数ファイル間の整合性を保ったまま作業するのが苦手です。少ないファイル数であればまだ良いのですが、7~8ファイルを超えるあたりで途端に難しくなります。修正コード提案を繰り返しているうちに混濁を起こし始めます。
対策
コードの先頭にファイルパスをコメントしておくと不整合が起こりづらくなります。
こんな感じです。
例.
# api/schema_validator.py
import logging
from typing import Dict, Any, List, Set
class SchemaValidator:
~~
~~
2:静止点を確保する(ディレクトリツリーとシーケンス図)
コード生成〜修正コード提案を繰り返しているうちに、毎度、履歴を考慮した提案が行われるため、トークン数がガンガン消費されていきます。加えてチャットの精度も落ちていきます。
チャットスレッドを新規に立てて作業を分けると良いのですが、新規のスレッドでは過去のやりとりが記憶されていないのでファイル間の依存関係や責務配置を示すことができません。
対策
ディレクトリツリーとシーケンス図をコーディングをはじめる前に生成しておき、新規スレッド立ち上げ時には初期投入してから作業を再開します。戻れる静止点を確保しているイメージです。
できるだけ 少ないトークン数 & AIが誤認しづらい形式 で静止点を確保することが重要になります。
私の行き着いた答えとして、ディレクトリツリーとmermaidシーケンス図を使っています。
他にもっと良い方法があれば、ぜひ教えてほしいです。
こんな感じです。
ディレクトリツリーにファイルの責務も付記するなど、その辺りの工夫は試行錯誤中です。
例.ディレクトリツリー
📦 react-e2e-test-generator
├── 📂 src
│ ├── 📂 core
│ │ ├── __init__.py
│ │ ├── project_scanner.py # プロジェクト構造スキャン
│ │ │ - ディレクトリ解析
│ │ │ - 依存関係解析
│ │ │ - 設定ファイル解析
│ │ │
│ │ ├── test_unit_analyzer.py # テスト単位判定
│ │ │ - ページ単位判定
│ │ │ - 機能単位判定
│ │ │ - シナリオ単位判定
│ │ │ - 依存関係マッピング
│ │ │
│ │ └── 📂 analyzers
│ │ ├── __init__.py
│ │ ├── component_analyzer.py # コンポーネント解析
│ │ ├── route_analyzer.py # ルーティング解析
│ │ └── api_analyzer.py # API解析
│ │
│ ├── 📂 test_generators
│ │ ├── __init__.py
│ │ ├── 📂 page_tests # ページ単位テスト生成
│ │ │ ├── page_test_generator.py
│ │ │ ├── layout_test.py
│ │ │ ├── navigation_test.py
例.シーケンス図
sequenceDiagram
actor User
participant GUI as MainWindow
participant Scanner as ProjectScanner
participant UnitAnalyzer as TestUnitAnalyzer
participant CompAnalyzer as ComponentAnalyzer
participant Router as RouteAnalyzer
participant API as APIAnalyzer
participant MSW as MSWGenerator
participant Generator as TestGenerator
participant FileOps as FileOperations
rect rgba(255, 182, 193, 0.3)
Note right of User: プロジェクトスキャンフェーズ
User->>+GUI: 1. プロジェクトディレクトリ選択
GUI->>+Scanner: 2. プロジェクト構造解析
Scanner->>Scanner: 3. ディレクトリ構造解析
Note over Scanner: - pages/<br>- features/<br>- components/
Scanner-->>-GUI: 4. プロジェクト構造情報
end
rect rgba(176, 224, 230, 0.3)
Note right of UnitAnalyzer: テスト単位判定フェーズ
GUI->>+UnitAnalyzer: 5. テスト単位分析
UnitAnalyzer->>UnitAnalyzer: 6. ページ単位判定
Note over UnitAnalyzer: - ページコンポーネント<br>- ルート定義<br>- ページ階層
UnitAnalyzer->>UnitAnalyzer: 7. 機能単位判定
Note over UnitAnalyzer: - 独立機能<br>- 状態管理<br>- API連携
UnitAnalyzer->>UnitAnalyzer: 8. シナリオ単位判定
Note over UnitAnalyzer: - ユーザーフロー<br>- 機能連携<br>- データフロー
UnitAnalyzer-->>-GUI: 9. テスト単位リスト返却
end
シーケンス図は開発者とAI双方のコンテキスト理解を助けるねらいもあります。
3:ファイルあたりの行数は、〜200行におさめること
生成AIとやりとりして段階的にコード改善を進めていくと、あっという間に1ファイルあたりの行数が300〜500行になってきます。できるだけ1ファイルの行数を抑えファイル分割したいところです。
なぜなら1ファイルが大きいと、1回のコード修正提案のやりとりでトークン消費が大きくなってしまい、ある時点から作業効率がとても悪くなります。
対策
ファイルが大きくなってからのコード分割はタスクの難易度があがります。
大きくなる前にコード分割をしていった方がベターです。200行はあくまで目安です。
もっというと、初めのディレクトリ検討段階がとても重要です。
初期段階でファイルあたりの処理大となる可能性があるものは Utilクラスに分離しておくなどを検討しておきたいです。後からUtilに切り出すのは、フォルダ階層が変わるなどによりAIの記憶混濁がかなり起きます。
機能品質を確保しつつ保守品質の確保を並行していないと、翻って機能品質の確保も難しくなる。これはAIとのペアプロに限った話ではないですね。
AIとのペアプロにおいても 「負債解消まとめてあと回し」はアンチパターン であると言えます。ご利用は計画的に。借金はこまめに返しましょう。
まとめ
AIとペアプロする際に気をつけていることを3つご紹介しました。
これまでの経験から、AI支援によるプログラム開発における課題分析と改善策を以下にまとめます。
## AI支援によるプログラミングで陥りがちなパターン
* 開発(1ファイル、100-300行)から開始
* 初期動作確認後、コード分割(1→3ファイル)を実施
* 改善要求による肥大化(100→1000行/ファイル)
* さらなるコード分割(3→8ファイル、サブディレクトリ構成)
* 結果として以下の問題が発生:
- ライブラリ依存関係の複雑化
- ファイル間の整合性低下
- 開発者とAI双方のコンテキスト理解困難
## 改善アプローチの仮説
1.コード分割戦略の見直し
* 早期分割の推奨(1000行での分割より200行程度での分割開始)
* ディレクトリ構成の事前整理の必要性
2. 早期分割の閾値設定の検討
* ファイル分割の理想的なタイミングは150-200行が目安
* 分割判断の具体的な他の指標例:
- 単一のクラスが1つ以上の責務を持つ場合
- メソッド数が7を超える場合
- 循環的複雑度が10を超えるメソッドの存在
- 外部依存が3つ以上になる場合
3. タスク複雑度の制御
* 全体コンテキスト量の制御より、個別タスクの入力複雑度低減が効果的
* ロジック部分の結合度管理が重要:
- n:m(多対多)結合の回避
- 結合度チェックの定期的実施
- 必要に応じた予防的コード分割
今後の検討
「AIによる支援で解決可能な複雑度なのか」を、ある程度定量的に測れるようにしたいです。
開発過程における結合度制御指標や複雑度指標が示せれば、課題スクリーニング手法として以下を早期に判別可能となります。
- 解決可能な課題の識別
- 解決困難な課題の発見
さいごに
AIとペアプロする際に気をつけていることをご紹介しました。
何はともあれ。Have Fun with AI Coding!!
おまけ
AIによるコードレビューには、Github CopilotのVS Code Extension「Promptis」 が便利です。