私とコーディングエージェントの現在地
2025年はCline/Devinブームから始まり、Claude Code、Gemini CLI、Codex CLIなどの様々なコーディングエージェントが登場、加えてモデル自体の進化も進み、Webアプリケーション開発の現場では使うのが当たり前になるくらい実用的なレベルになりました。
特に直近半年は私自身もコーディングエージェントを作り、実践の中で試行錯誤を繰り返しながら活用方法や安全性などの考慮すべき点を模索してきました。 結果、最近の案件ではコミットしたコードのうち約60%(変更行数ベース)がエージェントを利用したものとなっており、ようやく活用できるようになったと実感し始めています。
このようなタイミングで、さらにこの先の理想状態を想像するためにも現状を整理しようと思います。
Table of Contents
Background
コーディングエージェントの活用のしやすさは、関わるプロジェクトの性質や役割にも影響を受けると思うので、後で読み返したときに思い出せるよう今の状況を書き残しておこうと思います。
- 関わっているプロダクト: 海外ツアーやホテルの予約サイトで、システムの要素としては旅行者が旅行商品を予約するアプリ(ネイティブ、Web)、旅行商品管理(商品の入稿や値付け)や顧客・予約管理(手配業務など)をするための旅行管理システムの2つがあります。
- 私の担当領域・ドメイン特性: 主に旅行商品や顧客・予約管理のための旅行管理システムを担当。例えば、商品バリエーションの拡充やフライトやホテルの手配を自動化するために、複数のサププライヤーと在庫料金や予約情報をやり取りする仕組みを構築、拡張しています。サププライヤーごとに機能やキャンセルポリシー、お作法などの違いがあり、それらを自社商品であるパッケージツアーとして統合するのが難しいポイントです。
- 技術特性:
- 言語はBackend/FrontendともにTypeScript、API InterfaceはGraphQL、旅行管理システムのUIはNext.js+コンポーネントライブラリ(自分でコンポーネントを書くことはほぼない)
- 在庫料金情報の定期的なリフレッシュ、イベントトリガーでの手配処理などBackendでやることが多く、コードベースはBackendの方が大きい。
- システム規模(参考値)
- 開発期間は約3年、初期は2,3人でスタート、現在は10名ほどのエンジニアが関わっています
- APIのTypeScriptのソースファイルが数千件、合計数十万行
- メインで利用しているリレーショナルデータベースのテーブル数は数百
できていること
🔍️ 既存実装の調査
コーディングエージェントを触り初めた当初、最も活用したのが既存のコード構成の調査です。 数年掛けて作り上げたシステムは自分が担当した機能に関しても記憶が薄れていきますし、開発メンバー/開発の並列度が増えて自分が知らない部分も増えてきました。 当然そのような状況では、これから改修する部分とその影響範囲の現状把握に多くの時間を取られることになります。 例えばですが「xxx.tsの関数xxxはどのエンドポイントから呼ばれている?呼び出し階層や呼び出される条件をツリー形式でまとめて欲しい」(呼び出し階層が深く分岐も多くてコードを追うのが大変な部分)、 「予約関連のエンドポイントがどのような順序・依存関係で呼ばれるかをGraphQLのschemaをヒントに調査して欲しい」(複数エンドポイントにまたがるフロー、なにかしらパラメーターをリレーすることをヒントに依存関係を追わせる)というように、愚直にコードを読んで依存関係を調査・レポートしてもらう、という使い方です。
💬 命名の壁打ち
必要なエンドポイントやQueueの役割を私の方でまとめたうえで、その命名の候補をあげてもらう、という使い方です。 悔しいことに私よりも英語の言葉選びが上手なので簡潔でわかりやすい名前を考えてくれます。 ソフトウェアを一定期間運用していると、作った当初には想定しなかったユースケースが増えたり、ドメインへの理解が深まることで当初の命名が適切でなかったことに気づき後悔することが多々あります。※ エージェントが書いたコードはまだ運用期間が短いのでその良し悪しはまだ分からないこともあります。 気軽に相談できる命名の壁打ち相手ができたことで、こういった誤りも減らせると良いですね。
🔄 Input/Outputが明確な数百行程度の関数の実装とテスト
関数のInput/Outputの型定義を私の方で書き、関数の役割や考慮ポイントを説明したうえで、実装と自動テストを書いてもらう、という使い方です。 完成度100%とはいかず不要なエラーハンドリングや可読性の悪さは残りますが、大枠は外しません。 必要な関数やクラスは私の方で整理して、関数レベルでまずは動くものを書いてもらう → テストケースを確認して、境界値など考慮できてないポイントがあればテストケースを追加してもらう/内容の重複した無駄なテストは消す → 最終的に私の方でレビューしながら無駄な分岐やネスト、意味の薄いコメントを削除して可読性を改善する、という流れで完成させます。
🧹 リファクタリング
多くの呼び出し箇所から参照されている関数のInterface変更や同じような計算処理の共通化など、機械的な書き換えと自動テストで結果を検証できるものは任せることができます。
🚀 実装の並列化
コーディングエージェントを利用した開発において、私がやることはコード構成(関数やクラス)の整理までになり、そこから先はコーディングエージェントが「大枠を外さない」粒度で実装を委託、フィードバックを通してテストケースの補強やリファクタを繰り返して完成度を高める、という流れになります。 エージェントが実装している間は私の手が空くので、その間に別ブランチで依存しない別の関数や別案件の開発を進めることができます。
ただし、アウトプットの最終調整が必要なので、それ以上に同時に動かしても自分がボトルネックになります。 また、よくある話だと思いますが、どんなに考えて設計しても実装を通して理解が深まることで設計の問題が顕在化し、設計を見直さなければならないことがあります。(最悪のケースでは仕様レベルでの検討が必要になることもある) そう考えると、今見えている仕様と設計が100%正しいと仮定してエージェントに委託できる粒度に分解できたとしても、それを高い並列度で実装するのはあまり現実感がありません。 割り切って進めることもできなくはないと思いますが、長期的な安定性や拡張性を見据えた再設計のチャンスを潰すことになると考えてます。
💡 幸いなことに、データベースを利用した自動テストをCI環境で並列実行するために、コア数分のデータベースをセットアップするスクリプトがありました。これを流用してデータベースのコンテナは一つ、git worktreeごとにデータベースを割り当てることで、データベースが必要なテストを干渉なく効率よく並列で実行できる環境を構築できました。
📺 既製コンポーネントを組み合わせたUIの実装
コンポーネントライブラリを組み合わせで作っているような画面は、使って欲しいコンポーネントと似たような画面の実装を渡すことでうまく実装してくれます。 まずはAPIとは接続せずに、見た目と入力バリデーションやモーダル開閉などの挙動のみを実装 → APIと接続 → 最終的には私が動作確認して完成させる、という流れになります。 APIの実装では自動テストでフィードバックを得て修正してもらえますが、UIの自動テストはこれまで整備してこなかったため、TypeScriptの型チェックやLinterによる検証までしか実現できていません。
できてないこと(試せてないこと)
⛰️ 複数のサービスの連携やAPIエンドポイントをまたぐようなフローなど、比較的抽象度の高い設計
システムの規模が大きくなると既存機能への影響など考慮すべき事項も多くなり、エージェントに渡すコンテキストを準備するのに時間が掛かるようになります。 仕様ドキュメントをもとにエージェントにシステム設計をしてもらおうとプレーンテキストで仕様や制約事項を整理してみましたが、その過程でシステムとしてのあるべき姿が見えてきてエージェントに依頼する必要がないという状態になってしまいました。(仕様のプレーンテキスト管理はその後の実装時にコンテキストして渡しやすいのでやって良かったと思います) 今後の開発案件では、設計のレビューや壁打ち相手として設計の質を高める目的で試してみようと考えています。
🗂️ 内部のコンポーネント構成の設計(関数やクラス)
現在のコーディングエージェントの能力では、自動テストで検証可能な数百行サイズのコンポーネントに分割すれば「大枠を外さない」ことは感覚的に分かっています。 コンポーネント分割の際には、人にとっての認知のしやすさ(抽象度の一貫性など)や再利用性、Interfaceの普遍性(後で実装だけ最適化できるなど)を大事にしていますが、 (今始めて言語化したかもしれない)これがうまく伝えられず無駄に複雑なInterfaceを生成するようなことが何度か発生しました。 現時点では、自分でざっくりとInterfaceだけ書いてみて納得感を持てたらあとは実装を委託する、というやり方がうまく機能してます。
👷 運用作業
エラーログの調査や機能に対する問い合わせなど、まだまだエージェントにお任せできそうな仕事が多数あります。これからの取り組むべき重要な課題の一つです。 アプリケーションログやデータベース、ソースコードへのアクセス権限を安全に渡せるか、必要なコンテキストを効果的に渡せるかが重要なポイントになると考えています。
コーディングエージェントとサンドボックス環境
いくつか理由があり、コーディングエージェントとサンドボックス環境は自分で作ったものを利用しています。 モデルプロバイダーはAnthropic、Gemini、OpenAI、xAIをサポートしています。 1ヶ月後にどうなっているかはわかりませんが今はコストと性能のバランスからGPT-5のみを利用しています。
学習機会として
すでに様々なプロダクトでLLMを利用した機能が実装され始めています。 できるだけ生のモデルに触れることでプロバイダーごとの違いや、プロンプトのコツ、性能の限界、コストのコントロール方法を知り、プロダクト機能の開発に活かせるようになると考えています。
コスト
各社改善が進み現状は変わっているかもしれませんが、以前Clineを試した際、巨大なファイルの中身をすべて読んでしまい無駄コンテキストを消費する動きが気になりました。 私のエージェントではコマンドの出力が大きすぎる場合はファイルに書き出して、部分的に読む工夫をしています。
既製品のベースプロンプトに関して、私が依頼する仕事内容に対して無駄な指示が多いことも気になるポイントで、自分自身で必要十分なプロンプトに調整したいと考えていました。 世の中の様々なユースケースを考慮したメタプロンプトのようなものになるので肥大化することは当然ですが、1ターンあたり数円~十円(Claude Codeの例)程度でも日常的に何度もやり取りすることになるので少しでも安く抑えたいものです。 ※ 定額のサブスクリプションでも結局は使用量の上限が設定されるので、トークン数を抑えたいのは変わらないと思います。
安全性とパフォーマンスの両立
コーディングエージェントの使い方は様々ですが、自律的に実装と検証のイテレーションを繰り返してもらう、その間私は別の仕事を進められる状態が理想です。 これを実現するためには、仮にエージェントが暴走してもプロダクション環境の破壊やセンシティブな情報の流出が起きないレベルの安全性が必要と考えています。
各社安全性に関しては様々な工夫を凝らしているものの、正しく権限設定することが難しく、常に予期せぬ抜け道がある前提でファイルアクセスやネットワークを制限するサンドボックス環境の利用は必須です。
参考: コーディングエージェントとセキュリティ - 社内勉強会でシェアした内容です
Claude Codeではdevcontainerの利用を推奨していますが、すべてをdocker container内でやろうとするとLinterやTypeScriptの型チェックが2倍ほど遅くなり、 docker環境 (colima) の設定値やvolume、mountオプションの見直しをしましたが解決できませんでした。
Codex CLIではApple Seatbeltベースのサンドボックスが利用できますが、ネットワーク全体をON/OFFする粒度の設定で、ONにすればサンドボックスの意味はなく、OFFにしたらテスト実行中にローカルのDBに接続できず、私のユースケースにはマッチしません。 サンドボックスがコーディングエージェントに組み込まれていることで、ツールごとに設定を見直すのも煩わしいポイントです。
そこで、dockerベースのサンドボックスコマンドを自分で作ることにしました。 デフォルトではカレントディレクトリ配下をRead-onlyでマウントするのみで、明示的に許可した場合のみ書き込みやネットワークアクセスが可能になります。 ネットワークはドメイン or アドレス、ポートの指定が可能です。 意図としては、例えばcloud sql proxyのようなものを利用して、チーム共用の開発環境のDBにつなぐユースケースがあるとします。 そんなときに、たとえローカルホストでもアクセスされたくないと考えてポートレベルで指定可能、指定しなければデフォルトで443のみ許可します。
agent-sandbox --dockerfile Dockerfile --allow-write --allow-net registry.npmjs.org npm install
コーディングエージェントではコマンド単位でサンドボックス環境で動かすか、そのまま動かすかを設定可能です。 コンテナ環境では時間がかかってしまう(かつ、安全な)コマンドをそのまま動かしたり、npm installを実行するときだけnpm registryへのアクセスを許可するなどの細かな制御が可能です。 ※ もちろん、エージェントが暴走してpackagen.jsonのscriptに危険な操作を埋め込まないように、別途自動承認の設定は気をつける必要があります
{
"sandbox": {
"command": "agent-sandbox",
"args": ["--dockerfile", ".agent/sandbox/Dockerfile", "--allow-write", "--skip-build"],
"rules": [
// 特定のコマンドは直接実行したい ※ 自動承認の設定は別
{
"pattern": {
"command": ["npm"],
"args": ["run", "check"]
},
"mode": "unsandboxed"
},
// ネットワークアクセスを許可する(ポートを指定しない場合は443のみ許可)
{
"pattern": {
"command": "npm",
"args": ["install"]
},
"mode": "sandbox",
"extraArgs": ["--allow-net", "registry.npmjs.org"]
}
// ルールに一致しない場合はサンドボックス環境で実行
]
}
}
チーム開発における活用
CLAUDE.md
最近はAGENT.mdに統一しようという動きにありますが、所属する開発チームではClaude Codeを使うメンバーが多くCLAUDE.mdがもっともメンテナンスされています。 中にはコーディング規約(表層的なスタイル、ディレクトリ構成、自動テストのポリシーなど)やドメイン(予約、ツアーなど)ごとのモジュールの構成について記載されています。
私のエージェントからはこのような指示をベースプロンプトをいれることで読み込ませています。 プロジェクト配下のmarkdownファイルをリストアップして、エージェント向けの指示があればそれを読む、なければREADMEを読む、という指示です。
## Project Knowledge Discovery
When working with project files, gather project-specific knowledge.
Follow these steps in the exact order below:
1. List documentation files: exec_command { command: "fd", args: ["--extension", "md", "--hidden", "--max-depth", "3"] }
- Limit depth when listing documentation.
2. Read agent prompt files:
2-1. First, read AGENTS.md, AGENTS.local.md in project root for project-wide context.
2-2. Then, read AGENTS.md at all task-relevant hierarchy levels in sequence - When working with foo/bar/baz, read foo/AGENTS.md for broader context, then foo/bar/baz/AGENTS.md for specific context.
2-3. If no AGENTS.md files are found, read CLAUDE.md files at all task-relevant hierarchy levels instead.
2-4. If no CLAUDE.md files are found, read the equivalent files in .clinerules or .cursor/rules directories instead.
2-5. As a final fallback, read README.md files at all task-relevant hierarchy levels.
3. Read task-relevant files:
3-1. Files referenced in the agent prompt files.
3-2. Any other files that relate to the task.
コードレビュー
CLAUDE.mdの内容をもとにコードレビューをしてくれるGitHub Actions Workflow (Claude Code Action)を同僚が作ってくれました。 プロジェクト固有のコーディング規約に関しては人間よりも網羅的にチェックでき、人間のレビュアーは可読性や仕様の理解と正しさの確認に集中することができます。 ただ、的はずれな指摘も多く、継続的なチューニングが必要です。
活用レベルのモニタリング
活用レベルの指標として何か可視化できないかと考え、コミットログからLLMを使って修正したコード行数を計測できるようにしています。 エージェントで生成したコードはメッセージにCo-authoredを付けて、それをヒントの計測する、という方法です。 もちろんコードの行数なんてものはただ測りやすいからみているだけの参考値であって、行数は行数でしかなくて、生み出した価値ではありません。
将来的には、全員が当たり前にほとんどのコードを生成できる世界になれば計測する意味は薄れてくるでしょう。 最近流行り初めたCodex CLIはコミットメッセージにCo-authoredを入れてくれませんし、機能として実装されることもなさそうです。
Co-authoredをマニュアルで付けるのは、たとえシェルの関数などを活用しても一定の煩わしさは残るので、何か別の手段で定量モニタリングできるならばコミットログの運用はやめたいと思ってます。
参考
- agent - コーディングエージェントの実装
- agent-sandbox - dockerベースのサンドボックスコマンドの実装