CodeCraft Lab

レガシーコードを安全にリファクタリングする

テストの有無に応じたリファクタリング戦略と、リスクを最小化するプロンプト設計を解説します

ふつう10分で読了
リファクタリングレガシーコードワークフロー

はじめに

レガシーコードのリファクタリングは、開発者にとって避けて通れない作業です。しかし「動いているコードを触るのが怖い」という気持ちは誰しもが持っています。Claude Codeを活用すれば、テストの有無に応じた戦略を立て、段階的かつ安全にリファクタリングを進められます。

このレシピでは、リファクタリング前の準備から差分のレビューまで、実践的な手順を解説します。

リファクタリングの鉄則

一度に大きく変えないことが最も重要です。小さな変更を積み重ね、各ステップでテストを通すことで、どの変更が問題を引き起こしたかを特定しやすくなります。

テストの有無を確認する

リファクタリングを始める前に、まず対象コードのテストカバレッジを確認しましょう。テストの有無によって、取るべきアプローチが大きく変わります。

このプロジェクトのテストカバレッジを確認して、
src/utils/legacy-processor.ts のテストが存在するか調べてください

テストがある場合の進め方

既存テストがある場合は、テストを「安全ネット」として活用できます。まずテストが通ることを確認してから、リファクタリングに着手します。

src/utils/legacy-processor.ts のテストを実行して、
現在すべてパスすることを確認してください

テストがない場合の進め方

テストがない場合は、リファクタリングの前にテストを書くことが最優先です。Claude Codeに既存の振る舞いを保証するテストを生成させましょう。

src/utils/legacy-processor.ts の現在の振る舞いを分析して、
既存の動作を保証するテストを作成してください。
エッジケースや異常系も含めてください。
自動生成テストの確認

Claude Codeが生成したテストは、必ず自分の目で確認してください。既存コードのバグをそのままテストに反映してしまう可能性があります。意図した動作かどうかを見極めることが大切です。

段階的リファクタリングの手順

コードの全体像を把握する

まずClaude Codeに対象コードを分析させ、構造と問題点を理解します。このステップではコードを変更しません。

src/utils/legacy-processor.ts を分析してください。
以下の観点でレポートしてほしい:
- 関数の責務と依存関係
- 問題点(長すぎる関数、重複コードなど)
- リファクタリングの優先度が高い箇所

リファクタリング計画を立てる

分析結果をもとに、Claude Codeに具体的な計画を立てさせます。重要なのは、一度にすべてを変えようとせず、段階的に進める計画にすることです。

先ほどの分析をもとに、リファクタリング計画を作成してください。
以下の条件で:
- 各ステップは1つの変更に絞る
- ステップごとにテストが通ることを確認できる粒度
- 外部に公開しているインターフェースは変更しない
- 変更の順序と理由を明記する

最小単位でリファクタリングを実施する

計画の最初のステップから着手します。スコープを明確に限定することで、Claude Codeの出力精度が向上します。

リファクタリング計画のステップ1を実施してください:
processData関数からバリデーションロジックを
validateInput関数として抽出する。
 
制約:
- processDataの外部インターフェースは変更しない
- 抽出後にテストを実行して全パスを確認する

差分を確認してコミットする

各ステップの変更後は、差分を確認してから次に進みます。Claude Codeに差分の要約を依頼するのも有効です。

今回の変更の差分を確認して、以下を報告してください:
- 変更されたファイルと行数
- 振る舞いが変わっていないことの確認
- 次のステップに進んで問題ないか

実践例: 200行の関数を分割する

ここでは、典型的な「やりすぎ関数」を段階的に分割する流れを紹介します。

対象コードの分析を依頼する

src/services/order-service.ts の processOrder 関数を分析してください。
200行以上ある関数で、バリデーション、在庫確認、価格計算、
注文保存、通知送信をすべて1つの関数で行っています。
 
この関数を適切な粒度に分割するリファクタリング計画を立ててください。
各ステップは独立してテスト可能な単位にしてください。

スコープを限定して段階的に実施する

processOrder関数のリファクタリング ステップ1:
バリデーションロジックをvalidateOrder関数として抽出してください。
 
条件:
- processOrderからvalidateOrderを呼び出す形にする
- 既存テストがすべてパスすることを確認する
- validateOrder単体のテストも追加する

ステップ1が完了したら、同様にステップ2以降を進めます。

processOrder関数のリファクタリング ステップ2:
在庫確認ロジックをcheckInventory関数として抽出してください。
ステップ1で抽出したvalidateOrderには触れないでください。
プロンプトでスコープを限定するコツ

「触れないでください」「変更しないでください」と明示的に書くことで、Claude Codeが意図しない範囲まで変更してしまうリスクを抑えられます。対象ファイルや関数名を具体的に指定することも効果的です。

応用テクニック

Plan Modeを活用する

大規模なリファクタリングでは、まず Plan Mode でコードを変更せずに計画を立て、計画に納得してから実装に移ると安全です。

claude --permission-mode plan

Plan Mode ではClaude Codeがファイルを読み取って計画を提案しますが、コードへの変更は行いません。計画を確認してから通常モードに切り替えて実装を進めましょう。

サブエージェントでレビューする

リファクタリング後のコードを、別のコンテキストでレビューさせることで品質を高められます。

サブエージェントを使って、今回のリファクタリングの差分をレビューしてください。
以下の観点で確認してほしい:
- 振る舞いが変わっていないか
- 新たに導入された関数の命名は適切か
- エッジケースの考慮漏れはないか

リファクタリング前後の動作を比較する

リファクタリングの安全性を担保するため、テストだけでなく実際の動作も確認しましょう。

リファクタリング前後で processOrder 関数の実行結果が
同一であることを確認するテストを書いてください。
代表的な入力パターンを5つ用意して、
出力と副作用が一致することをアサーションしてください。

まとめ

  • リファクタリング前に、まずテストの有無を確認する。テストがなければ先にテストを書く
  • 一度に大きく変えず、最小単位で段階的に進める
  • プロンプトでスコープを明確に限定し、「変更しない範囲」も指定する
  • 各ステップでテストを実行し、差分を確認してからコミットする
  • Plan Mode やサブエージェントを活用して、安全性をさらに高める