大きなリファクタリングをClaude Codeで進める:計画ファイルで段階に分ける方法
AIを使いこなすClaudeで執筆し、GPTで自動校閲・修正しています。

結論から言うと、大きなリファクタリングは「計画ファイルをリポジトリに置き、1段階ずつ実行して、段階ごとにコミットする」形で進めるのが安全です。計画ファイルには各段階の対象・触らない範囲・完了条件・戻し方を書きます。完了条件は「テストが通る」のような曖昧な書き方ではなく、実行するコマンドと期待する結果で書きます。 こうしておくと、各段階の終わりにアプリが動く状態を保ちやすくなります。会話をリセットしたあとも、計画ファイルを読ませれば続きから再開できます。この記事では、そのための雛形と完了条件の書き方、各段階の依頼文、人が確認する点を順に示します。 なお、本文中のファイル名・コマンド・サンプルはすべて「説明用の例」で、実際のプロジェクトで動かして確かめた結果ではありません。自分の環境に合わせて置き換えてください。
なぜ一回の指示で済ませないのか
公式ドキュメントのリファクタリング手順には、変更は小さく、テストできる単位で進めるというヒントがあります。またベストプラクティスの冒頭では、Claudeに「実行して確かめる手段」を渡すことが勧められています。大きな変更を一度に頼むと、途中のどこで壊れたのか切り分けにくくなります。レビューする差分も大きくなります。
もう一つの理由は、巻き戻しの限界です。Claude Codeの/rewindはファイル編集を戻せますが、Bashコマンドだけで変更されたファイルは追跡されず、Gitなどのバージョン管理の代わりにもならないとされています。したがって、戻せる地点は自分でコミットとして作っておく必要があります。段階分けはその地点を作る作業でもあります。
手順1:まず計画だけを作らせる
最初は編集させず、調査と計画案だけを出させます。Plan Modeでは、計画を承認するまでソースコードの編集がブロックされます(対話型ターミナルでバイパス権限を有効にした場合を除きます)。起動方法はShift+Tabで切り替える、claude --permission-mode planで起動する、または依頼文の先頭に/planを付ける方法です(Plan Modeの説明)。出てきた計画はCtrl+Gで既定のテキストエディタで直接編集できます。
依頼文の例です。
src/orders/ の注文処理を、決済・在庫・通知の3つのモジュールに分離したい。
まず編集せずに調べて、次を教えてください。
1. 現在の依存関係(どのファイルがどれを呼んでいるか)
2. 既存テストが守っている範囲と、守っていない範囲
3. 各段階の末尾でアプリが動く状態を保てる、5段階以内の分割案
各段階について「対象ファイル」「触らないファイル」「完了を判定するコマンド」を挙げてください。分割案を読んで、順序や粒度を直します。ここは人の仕事です。Claudeは依存関係の洗い出しが得意でも、「今週はこの画面に触れたくない」といった事情は知らないためです。案が固まったら通常モードに戻し、次の雛形の形でファイルに保存させます。
手順2:計画ファイルの雛形
リポジトリ直下にREFACTOR_PLAN.mdなどの名前で置きます。以下は説明用の雛形です。確認コマンドは、npmを使うプロジェクトを仮定しています。
# リファクタリング計画: 注文処理を3モジュールに分離する
## ゴール / 非ゴール
- ゴール: 決済・在庫・通知を別モジュールにし、相互の直接参照をなくす
- 非ゴール: 画面の変更、DBスキーマの変更、依存パッケージの更新
## 共通ルール
- 各段階の終わりで、確認コマンドがすべて通ること
- 1段階 = 1コミット。挙動を変える修正は混ぜない
- 既存テストを削除・緩和して通さない
- 「触らない」に書いたファイルが必要になったら、変更せず進捗メモに書いて止まる
## 確認コマンド
- テスト: `npm test`
- 静的検査: `npm run lint`
- 着手前の基準: テスト 120件成功 / 0件失敗(着手前に実測して書き換える)
## 段階
### 段階1: 現状の挙動をテストで固定する
- 対象: tests/orders/ (追加のみ)
- 触らない: src/ 配下すべて
- 完了条件: 新規テストが追加され `npm test` が全件成功。src/ の差分が0行
- 戻し方: このコミットをrevert
- 状態: [ ] 未着手
### 段階2: 決済モジュールを新設し、旧コードから呼ぶ
- 対象: src/payment/(新規), src/orders/checkout.ts
- 触らない: src/inventory/, src/notify/
- 完了条件: `npm test` 全件成功。旧の決済処理は残し、新モジュールへの委譲に置き換え済み
- 戻し方: このコミットをrevert
- 状態: [ ] 未着手
### 段階3: 在庫・通知も同様に分離する
(段階2と同じ書式で記入)
### 段階4: 旧コードを削除する
- 対象: src/orders/ 内の不要になった関数
- 完了条件: `npm test` `npm run lint` 成功。旧関数名の検索結果が0件
- 状態: [ ] 未着手
## 進捗メモ
(各段階の終了時に、実行したコマンドと結果、気づいた点を追記する)「新モジュールを作って旧コードから呼び、最後に旧コードを消す」という並べ方は、動く状態を保つための編集上の提案です。公式の必須手順ではありません。
手順3:完了条件の書き方
完了条件は、第三者がコマンドを打って合否を言える形にします。
- テストが通ること、強い書き方:npm test が終了コード0で、成功件数が着手前以上、理由:件数を比べれば、テストの削除による「通過」に気づけます
- 決済処理を整理する、強い書き方:src/orders/ から決済関連の関数が消え、検索結果が0件、理由:検索コマンドで判定できます
- 壊れていないこと、強い書き方:段階1で作った挙動固定テストが成功、理由:「壊れていない」の定義が明確になります
- 余計な変更をしない、強い書き方:git diff --stat の対象が「対象」欄のファイルだけ、理由:範囲逸脱を機械的に見つけられます
書くときのコツは三つです。判定コマンドを必ず含めること。「何を変えないか」も条件にすること。最初の段階は、テスト不足の箇所を補う段階にすることです。既存テストが薄いまま構造だけ動かすと、完了条件が成り立ちません。
手順4:段階ごとの実行と人の確認
各段階の実行では、次のように依頼します。
@REFACTOR_PLAN.md を読み、状態が未着手の最初の段階だけを実行してください。
「触らない」欄と共通ルールを守ること。
終わったら確認コマンドを実行し、結果を進捗メモに追記して、状態を更新してください。
コミットはせず、私の確認を待ってください。次の段階には進まないでください。終わったら、人が次を確認します。
- git diff --statで、変更ファイルが「対象」の範囲に収まっているか
- テストファイルの差分を見て、削除や期待値の書き換えで通していないか
- 完了条件のコマンドを、自分の手でもう一度実行する
- 問題なければ自分でコミットし、新しいセッション、または/clearのあとで次の段階に進む
セッションをまたぐ場合は、claude --continueで直近の会話を再開することも、計画ファイルを読ませて新規に始めることもできます(再開の方法)。状態が計画ファイルに残っているので、どちらでも続きから始められます。
手順5:うまくいかないときの判断表
- 完了条件のコマンドが落ちた、対応:同じ段階の中で原因を直させる。3回試しても直らなければ、直前のコミットに戻して段階を分け直す
- 「触らない」ファイルの変更が必要と報告された、対応:変更を許可する前に、計画を更新するか、その段階を二つに割るかを決める
- 想定より差分が大きい、対応:実行を止めてコミット前に戻し、段階を細かく割る
- 途中で別の不具合を見つけた、対応:進捗メモに書かせるだけにして、今の段階には混ぜない
- 計画自体が間違っていた、対応:計画ファイルを先に修正し、その版をコミットしてから再開する
計画は固定の契約ではなく、作業ごとに更新する文書です。ただし変更するのは人が判断してからにします。Claudeが実行中に自分で書き換えてよいのは「状態」と「進捗メモ」だけに限ると、計画の食い違いが起きにくくなります。

