refactoring について
テストで合格基準を確立した後、小規模で動作を変えないコードリファクタリングを評価・実施するためのスキルです。候補の優先順位付け、検証、コミット承認の手順を示します。
主な機能
- 01基準確立を先に行う手順
- 02候補の優先度評価
- 03動作を保つ小規模な変更
- 04テストとミューテーション検証の指針
- 05抽象化と範囲の管理ルール
活用シーン
- 01テスト合格後の候補評価
- 02動作を変えないコード構造の整理
- 03PR前の累積リファクタリング検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ citypaul/ .dotfiles --skill refactoringインストール後、Claude Code で/refactoringを入力して読み込まれたか確認します。
詳細
リファクタリング
リファクタリングは、再構成が適切な場合に、各高速な RED-GREEN-REFACTOR サイクルの最後のステップとして行います。GREEN によって動作テストの合格ベースラインが確立された後に評価します。各リファクタリングの前後に自動ミューテーションハーネスを実行しないでください。ミューテーションテストでは、ほかの作業が完了して PR の準備が整った段階で、フェーズ全体を検証します。
自動ミューテーションの証拠は意図的に後回しにされるため、リファクタリング中のベースラインの強度は、まだミューテーションハーネスで検証されていません。各リファクタリングは小規模にとどめ、動作を厳密に維持し、既存のオラクルで合格するようにしてください。最終ゲートで、積み重ねた結果を検証します。
このスキルは、範囲を限定した動作維持型の改善を安全に実装します。アーキテクチャ候補の発見と順位付けには improve-codebase-architecture を使用し、選定したモジュールの契約を設計するには codebase-design を使用してから、実装のためにこのスキルに戻ってください。対象のスライスが、選定された全経路削減プログラムに移行段階または最終削減として参加する場合は、台帳とゲートの状態を reduce-system-complexity で管理してください。該当する場合、このスキルは補助的なリファクタリング評価にのみ使用します。
リファクタリングするタイミング
- GREEN、またはそれに準じて合格した適切な保持ベースラインの後に評価します
- 評価の前、最初の編集の前、編集を見送る返信をする前に、該当するテストを自分で実行してください。依頼を断る場合も、すべての候補を Skip と分類する場合も評価に当たります。テストを実行せずに行う評価には、何の根拠もありません
- 最初の編集の前に、変更候補をすべて列挙し、それぞれに Critical、High、Nice、Skip のいずれかを付けてください
- すべて変更した場合も、一部を変更した場合も、何も変更しなかった場合も、最終返信には分類した候補リストを必ず含めてください。Skip の項目も含め、候補ごとに1行で記載し、最後に
Decision: <実施したこと、または実施しなかったこと>の行を付けてください。変更内容の要約は評価ではなく、分類されていない推奨も評価ではありません。明示されていない評価は、行われていない評価です - すべての候補が Skip の場合は、その旨を明記し、何も変更しないでください
- コードを改善する場合にのみリファクタリングしてください
- リファクタリングの前に、検証済みで復旧可能なベースラインを確立してください。明示的なユーザーの承認がある場合にのみコミットしてください
復元可能なベースラインを確立する — 理由
リファクタリング前に動作するベースラインを確立しておくと、次のことが可能になります。
- リファクタリングで問題が起きた場合に元に戻せます
- 実験時の安全策になります
- リファクタリングのリスクを軽減できます
- ユーザーがコミットを許可した場合、Git の履歴で明確な区切りを示せます
コミットを作成せずにベースラインを安全に復元できない場合は、暗黙にコミットせず、作業を止めて承認を求めてください。
ワークフロー:
- ベースライン:該当するテストがパスすること、および/または維持すべき動作と保証に見合った証拠があることを確認します
- チェックポイント:ベースラインと維持の証拠を記録します。ベースラインのコミットを作成するのは、ユーザーが明示的に承認した場合に限ります
- リファクタリング:
tddスキルの標準的な高速フィードバックポリシーに従い、小さなステップで構造を改善します。クリーンなベースラインから始める場合は、実績のあるリポジトリ所有のグラフ全体を対象とするウォッチャーを優先します。インストール済みのバージョン/設定で標準のクリーンスタート時のライブプルーフに合格した場合に限り、差分で選択した Vitest watch を使用します。それ以外の場合は、影響を受けるテストをワンショットで再実行します。モノレポではルートのグラフを使用し、推移的な利用側も引き続き対象となるようにします - 検証:各ステップの後、対象を絞ったテストと影響を受けるテスト、およびその他の妥当な証拠をすべて成功した状態に保ちます。編集のたびに全テストスイートを再実行しないでください
- チェックポイント:検証済みのリファクタリングに加え、ラベル付きの
Critical:/High:/Nice:/Skip:の評価行と、最後のDecision:行を提示します。変更内容の概要だけでは、このステップを完了したことになりません。コミットするのは、ユーザーが明示的に承認した後に限ります - PR 前のゲート:PR を出せる状態にほかの点で達したら、意味がある場合は蓄積した範囲に対してミューテーションテストを一度実行します。それが適用されない場合は、明示的に
N/Aと妥当な代替証拠を記録し、このゲート内で価値のある生存変異に対処します
完全なスライス
単一の限定された所有者または動作パスを中心に、小さく完全な変更を提供します。影響を受けるコントラクト、アダプター、利用側をまとめて更新します。すべてのハンドラーを移行してからすべてのサービスを移行するような水平移行では、通常、半分だけ変換されたパスが残ります。既存の動作オラクルを維持の証拠として使い、新しいメカニズムに必要なテストは別途特定します。簡素化を主張する場合は、削除したラッパー、重複した判断、変換処理、または依存関係を示します。抽出だけでも理解しやすさは改善できますが、メカニズムの削減にはならない場合があります。互換性のための足場を追加するのは、実証されたロールアウト上の制約がある場合に限り、所有者と削除条件を明記します。パス全体の削減を主張する場合は reduce-system-complexity を使用します。
優先度の分類
| 優先度 | 対応 | 例 |
|---|---|---|
| 重大 | 今すぐ修正 | 動作を変えるミューテーション、同一のビジネスルールの相反する複製、高リスクのパスを不明瞭にする制御フロー |
| 高 | このセッションで対応 | マジックナンバー(ルールごとに定数を1つ定義します。現在たまたま同じ値を共有しているだけの2つのルールにも、それぞれ独自の定数を割り当てます)、不明瞭な名前、複数の責務を調整する関数 |
| 推奨 | 後で対応 | 細かな命名、単一箇所でのみ使うヘルパー |
| 対応不要 | 変更しない | すでに整理されたコード |
DRY = コードではなく知識
抽象化する条件:
- 同じビジネス概念(意味上の意味)である
- 要件が変われば一緒に変更される
- まとめる理由が明白である
分けておく条件:
- 似て見えても異なる概念(構造上の類似)である
- 独立して進化する
- 結合すると分かりにくくなる
現在、同じ本体や数値を共有している2つのルールは、偶然そうなっているだけで、共有された知識ではありません。分けておくとは、それぞれのルールに独自の本体と名前付き定数を持たせることです。2つの値が等しくても、片方のルールをもう片方のルールに依存させたり、両方を共通の述語ヘルパーに通したりしてはいけません。そうすると、一方を編集しただけで2つのビジネスルールがひそかに変更されてしまいます。このような見た目だけ似たルールをまとめるよう求められても、実行してはいけません。何も変更しない場合でも、回答する前に該当するテストを実行してください。拒否も評価であり、編集と同じくテストがすべて成功しているベースラインが必要です。そのうえで、異なる2つのルールに名前を付け、どちらかを変更した時点で両者が別々の方向に変化することを説明し、両方の定義をそのまま残してください。そして、両者をまとめない変更だけを提案してください。
評価例 — 返信にはこの形式を使う
// After GREEN establishes a passing behavior-test baseline:
const planBatch = (batch: Batch): PlannedBatch => {
const itemSlots = batch.items.reduce((sum, item) => sum + item.quantity, 0);
const bufferSlots = itemSlots > 50 ? 0 : 6;
return { ...batch, plannedSlots: itemSlots + bufferSlots, bufferSlots };
};
// ASSESSMENT:
// ⚠️ High: Magic numbers 50, 6 → extract constants
// ✅ Skip: Structure is clear enough
// DECISION: Extract constants only
新しい動作には根拠が必要
失敗するテスト、またはリポジトリで認められたその他の受け入れ確認によって必要性が示されていない限り、新しい動作を追加してはいけません。動作を維持するリファクタリングでは、変更に見合った動作維持の証拠が成功している場合に限り、新しい RED テストなしでコード行を変更できます。PR の準備が整った段階では、意味のある累積スコープに対してミューテーションテストの証拠を使い、適用できない場合は明示的な代替証拠を用いてください。構造上のミュータントをでっち上げてはいけません。
❌ 根拠のない追加:
- 「念のため」のロジック
- まだ必要ではない機能
- 想像上の将来の柔軟性だけを目的とした抽象化
- 合意された契約のない新しいエラー動作
✅ 正しい方法:根拠のない動作は追加しないでください。必要になった場合は、それを要求する失敗するテストを書いてから実装してください。
テストされていない既存コードが、根拠のない動作や不要なコードだと証明されているわけではありません。分岐を削除する前に、観測可能な動作を特徴付け、すべての呼び出し元と到達可能な経路を調べ、動作の根拠を確認してください。到達不能であることが証拠によって示された場合、または合意された契約で明示的に廃止された場合にのみ削除し、その後も動作維持チェックと回帰チェックを成功させてください。
// ❌ WRONG - Speculative error handling (no test demands this)
if (items.length === 0) {
throw new Error('Empty cart'); // No test for this path!
}
// ✅ CORRECT - Test-driven error handling
// First: write a test that expects this behavior
// Then: implement the guard clause to make it pass
リファクタリングしない場合
次の場合はリファクタリングしないでください。
- ❌ 現在の構造が目の前の作業を妨げていない(十分に整ったコードは、構造を変更する必要がありません)
- ❌ 根拠のない汎用化 — まだ存在しない要件のための構造変更
- ❌ 動作が変わる(それはリファクタリングではなく、機能追加です)
- ❌ 時期尚早な最適化
- ❌ 現在の段階ではコードが「十分に良い」
- ❌ テスト可能性だけを目的とした抽出 — コードを別ファイルに移す理由が「単体テストできるようにするため」だけなら、インラインのままにしてください。このコードは、呼び出し元の関数に対する動作テストですでにカバーされています。読みやすさ、DRY(複数箇所で使われる同じ知識。上記の「DRY = コードではなく知識」を参照)、または関心の分離のために抽出してください。テスト可能性だけを理由にしてはいけません。
覚えておいてください:リファクタリングは、動作を変えずにコードの構造を改善するものです。
リファクタリングのコミットメッセージ
ユーザーがリファクタリングのコミットを承認したら、次のような焦点の絞られたメッセージを使用してください。
refactor: extract scenario validation logic
refactor: simplify error handling flow
refactor: rename ambiguous parameter names
形式:refactor: <変更内容>
注:コミットを使用する場合、リファクタリングのコミットを機能追加のコミットと混在させないでください。
リファクタリングチェックリスト
- 既存の動作テストが成功しており、テストの編集によって動作変更が隠されていません
- リファクタリング中、対象を絞ったテストと影響を受けるテストが成功し続けており、PR 前にリポジトリで定義された完全な非ウォッチ PR テストゲートが成功しています
- リファクタリングしたフェーズが PR に出せる状態であれば、意味のある範囲で、累積した対象範囲に対するミューテーションテストの結果を一度確認したか、明示的に
N/Aと記録し、相応の代替エビデンスを残しています - 予定していないコンシューマー向け API を追加していません。内部または一時的な契約は、選択した設計と互換性計画に従っています
- コードが以前より読みやすくなっています
- コミットは明示的に承認され、機能追加とは分けてあります
- 検証済みで復元可能なベースラインを確立しています。ベースラインコミットの作成は、承認された場合に限っています
- 推測に基づくコードを追加していません
- 合格した動作保持エビデンスの信頼性と忠実度の範囲内で、動作に変更がありません