PaPoo
cover

安全にリファクタする:テストを足してから直す段取り

テストもないのに手を入れて、あとで「何が壊れたか分からない」と泣く。これ、かなりありがちな事故だ。Claude Code を使うときも同じで、いきなり大工事を頼むより、先に“壊してはいけない形”をテストで囲ってから直したほうが圧倒的に安全になる。

ここで言うのは、大規模な自動テスト体制の話ではない。まずは、今ある挙動を固定するための最小限のテストを足す。それからリファクタする。Claude Code は差分を追いながら作業できるので、この段取りと相性がいい。指示の出し方さえ間違えなければ、雑に直して戻し作業を増やすより、ずっとましだ。

筆者も最初は「どうせ小さい変更だし」と思って直し始めて、関連ファイルまで連鎖的に触ってしまい、どこで壊したか探す羽目になった。特に Claude Code に曖昧な依頼をすると、要点を広く拾おうとして diff が膨らむ。だから順番が大事だ。先にテスト、次に修正。これで迷子になりにくい。

まず押さえるべきなのは、リファクタの前に「守るべき振る舞い」を1つでもいいから言葉にすることだ。関数の入力と出力、ファイルの生成結果、表示文言、削除してよい条件。何を固定したいのかが見えれば、Claude Code にも伝えやすい。

たとえば Python なら、こんな具合に始める。

claude

Claude Code には、いきなり「きれいにして」ではなく、こう頼む。

このリポジトリをリファクタしたいです。
まずは既存の挙動を壊さないためのテストを追加してください。
対象は src/utils/slugify.py です。

今ある挙動:
- 空文字は空文字を返す
- スペースはハイフンになる
- 英字は小文字になる

実装の変更はまだしないでください。
まずテストファイルだけを足して、どのテストを追加したか説明してください。

この頼み方が効く理由は単純だ。Claude Code に「まず観察せよ」と指示できるからだ。いきなり実装を触らせると、テストを書く前にコードをいじり始めることがある。小さな変更でも、その場で直せると思って突っ込むと、後で「もともとの仕様」が曖昧になって詰まる。

テストを足す段階では、網羅しすぎないのがコツだ。全部の分岐を埋めようとすると、最初の一歩が重くなる。壊れやすいところだけ先に囲えばいい。条件分岐が多い関数なら、よく通る1ケースと、落としたくない1ケースを入れる。ファイル処理なら、空ディレクトリ、既存ファイルあり、削除対象の除外条件あたりから始める。

Claude Code への依頼も、こういう粒度がちょうどいい。

この関数のテストを追加してください。
優先度は高い順に:
1. 一番よく使う入力
2. 境界値
3. 失敗時の振る舞い

全部を一度にやらず、まず 1 と 2 だけでよいです。

ここでありがちな失敗がある。テストを書かせたのに、実行できない形で止まることだ。例えば依存モジュールの不足、モックの置き方のズレ、既存テストフレームワークとの不整合。筆者は一度、テストを増やしたつもりで実は pytest の収集対象外の場所に置いてしまい、「書いたのに走らない」状態を作った。見た目は進んでいるのに、実際は何も守れていない。これはかなりだるい。

だから、テストを足したら必ず実行までセットにする。

追加したテストを実行して、失敗しているなら原因を直してください。
実装変更はまだ最小限に留めてください。

実行コマンドも明示すると話が早い。

pytest -q

あるいはプロジェクトに合わせて、npm test でも go test ./... でもいい。Claude Code は周辺のコマンドを見て提案できるが、こちらが指定したほうがブレにくい。

テストが通ったら、ようやく本体を直す。ここでの指示は「動作を変えずに整理する」と言い切るのが重要だ。曖昧に「見通しよくして」だけだと、名前を変えたり、処理をまとめたりする過程で意図せず振る舞いが変わる。

追加したテストが通ることを前提に、実装をリファクタしてください。
やってよいことは:
- 関数の分割
- 変数名の整理
- 重複の除去
- 処理順の整理

やってはいけないこと:
- 仕様変更
- 返り値の変更
- エラー条件の追加

変更後にテストを再実行し、差分の要点を説明してください。

この「やってはいけないこと」を先に書くのが地味に効く。Claude Code は有能だが、こちらの意図がぼやけると、つい良かれと思って直しすぎる。特に古いコードを触るときは、動く範囲が広いぶん、見た目の改善と仕様変更の境目が曖昧になりがちだ。

もうひとつ大事なのは、テストを「証拠」として扱うことだ。リファクタの前後で、同じテストが通るなら、その変更は少なくとも既存の挙動を壊していない可能性が高い。もちろんテストが万能ではない。だが、何もない状態で直すよりはるかにましだ。特に Claude Code では、差分を見ながら「この行は削っていいか」を詰めていくので、テストの存在が作業の足場になる。

もし対象がファイル整理や文書作成寄りなら、考え方は同じだ。たとえば「案件フォルダ内の重複文書だけを候補として出す」「ファイル名に含まれる日付の形式は変えない」といったルールを先に小さくテスト化する。プログラムの単体テストじゃなくても、確認用の小さなチェックリストやサンプル出力を用意しておけば、Claude Code に安全な整頓を任せやすい。

ただし、何でもテストにすればいいわけではない。リファクタの前に巨大なテスト群を作ろうとすると、そこで力尽きる。まずは壊すと痛いところだけだ。画面表示の文言、削除処理、変換ロジック、ファイル名の生成。そこだけ囲う。残りは後で足せばいい。

実務で使いやすい段取りを、かなり雑に圧縮するとこうなる。

1. 既存の挙動を列挙する
2. その中から壊れたら困るものを 1〜3 個選ぶ
3. そのテストだけ追加する
4. テストを実行して通す
5. テストを守りながら実装を整理する
6. 再度テストを回す
7. 差分を読む

この順番を崩さないだけで、Claude Code の使い勝手はかなり変わる。先にテストを置くと、モデルが出してくる提案も「何を壊してはいけないか」を前提にしたものになるからだ。逆に、テストなしでいきなり直すと、レビューもやり直しも全部人間の記憶頼みになる。そりゃしんどい。

最後に、Claude Code へ投げる指示は「段階を分ける」のが正解だ。まとめて全部やらせるより、テスト追加、実行、実装修正、再実行の4段に切る。これだけで差分が小さくなり、失敗しても戻しやすくなる。リファクタは腕力ではなく手順の勝負だ。テストを足してから直す。単純だが、これを守るだけで事故率はかなり下がる。

関連 TIPS

同じ著者の記事