はじめに
Mars Flag Advent Calendar 2025 18日目担当の小川です。よろしくお願いします。
この記事は、以前から個人的に興味を持っていた物事を、Advent Calenderという機会において調査した記事となっていることをご了承ください。
生成AIによる記事作成
本記事は、文章作成の運転もかねて生成AIを使用しています。
調査対象
「AI使ってコード書けるらしいけど、実際どうなの?」
そう思って、Claude Codeというツールを使って小さなマイクロサービスプロジェクトでOpenTelemetryの統合をやってみました。前回の記事(小さなマイクロサービスでOpenTelemetryを試してみた)では技術的な側面を書きましたが、今回は「どうやってAIと一緒に開発したのか」を記録として残しておきます。
使ったツール:Claude Code(Anthropic公式CLI)
正直な感想:
- 「これ、一人で書いてたら何週間かかったんだろう...」
- 「AIに任せていいところ、自分で判断すべきところがわかってきた」
- 「AIとのペアプログラミングって、こういう感じなのかな」
こんな方に読んでいただけたら:
- AI駆動開発に興味がある方
- Claude Codeの実践的な使い方を知りたい方
- 「実際の現場でどう使うの?」という疑問をお持ちの方
目次
1. プロジェクトの規模感
プロジェクトの準備
まず、検証用に用意した小さなマイクロサービス(original/)をwith_otel/にコピーしてから、OpenTelemetryの統合を開始しました。
なお、ベースとなるサービス群もClaude Codeに作ってもらっています。
何を作ったのか
3つのマイクロサービス(WebAPI、Process Batch、WebCrawler API)に、OpenTelemetryを統合してみました。
実装した内容:
- ✅ 分散トレーシング(Jaeger)
- ✅ カスタムメトリクス(Prometheus)
- ✅ ログ相関(trace_id自動付与)
- ✅ ストレージ永続化(30日保持)
実装規模
コード変更: 約15ファイル
追加コード: 約800行
ドキュメント: 約3,000行(CLAUDE.md、技術資料)
ブログ記事: 約1,300行(Qiita形式、2記事)
作業期間: 3日間
「え、3日で?」 はい、Claude Codeと一緒にやったらこうなりました。
作業スタイルと実際の時間について
作業期間は3日間ですが、連続作業ではありません。Claude Proのセッションリミット(メッセージ数制限)に引っかかったり、仕事の合間に少しずつ進めたりと、断続的な作業でした。
このプロジェクトで実感したこと
🎯 未経験の技術領域でも、効率的に実装できた
OpenTelemetryという初めて触る技術で、分散トレーシングという複雑な概念の実装でしたが:
- ✅ 公式ドキュメントを何時間も読む必要がなかった
- ✅ 実装パターンを調べる時間が大幅に短縮された
- ✅ 「どう実装すればいいか」の判断をClaude Codeが担ってくれた
- ✅ ベストプラクティスを自然に学べた
2. Claude Codeって何?
基本情報
Claude Codeは、Anthropic(Claude開発元)が公式に提供するCLIツールです。
# インストール(例)
npm install -g @anthropic-ai/claude-code
# 起動
claude
3. 実際の開発の流れ
Phase 1: 分散トレーシングの実装
やりたいこと
「3つのサービスに分散トレーシングを入れたい」
実際の対話
👤 私:
「3つのサービス(webapi、process_batch、webcrawler_api)に
OpenTelemetryの分散トレーシングを追加してください。
Jaegerにデータを送信する構成で。」
🤖 Claude Code:
プロジェクト構造を確認します...
→ with_otel/配下の3サービスを検出各サービスのpyproject.tomlにOpenTelemetryパッケージを追加します...
→ opentelemetry-api, opentelemetry-sdk, etc.各サービスのmain.py/cli.pyにTracer設定を追加します...
→ TracerProvider初期化、OTLP Exporter設定自動計装を有効化します...
→ FastAPI, SQLAlchemy, HTTPXdocker-compose.ymlにJaegerとOTel Collectorを追加します...
完了しました。動作確認しますか?
かかった時間: 約15分
感想: 「え、もう終わり?」という感じでした。
何が起きたのか
Claude Codeは以下を自動でやってくれていました:
-
ファイル検索:
find_symbolで既存の設定を確認 -
パッケージ追加: 3つの
pyproject.tomlを並行編集 - コード生成: 各サービスに適した設定コードを生成
-
設定ファイル作成:
docker-compose.yml、otel-collector-config.yaml
驚いたところ:
- 各サービスの違いを理解している(FastAPI vs Click CLI)
- 既存コードを壊さない(既存のインポートを保持)
- Docker Compose の depends_on も正しく設定されている
Phase 2: 非同期処理のトレース継続
発生した問題
# テスト実行
$ curl -X POST http://localhost:8000/v1/sample_api/requests -d '{"url": "https://example.com"}'
$ docker compose run process-batch process --request-id 1
# Jaegerで確認
→ トレースが切れてる!WebAPIとProcess Batchが別のトレースになってる
対話例
👤 私:
「データベースキュー経由でトレースが切れてしまいます。
trace_idをDBに保存して、Process Batch側で復元する実装をお願いします。」
🤖 Claude Code:
問題を理解しました。HTTPヘッダーで伝播できないため、
手動でトレースコンテキストを永続化する必要がありますね。
WebAPIのリクエストモデルにtrace_id/span_idフィールドを追加...
→ Alembicマイグレーション生成WebAPIのエンドポイントでtrace_id/span_idをDBに保存...
→ create_request()を修正Process BathcでDBから取得したtrace_id/span_idを復元...
→ SpanContext復元ロジックを追加実装完了。マイグレーションを実行してテストしてください。
感想: 「マイグレーションファイルまで作ってくれるの!?」とびっくりしました。
ここで学んだこと
Claude Codeが得意なところ:
- 複数ファイルにまたがる一貫した変更
- 既存パターンの踏襲(Alembicマイグレーションの規約に従う)
- エラーハンドリングの追加
人間が判断すべきところ:
- 「DBに永続化する」というアーキテクチャの判断
- trace_id/span_idのフィールド名(命名規則)
Phase 3: Log Correlation実装
やりたいこと
「すべてのログにtrace_id/span_idを自動で付けたい」
実際の対話
👤 私:
「各アプリケーションログにtrace_id/span_idを追加してください。
pythonjsonloggerを使ってJSON構造化ログにしたいです。」
🤖 Claude Code:
Log Correlationを実装します。
各サービスにTraceContextFilterを追加...
→ logging.Filterを継承したカスタムフィルターpythonjsonloggerの設定を追加...
→ JsonFormatter設定pyproject.tomlにpythonjsonloggerを追加...
動作確認用のログを出力してテストします...
あれ、trace_id/span_idフィールドが出力されていません。
pythonjsonloggerはNone値を出力しないようです。
空文字列に修正します...完了しました。
驚いたこと:
- ❌ 一度失敗した(trace_id出力されず)
- ✅ 自分でデバッグして修正した(
None→"") - ✅ 3つのサービス全部に同じ修正を適用してくれた
エラー対応の様子
🤖 Claude Code(最初):
record.trace_id = None # トレースコンテキストがない場合
↓ テスト実行 ↓
🤖 Claude Code:
ログを確認したところ、trace_idフィールドが出力されていません。
pythonjsonloggerのドキュメントを確認します...→ pythonjsonloggerはNone値のフィールドを除外する仕様でした。
修正します:
record.trace_id = "" # 空文字列に変更→ 3つのサービスすべてに同じ修正を適用...
完了。再テストをお願いします。
感想: 「AIが自分でハマって、自分で調べて、自分で直した...!」と思いました。
Phase 4: ブログ記事の作成
やりたいこと
「この開発の経験を記事にまとめたい。でも3,000行のドキュメントを書くのは...」
実際の対話
👤 私:
「この実装の経験をQiita記事にまとめたいです。
2つの記事を書きたくて:
- OpenTelemetry実装の技術的な記事
- Claude Code使用体験の記事
「お試しで小さなサービスを作って試してみた」という
実験的なトーンで書いてください。」
🤖 Claude Code:
プロジェクトの実装履歴を確認します...
→ Phase 1〜5の実装内容を分析2つの記事の骨格を作成します...
→ blog_article_1_opentelemetry.md
→ blog_article_2_claude_code.md【記事1】技術編の構成:
- はじめに(動機)
- サービス準備
3-6. Step 1〜4(各ステップで「なぜ→何を→結果」)- 全体のまとめ
【記事2】Claude Code使用体験:
- プロジェクト規模
2-3. 実際の開発フロー(対話例付き)- 効果的な使い方
- 失敗例
完成しました。レビューをお願いします。
かかった時間: 約30分
驚いたこと
👤 私:
「もう少し謙虚で親しみやすいトーンにしたいです。
過去に書いた記事を参考に見てください:https://qiita.com/...」
🤖 Claude Code:
参考記事のスタイルを分析します...
→ ですます調、謙虚なトーン、実験的な表現2つの記事を調整します...
→ 「できる」→「できるかもしれません」
→ 「効果」→「良かったこと」
→ 「驚いたポイント」→「驚いたところ」完了しました。
学んだこと:
- ✅ 実装履歴を理解して記事構成を提案してくれる
- ✅ 参考記事のトーンを分析して真似できる
- ✅ 技術記事でも「体験」を重視した構成ができる
感想: 「記事執筆までAIに任せられるんだ...」と驚きました。
4. 効果的だった使い方
1. CLAUDE.mdでプロジェクトコンテキストを設定
プロジェクトルートに置いたCLAUDE.md:
# OpenTelemetry Implementation Project
## Paths
- **Project Root**: `claude_work/otel_prj`
- **Original**: `original/` - 変更しないでください
- **With OpenTelemetry**: `with_otel/` - こちらを変更
## Language
- Think in English, respond in Japanese
- Code comments in Japanese
## Recent Implementation
- 2025-12-07: WebCrawler API統合完了
- 2025-12-09: Log Correlation実装完了
効果:
- ✅ 毎回「original/は触らないで」と言わなくて済む
- ✅ 言語設定が一貫(思考=英語、応答=日本語)
- ✅ 進捗を記録しておくと、前回の続きがスムーズ
2. MCPサーバー(Serena)の活用
Serenaって?: コード解析に特化したMCP(Model Context Protocol)サーバー
何ができる?:
- シンボル検索(クラス、関数、変数)
- 参照検索(「このクラスはどこから呼ばれてる?」)
- ファイル構造解析
実例
👤 私:
「TraceContextFilterの実装、3つのサービスで同じになってる?」
🤖 Claude Code:
find_symbol("TraceContextFilter")で確認します...
→ webapi/app/core/logging.py
→ process_batch/app/cli.py
→ webcrawler_api/app/logging_config.py3つのファイルを比較します...
【結果】
- webapi: TraceContextFilter実装 ✅
- process_batch: TraceContextFilter実装 ✅
- webcrawler_api: TraceContextFilter実装 ✅
すべて同じロジックです。pythonjsonloggerのNone値問題も
3つとも修正済みです。
便利だと思ったところ:
- 全ファイルを読まずにシンボルだけ検索できる(トークン節約)
- 3ファイルの差分を自動で比較してくれる
- 「同じ実装か?」という質問に即答してくれる
3. 段階的な確認
良かったパターン:
👤 私:
「まず、webapi だけに実装して動作確認。
OKなら、残り2つのサービスにも同じ実装を展開してください。」
🤖 Claude Code:
了解しました。段階的に進めます。
【Step 1】 webapiに実装...
完了。動作確認をお願いします。
↓ 動作確認OK ↓
👤 私:
「OKです。残り2つにも展開してください。」
🤖 Claude Code:
【Step 2】 process_batchとwebcrawler_apiに展開...
webapiと同じパターンで実装しました。
良かったこと:
- ✅ 問題があれば早く見つかる
- ✅ 同じ間違いを3回繰り返さなくて済む
- ✅ 人間が検証するタイミングを制御できる
4. 具体的な指示
❌ あいまいな指示:
👤 私:
「ログを改善してください」
→ Claudeが何をすればいいかわからない
✅ 具体的な指示:
👤 私:
「各アプリケーションログに、OpenTelemetryのtrace_idとspan_idを
自動で付与する実装をお願いします。
pythonjsonloggerを使ってJSON構造化ログにしてください。」
→ Claudeが明確に動ける
コツ:
- What: 何をしたいか(ログにtrace_id追加)
- How: どうやって(pythonjsonlogger使用)
- Why: なぜ(ログとトレースを紐づけたい)← Claudeの理解を助ける
5. うまくいかなかったこと
1. 一度に全部やろうとした
失敗した例:
👤 私:
「3つのサービスにOpenTelemetryを追加して、
ログにtrace_idも付けて、
Prometheusメトリクスも追加して、
ストレージも永続化してください。」
🤖 Claude Code:
(大量のファイルを一気に変更)
→ 途中でエラー
→ どこまで完了したか分からない
→ ロールバックも大変
学んだこと: 一度に1つのことだけ頼む方がいい
改善後のやり方:
- まず分散トレーシングだけ → テスト
- 次にメトリクス追加 → テスト
- 次にログ相関 → テスト
- 最後に永続化 → テスト
2. コンテキストの共有忘れ
失敗した例:
👤 私:
「エラーが出ました」
🤖 Claude Code:
「どのファイルのどの行でエラーが出ましたか?
エラーメッセージを教えてください。」
→ 何度もやり取りが発生してしまう
改善後のやり方:
👤 私:
「webapi/app/main.py:42行目でエラーが出ました。
エラーメッセージ:ModuleNotFoundError: No module named 'pythonjsonlogger'原因を調べて修正してください。」
🤖 Claude Code:
pythonjsonloggerがインストールされていないようです。
pyproject.tomlに追加して、uv lockを実行します...
心がけていること:
- エラーメッセージは全文コピペする
- ファイル名と行番号を明記する
- 関連するログも一緒に送る
3. 「original/を触らないで」を忘れた
失敗した例:
🤖 Claude Code:
original/webapi/app/main.py を修正しました...
👤 私:
「あ!!! original/ は触らないでって言ったのに...」
対策: CLAUDE.mdに明記する
## Paths
- **Original**: `original/` - ⚠️ 絶対に変更しないでください
- **With OpenTelemetry**: `with_otel/` - こちらを変更してください
これを書いてから、間違いがなくなりました。
6. 数値で見る効果
開発時間の比較(推定)
| タスク | 一人で実装(推定) | Claude Code使用 | 短縮率 |
|---|---|---|---|
| 分散トレーシング基本実装 | 6時間 | 30分 | 12倍 |
| 非同期トレース継続 | 5時間 | 20分 | 15倍 |
| Log Correlation | 2.5時間 | 15分 | 10倍 |
| ストレージ永続化 | 1.5時間 | 10分 | 9倍 |
| ドキュメント作成 | 4時間 | 30分 | 8倍 |
| ブログ記事作成(1,300行×2本) | 5時間 | 30分 | 10倍 |
| 合計 | 24時間 | 2.2時間 | 約11倍 |
計算根拠:
- 一人で実装: 調査、実装、テスト、ドキュメント化の合計
- Claude Code使用: 実際にかかった時間(対話 + 動作確認)
- デバッグ時間は含まず(両方とも発生)
特に調査時間の短縮効果が大きい:
- OpenTelemetryの公式ドキュメントを読む時間
- 実装パターンを調べる時間
- ベストプラクティスを探す時間
- 「どう実装すればいいか」を考える時間
→ Claude Codeがこれらの調査・判断を担ってくれることで、未経験の技術領域でも効率的に実装できる
時間短縮の内訳
一人で実装した場合の想定: 約24時間
- 調査時間が特に長い(OpenTelemetryドキュメント理解、実装パターン調査)
- 実装、テスト、ドキュメント化
Claude Code使用: 約2.2時間
- 調査・判断をClaude Codeが担当
- 人間は指示と確認に集中
節約できた時間: 約21.8時間 ≒ 約3営業日分
コード品質
Claude Codeが生成したコード:
- ✅ PEP 8準拠(Ruffでチェック済み)
- ✅ 型ヒント付き
- ✅ Docstring完備(日本語)
- ✅ エラーハンドリング適切
- ✅ テストが通る
人間がレビューで修正した箇所:
- 変数名を2箇所変更(ビジネスロジックに合わせて)
- コメントを3箇所追加(チーム規約に合わせて)
ほぼそのまま使えるレベルでした。
7. AI駆動開発の懸念点
効率化の代償:学びの機会が減る?
今回、Claude Codeを使ってOpenTelemetryを導入してみて、非常に良い成果物が得られました。まとまったドキュメントもできたし、動くコードもある。でも、正直に言うと「あれ、やりたいこと/できあがったものはあるんだけど、自分はどれだけ中身を理解できてるんだろう?」という疑問も残りました。
手を動かす vs AIに任せる
もし自分一人でやっていたら:
1. 公式ドキュメントを読む
↓ 「あれ、これどういう意味?」
2. 試しに実装してみる
↓ エラーが出る
3. Stack Overflowを漁る
↓ 「なるほど、こういうことか」
4. やっと動いた!
↓ 「次は同じミスしないぞ」
この突っかかって解決した経験が、次の開発に活きるんですよね。
Claude Codeと一緒にやった場合:
1. 「OpenTelemetry追加して」
↓ Claude Codeがスマートに実装
2. 「あ、動いた」
↓ ...で、次は?
あまりにスムーズすぎて、「あたりの付け所」が身につかない気がします。
具体例:トレースコンテキストの伝播
今回、データベースキュー経由でトレースコンテキストを伝播させる実装がありました。
Claude Codeが提示したコード:
# SpanContextを復元
span_context = SpanContext(
trace_id=int(work_item.trace_id, 16),
span_id=int(work_item.span_id, 16),
is_remote=True,
trace_flags=TraceFlags(0x01), # sampled
)
これ、正直言うとなぜこうなるのか、完全には理解していません。
もし自分で実装していたら:
- 「
trace_flagsって何?」 - 「
0x01ってどういう意味?」 - 「
is_remoteはなぜTrue?」
こういう疑問に突き当たって、ドキュメントを読んで、試行錯誤して...という過程で理解が深まるはずです。
次に同じことをやるとき
心配なこと:
- また1から調べ直す羽目になりそう
- 応用が効かないかもしれない
- トラブルシューティングできないかも
一方で:
- 動くコードは手元にある
- ドキュメントも整備されている
- 時間は圧倒的に短縮された
どうバランスを取るか?
今回の経験から考えた対策:
-
AIが書いたコードを「教材」として読み直す
- 後で時間を取って、一行ずつ理解する
- 公式ドキュメントと照らし合わせる
-
「なぜ?」を意識的に残す
- Claude Codeに「なぜこうするのか説明して」と聞く
- コメントで理由を書いてもらう
-
小さな変更は自分でやる
- 全部AIに任せない
- 一部は手動で試してみる
-
次のプロジェクトで実践する
- 同じような実装を、今度は自分でやってみる
- AIのコードを参考にしながら
正直な感想
効率は最高だけど、学ぶ機会が減ってしまう
これが今回の率直な感想です。ビジネス的には大成功だけど、エンジニアとしての成長という観点では、問題解決の経験が少なくなってしまったかなと。普段使っているGitHub Copilotで部分的に助けてもらう方が、全体設計は自分で考えるので学びが残る気がします。
ただ、これは使い方次第だと思います。
- 納期優先のプロジェクト → AI全開でOK
- 技術習得が目的 → AIは補助的に
使い分けが大事ですね。
学習とAIのジレンマ
初学者がAIに頼りすぎると、基礎が身につかないリスクがあります。一方で、AIを使わないと時代に取り残される。このバランスをどう取るかは、これからのエンジニアの課題かもしれません。
8. まとめ
やってみてわかったこと
✅ Claude Codeが得意なところ:
- 複数ファイルをまたいだ一貫した変更
- ボイラープレートコードの生成
- パターンの踏襲(既存コードのスタイルを真似る)
- ドキュメント生成
❌ Claude Codeが苦手なところ:
- アーキテクチャの意思決定(人間が判断すべき)
- ビジネスロジックの詳細(ドメイン知識が必要)
- 完全に新しいパターンの創造
効果的な使い方(まとめ)
-
CLAUDE.mdでプロジェクトコンテキストを設定する
- パス構造、命名規則、注意事項を明記しておく
-
段階的に進める
- 一度に1つのタスクだけ
- 各ステップで動作確認する
-
具体的に指示する
- What(何を)、How(どうやって)、Why(なぜ)を伝える
-
MCPサーバーを活用する
- Serenaでシンボル検索できる
- トークン節約、高速化につながる
-
人間が最終判断する
- アーキテクチャ
- 命名
- ビジネスロジック
実際に試してみたこと
このプロジェクトで実践できたこと:
- ✅ テストコードの動作確認 - 既存テスト(46個)がOpenTelemetry追加後も全てパス
- ✅ 複数サービスの一貫した実装 - 3つのサービスに同じパターンで計装
- ✅ データベースマイグレーション - trace_id/span_idフィールド追加
- ✅ エンドツーエンドの動作確認 - Jaegerでトレース検証
- ✅ カスタムメトリクスの実装 - Histogram(処理時間)とCounter(処理件数)
次に試してみたいこと:
- リファクタリングの提案
- セキュリティ脆弱性のチェック
- 大規模なコードベースでの活用
参考リソース
最後まで読んでいただき、ありがとうございました!
「Claude Code、使ってみたいけど実際どうなの?」という疑問に、少しでも答えられていたら嬉しいです。
実際に使ってみて、「AI駆動開発」が単なる流行語ではなく、実用的なペアプログラミング相手になるかもしれないと感じました。
ちなみに
この記事自体も、Claude Codeに「実装経験をQiita記事にまとめて」と頼んで作成しました。
実装履歴を理解して、構成を提案して、参考記事のトーンを真似て...という一連の流れを、
AIと一緒にできたのは新鮮な体験でした。
関連記事: