はじめに
2026年2月、The Unwritten Algorithm(Dev Genius)がある体験談を公開した。
「私はAIにレガシーコードベース全体のリファクタリングを任せた。コードは美しくなった。しかし私たちが数週間後に発見した127個のバグは、AIがコードがなぜ醜いのかを理解していなかったことを示していた。」
何が起きたか。synchronized ブロックを「不要な複雑さ」として削除した結果、本番環境で二重決済とレースコンディションが発生した。冗長に見えたnullチェックを除去した結果、エッジケースでNullPointerExceptionが発生した。「クリーンなリファクタリング」がセキュリティ脆弱性を導入した。しかもAI支援を受けた開発者がコードに過剰な自信を持ち、レビューが甘くなってしまった(127バグの事例より「過信バイアス」と呼ばれる問題だ)。
AIはコードの「外見的な醜さ」は理解できる。しかし「なぜそう書かれているか」というビジネスロジックと歴史的背景は理解できない。
この記事では、この失敗を反面教師にしながら「一括書き換え」ではなく「インクリメンタルなモダナイゼーション」という正しいアプローチを解説する。
技術的負債の現実——Claude Codeが公式に対応を明記
McKinseyのレポートでは、開発者が業務時間の相当部分を技術的負債への対応に費やしていることが示されている。この問題をAnthropicも重く見ており、Claude Codeの公式ソリューションページ(claude.com/solutions/code-modernization)でCode modernizationをユースケースとして明記している。
レガシーコードを触るときに毎回感じるのは、「コードが古い」こと自体よりも、「変更が怖い」という感覚だ。テストがない、依存関係が分からない、変更コストが高い——この3つが揃うと、誰も手を入れようとしなくなる。
なぜ「一括書き換え」は失敗するか
冒頭の127バグ事例が示した通り、一括書き換えには構造的な問題がある。
❌ 危険なアプローチ(ビッグバン方式)
「このモジュール全体をモダンなコードに書き直して」
↓
コンテキスト不足 → ビジネスロジックの消失
テストなし → 動作確認不能
一度に大量変更 → レビュー不能
Anthropic公式ドキュメント(Common Workflows)が推奨するのはインクリメンタル戦略だ。理解フェーズ(依存関係・アーキテクチャを先にマッピング)→テスト生成フェーズ(挙動を保護するテストをリファクタリング前に自動生成)→分割リファクタリング(モジュール単位で1つずつ変更・検証)→統合検証(旧コードと新コードの共存期間を設ける)という順序だ。
Claude Code固有の機能:レガシー対応ツールセット
コードベースナビゲーション——「なぜそう書かれているか」を推定する
レガシーコードベースで最初にすべきことはClaude Codeへの「全体を教えてくれ」だ。
「このリポジトリの主要なモジュールと依存関係を説明して。
特にUserAuthモジュールが何と連携しているかを重点的に」
Claude Codeは git blame・コメント・コミット履歴から「なぜそうなっているか」を推定できる。新人エンジニアがClaude Codeを使ってコードベース全体を把握するユースケースが増えており、従来のConfluence等のドキュメントツールを置き換える形での活用が報告されている。
/techdebt カスタムコマンド——技術的負債を計測から始める
注意:
/techdebtはClaude Codeの組み込みコマンドではない。.claude/commands/techdebt.mdにプロンプトを定義することでチームが自作するカスタムスキルのパターンだ。
# .claude/commands/techdebt.md に定義
「このセッションで触ったコードで重複・死んでいる・命名が不適切なものを
列挙して、優先度をつけてGitHub Issues形式で出力して」
セッション終了時にこのコマンドを実行することで、技術的負債を自動検出してGitHub Issuesに整理できる。「議論から推測ではなく、計測から始める」アプローチだ。APIエンドポイントのレビュー結果をGitHub Issuesに自動作成した実践報告がある。
依存関係マッピング——「どこから始めるか」を特定する
「UserServiceクラスの依存関係を全て洗い出して。
循環依存があれば特に強調して。
Mermaid記法でダイアグラムを生成して」
Claude Codeはデッドコード(参照されていないクラス・関数)、高結合度モジュール(変更時の影響範囲が広い)、循環依存(リファクタリングの優先ターゲット)を依存グラフ分析で特定できる。
挙動保護テストの自動生成——リファクタリング前の「保険」
「PaymentProcessorクラスをリファクタリングする前に、
現在の挙動を全てカバーするテストを生成して。
エッジケース(null入力・タイムアウト・並列実行)も含めること」
テストを「リファクタリング後」ではなく「前」に生成することが重要だ。変更によって何かが壊れた場合に即座に検出できる。127バグ事例の根本原因の一つは、テストなしで大規模変更を行ったことにある。
安全なリファクタリングの実施手順
Step 1: 影響範囲の事前評価
「OrderServiceのrefundメソッドを変更する前に、
この変更が影響しうるファイル・テスト・サービスをリストアップして。
『Blast-Radius Report』形式でまとめて」
事前に影響範囲を把握することで、思わぬ副作用を防げる。「Blast-Radius Report」という名前でCLAUDE.mdに定義しておくと、リファクタリングの標準プロセスにしやすい。
Step 2: 小さく変更・即座に検証
❌ 避けるべき
「UserModule全体をリファクタリングして」(1,000行の一括変更)
✓ 推奨
「UserModuleのvalidateEmail関数だけ、まずリファクタリングして」
→ テスト実行 → 動作確認 → 次の関数へ
1PR・1関数・1モジュールを原則にすることで、問題が発生しても影響範囲を限定できる。
Step 3: セキュリティリグレッションの確認
「リファクタリング後のコードを、セキュリティの観点でレビューして。
特にSQL injection・認証バイパス・null dereference の観点で」
127バグ事例で発生したセキュリティリグレッションは、この確認ステップがなかったことが原因だ。過信バイアス(AI支援を受けた開発者がコードに過剰な自信を持つ傾向)を意識的に打ち消すプロセスとして組み込む。
EMの視点:チームへの展開計画
段階的な導入が安全だ。
| フェーズ | 内容 | 期間 |
|---|---|---|
| Phase 1 | コードベースナビゲーションのみ(読むだけ) | 1週間 |
| Phase 2 | テスト生成(書くが本番コードは変えない) | 1〜2週間 |
| Phase 3 | 低リスクモジュールのリファクタリング(ユーティリティ関数等) | 2週間〜 |
| Phase 4 | コアビジネスロジックのリファクタリング(PRレビュー必須) | 要計画 |
チームで合意すべきルールも3つある。「AIを信頼しすぎない」ルール(AIが「冗長に見えるコード」を消したがっても業務背景を確認してから削除する)、「テスト先行」ルール(リファクタリング前にテストカバレッジが閾値を超えていることを必須条件にする)、「小さいPR」ルール(Claude Code起因のリファクタリングPRは200行以内を推奨)だ。
Before/After
Before(一括アプローチ)
「このモジュール全体をリファクタリングして」
↓
AIが全体を書き直す
↓
テストなし → 動作確認できない
ビジネスロジック消失 → 127個のバグ
チームがレビューできない → LGTM連発
↓
本番障害
After(インクリメンタルアプローチ)
依存関係マッピング → 「どこから始めるか」を特定
↓
テスト生成 → 挙動を保護
↓
1関数ずつリファクタリング → 即検証
↓
Blast-Radius Report → 影響範囲を事前把握
↓
セキュリティレビュー → リグレッションなし確認
↓
安全に技術的負債を削減
まとめ
冒頭の127バグ事例を読んで「やっぱりAIは使えない」と思った人もいるかもしれないが、失敗の原因は「一括で任せたこと」にある。インクリメンタルに、テストを先に生成して、1モジュール1機能ずつ進めれば、Claude Codeはレガシーコードの改善に確実に役立つ。
まず何をするかで迷ったら、この順番で動いてみてほしい。
今すぐ(5分):最も変更コストが高いモジュールを1つ選び、Claude Codeに依存関係マッピングを依頼する。Mermaid記法でダイアグラムを生成させると、依存関係が一目で分かる。
今日中:そのモジュールのテストカバレッジをClaude Codeに確認させ、不足している箇所を特定する。テストが十分にあれば、次の作業への安心感が格段に上がる。
チーム展開:「AIリファクタリングPRは200行以内」というルールをチームで合意し、Blast-Radius Reportをリファクタリングの標準プロセスに組み込む。過信バイアスを防ぐ構造を作ることが、AIを安全に活用するための土台だ。

コメント