09-02. ケース 2: 反復的なリファクタリングの自動化
シチュエーション
コードベース内の 同じパターン(古い API 呼び出し → 新しいもの、命名規約変更、型注釈追加など)を 50 ファイル超 に渡って適用したい。
例:
- from old_module import X を from new_module import X に
- すべてのテスト関数に @pytest.mark.unit デコレータを追加
- print(...) を logger.info(...) に置換(ただし context 依存で残すべき箇所もある)Before (Claude Code を使わない場合)
- sed/awk で機械置換 → エッジケースで壊れる(コメント内、文字列内、import の順序)
- 手動で 1 ファイルずつ → 集中力が持たない、ヒューマンエラー
- テストを毎回回す → サイクルが長い
- 数日かかる、レビューも疲れる
After (Claude Code を使う場合)
Claude に「3 段階」で頼む:
1. 該当箇所を全部リスト化させる
2. 1 ファイルだけ変更してテストを通す(パイロット)
3. 残りを順次変更、各 commit で必ずテスト
→ 30 分〜数時間で完了、テスト保証付き。必要な道具立て
| 機能 |
何のために |
| CLAUDE.md |
テスト・ビルドコマンド明記 (make test, pytest) |
| Hook: PostToolUse (Edit/Write 後) |
自動で pytest -x を走らせ、失敗したら次の編集をブロック |
| Skill: refactor-pattern |
リファクタの手順を Claude に守らせる |
CLAUDE.md 必須セクション例
## テストとリンタ
- すべての変更後: `pytest -x` (失敗したら止まる)
- 型チェック: `mypy src/`
- フォーマッタ: `ruff format`
## このリポジトリのリファクタ規約
- 1 commit = 1 リファクタタイプ。混ぜない
- import の順序は isort 規約
- print → logger 置換時、テストコード内の print は対象外
Hook 設定 (.claude/settings.json)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "pytest -x --quiet 2>&1 | tail -20; if [ $? -ne 0 ]; then echo 'TESTS FAILED — stop and review' >&2; exit 2; fi"
}
]
}
]
}
}
→ Edit のたびにテスト、失敗したら Claude に「次の編集をブロック、見直せ」と返す。Skill .claude/skills/refactor-pattern/SKILL.md
---
name: refactor-pattern
description: コードベース全体に同じパターンの変更を適用するリファクタタスク
---
# リファクタの手順
## 必ず 3 段階で進める
1. **発見フェーズ**: 該当箇所を Glob/Grep で全部リスト化、`.notes/refactor-list.md` に保存
2. **パイロットフェーズ**: リストから 1 ファイル選び、変更してテスト通す。動かなければ元に戻す
3. **展開フェーズ**: 残りを順次。10 ファイルごとに git commit、コミットメッセージは Conventional Commits
## 注意
- パイロットで 30 分以上詰まったら、ユーザーに戻して相談
- テストがないファイルは飛ばし、`.notes/refactor-skipped.md` にリスト
- 影響が大きい変更(API シグネチャ変更など)は、まず影響範囲を提示してユーザー確認
ワークフロー (例: print → logger 置換)
ユーザー: 「コードベース内のすべての print(...) を logger.info(...) に置換して。
ただしテストコード内の print は除外。」
Claude:
Step 1 (refactor-pattern Skill 発火): 該当箇所をリスト化
> Grep で `print(` を全検索 → 87 件
> .notes/refactor-list.md に保存
> うちテストファイル (tests/ 配下) は 23 件 → 除外、.notes/refactor-skipped.md
> 残り 64 件が対象
Step 2: パイロット 1 ファイル
> src/utils/helper.py の 3 箇所を変更
> Hook が pytest を走らせる → 通る
> git commit -m "refactor: print → logger.info in src/utils/helper.py"
Step 3: 残り 22 ファイル × 平均 3 箇所
> 10 ファイルごとに commit
> Hook で各 commit 前にテスト
> 1 ファイル(src/legacy/old_module.py)で test 失敗 → 該当変更をリバート、ユーザーに報告
注意点・限界
- テストカバレッジが低い箇所は危険(変更後テストが通っても本当に動くか分からない) → カバレッジが低い領域は別途手動確認
- 意味を変える置換(例:
print でロガーが上書きする出力色を期待してた箇所)は AI には判別できない → コードレビューで人間が確認
- 大きすぎるリファクタ(1000 ファイル超)は 1 セッションでは厳しい → 章単位で分割
- コスト目安: Haiku で 50 ファイル ≈ $1〜$3、Sonnet を使うと $5〜$15
応用
- 依存パッケージのメジャーバージョンアップ (Python 3.x → 3.y で deprecated になった API の置換)
- テストデコレータの一斉追加 (新しい pytest plugin の設定)
- i18n キーの追加 (UI 文字列を
gettext("...") で囲む)
- 型注釈の段階的導入 (untyped だった関数に Type hint を追加)
このケース後にできるようになること
- 機械的反復作業を半自動化 できる
- テストが品質保証になる という感覚 — テストが薄いと AI 任せもできない、と気づく
- Hook の威力を体感(失敗を即座に検知 → 暴走しない)
関連