<!-- i18n-source: 03-skills/refactor/SKILL.md -->
<!-- i18n-source-sha: 245272f -->
<!-- i18n-date: 2026-04-27 -->
---
name: code-refactor
description: Martin Fowler の方法論に基づく体系的なコードリファクタリング。ユーザーがコードのリファクタリング、コード構造の改善、技術的負債の削減、レガシーコードのクリーンアップ、コードスメルの解消、コード保守性の向上を求めた際に使用する。本スキルは、リサーチ・計画・安全な段階的実装からなる段階的アプローチを案内する。
---

# コードリファクタリングスキル

Martin Fowler 著『Refactoring: Improving the Design of Existing Code』(第 2 版) に基づくコードリファクタリングへの体系的アプローチ。本スキルは、テストに支えられた安全で段階的な変更を重視する。

> "Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure." — Martin Fowler

## 中核となる原則

1. **振る舞いの保全**: 外部から見える振る舞いは変えてはならない
2. **小さなステップ**: テスト可能な微小な変更を積み重ねる
3. **テスト駆動**: テストはセーフティネットである
4. **継続的**: リファクタリングは一度きりの作業ではなく継続的に行う
5. **協調的**: 各フェーズでユーザーの承認が必要

## ワークフロー概要

```
Phase 1: Research & Analysis
    ↓
Phase 2: Test Coverage Assessment
    ↓
Phase 3: Code Smell Identification
    ↓
Phase 4: Refactoring Plan Creation
    ↓
Phase 5: Incremental Implementation
    ↓
Phase 6: Review & Iteration
```

---

## フェーズ 1: リサーチと分析

### 目的
- コードベースの構造と目的を把握する
- リファクタリングの範囲を特定する
- ビジネス要件に関するコンテキストを収集する

### ユーザーへの確認事項
開始前に次の点を明確化する。

1. **範囲**: どのファイル/モジュール/関数をリファクタリングするのか?
2. **目標**: 何を解決したいのか?(可読性、性能、保守性)
3. **制約**: 変更してはいけない領域はあるか?
4. **時間的圧力**: 他作業のブロッカーになっているか?
5. **テスト状況**: テストは存在するか?パスしているか?

### アクション
- [ ] 対象コードを読み、理解する
- [ ] 依存関係と統合箇所を洗い出す
- [ ] 現行アーキテクチャを文書化する
- [ ] 既存の技術的負債マーカー(TODO、FIXME)を控える

### 出力
ユーザーへの提示内容:
- コード構造のサマリー
- 検出された問題箇所
- 初期推奨事項
- **着手の承認を依頼する**

---

## フェーズ 2: テストカバレッジの評価

### なぜテストが重要か
> "Refactoring without tests is like driving without a seatbelt." — Martin Fowler

テストは安全なリファクタリングを可能にする**鍵となる要素**である。テストがなければ、バグを混入させるリスクがある。

### 評価ステップ

1. **既存テストの確認**
   ```bash
   # テストファイルを探す
   find . -name "*test*" -o -name "*spec*" | head -20
   ```

2. **既存テストの実行**
   ```bash
   # JavaScript/TypeScript
   npm test

   # Python
   pytest -v

   # Java
   mvn test
   ```

3. **カバレッジの確認(可能な場合)**
   ```bash
   # JavaScript
   npm run test:coverage

   # Python
   pytest --cov=.
   ```

### 判断ポイント: ユーザーへの確認

**テストが存在し、かつパスしている場合:**
- フェーズ 3 へ進む

**テストが不足、または不完全な場合:**
次の選択肢を提示する。
1. 先にテストを書く(推奨)
2. リファクタリング中に段階的にテストを追加する
3. テストなしで進める(リスクあり、ユーザーの明示的同意が必要)

**テストが失敗している場合:**
- STOP。リファクタリング前に失敗テストを修正する
- ユーザーに確認: 先にテストを直すべきか?

### テスト作成のガイドライン(必要時)

リファクタリング対象の各関数について、以下をテストでカバーする。
- ハッピーパス(通常動作)
- エッジケース(空入力、null、境界値)
- エラーシナリオ(無効入力、例外)

「red-green-refactor」サイクルを用いる。
1. 失敗するテストを書く(red)
2. パスさせる(green)
3. リファクタリングする

---

## フェーズ 3: コードスメルの特定

### コードスメルとは?
コードに潜むより深い問題の症状である。バグそのものではないが、コード改善の余地を示す指標となる。

### よくチェックすべきコードスメル

完全なカタログは [references/code-smells.md](references/code-smells.md) を参照。

#### クイックリファレンス

| スメル | 兆候 | 影響 |
|-------|-------|--------|
| **Long Method（長すぎる関数）** | メソッドが 30〜50 行を超える | 理解、テスト、保守が困難 |
| **Duplicated Code（重複したコード）** | 同じロジックが複数箇所に存在 | バグ修正を複数箇所で行う必要がある |
| **Large Class（巨大なクラス）** | 責務が多すぎるクラス | 単一責任原則に違反 |
| **Feature Envy（機能の横恋慕）** | 他クラスのデータを多く使用するメソッド | カプセル化が不十分 |
| **Primitive Obsession（プリミティブ型への執着）** | オブジェクト化すべき所をプリミティブで多用 | ドメイン概念が欠落 |
| **Long Parameter List（長すぎるパラメータリスト）** | パラメータが 4 個以上 | 正しく呼び出すのが困難 |
| **Data Clumps（データの群れ）** | 同じデータ項目が常に一緒に現れる | 抽象化が欠落 |
| **Switch Statements（スイッチ文)** | 複雑な switch / if-else の連鎖 | 拡張が困難 |
| **Speculative Generality（投機的一般化）** | 「念のため」のコード | 不要な複雑さ |
| **Dead Code（デッドコード）** | 使われていないコード | 混乱と保守負担 |

### 分析ステップ

1. **自動分析**(スクリプトが利用可能な場合)
   ```bash
   python scripts/detect-smells.py <file>
   ```

2. **手動レビュー**
   - コードを体系的に読み進める
   - 各スメルを場所と深刻度とともに記録する
   - 影響度別に分類する(Critical / High / Medium / Low)

3. **優先順位付け**
   次のようなスメルに注力する。
   - 現在の開発をブロックしているもの
   - バグや混乱を引き起こしているもの
   - 変更頻度が高いコードパスに影響するもの

### 出力: スメルレポート

ユーザーへの提示内容:
- 検出されたスメルの一覧と場所
- 各スメルの深刻度評価
- 推奨される優先順位
- **優先順位の承認を依頼する**

---

## フェーズ 4: リファクタリング計画の作成

### リファクタリング技法の選定

各スメルに対して、カタログから適切なリファクタリング技法を選ぶ。

完全な一覧は [references/refactoring-catalog.md](references/refactoring-catalog.md) を参照。

#### スメル別の推奨リファクタリング

| コードスメル | 推奨リファクタリング |
|------------|---------------------------|
| Long Method（長すぎる関数） | メソッドの抽出、Replace Temp with Query |
| Duplicated Code（重複したコード） | メソッドの抽出、Pull Up Method、Form Template Method |
| Large Class（巨大なクラス） | クラスの抽出、Extract Subclass |
| Feature Envy（機能の横恋慕） | Move Method、Move Field |
| Primitive Obsession（プリミティブ型への執着） | Replace Primitive with Object、Replace Type Code with Class |
| Long Parameter List（長すぎるパラメータリスト） | パラメータオブジェクトの導入、Preserve Whole Object |
| Data Clumps（データの群れ） | クラスの抽出、パラメータオブジェクトの導入 |
| Switch Statements（スイッチ文） | ポリモーフィズムによる条件記述の置き換え |
| Speculative Generality（投機的一般化） | Collapse Hierarchy、Inline Class、デッドコードの削除 |
| Dead Code（デッドコード） | デッドコードの削除 |

### 計画の構成

[templates/refactoring-plan.md](templates/refactoring-plan.md) のテンプレートを使用する。

各リファクタリングごとに次の項目を埋める。
1. **対象**: 何を変更するか
2. **スメル**: どの問題に対処するか
3. **リファクタリング**: どの技法を適用するか
4. **手順**: 細かいマイクロステップ
5. **リスク**: 何が失敗しうるか
6. **ロールバック**: 取り消す方法

### 段階的アプローチ

**重要**: リファクタリングはフェーズに分けて段階的に導入する。

**フェーズ A: クイックウィン**(低リスク、高価値)
- 明確化のための変数名変更
- 明らかな重複コードの抽出
- デッドコードの削除

**フェーズ B: 構造改善**(中リスク)
- 長すぎる関数からのメソッド抽出
- パラメータオブジェクトの導入
- メソッドを適切なクラスへ移動

**フェーズ C: アーキテクチャ変更**(高リスク)
- 条件分岐をポリモーフィズムで置換
- クラスの抽出
- デザインパターンの導入

### 判断ポイント: ユーザーへの計画提示

実装前に:
- 完全なリファクタリング計画を提示する
- 各フェーズの内容とリスクを説明する
- 各フェーズについて明示的な承認を得る
- **質問**: 「フェーズ A を進めてもよいか?」

---

## フェーズ 5: 段階的な実装

### ゴールデンルール
> "Change → Test → Green? → Commit → Next step"

### 実装のリズム

各リファクタリングステップで:

1. **事前チェック**
   - テストがパスしている(green)
   - コードがコンパイルできる

2. **小さな変更を 1 つだけ行う**
   - カタログのメカニクスに従う
   - 変更は最小限に保つ

3. **検証**
   - 直ちにテストを実行
   - コンパイルエラーがないか確認

4. **テストがパス(green)した場合**
   - 説明的なコミットメッセージでコミット
   - 次のステップへ進む

5. **テストが失敗(red)した場合**
   - 直ちに STOP
   - 変更を取り消す
   - 何が起きたかを分析する
   - 不明な場合はユーザーに確認する

### コミット戦略

各コミットは次の性質を満たすこと。
- **アトミック**: 論理的に 1 つの変更
- **可逆**: 容易に revert できる
- **説明的**: 明確なコミットメッセージ

コミットメッセージ例:
```
refactor: Extract calculateTotal() from processOrder()
refactor: Rename 'x' to 'customerCount' for clarity
refactor: Remove unused validateOldFormat() method
```

### 進捗報告

サブフェーズごとに、ユーザーへ次を報告する。
- 行った変更
- テストはまだパスしているか
- 発生した問題
- **質問**: 「次のバッチへ進めてもよいか?」

---

## フェーズ 6: レビューと反復

### リファクタリング後チェックリスト

- [ ] 全テストがパスする
- [ ] 新たな警告/エラーが出ていない
- [ ] コードが正常にコンパイルできる
- [ ] 振る舞いが変わっていない(手動検証)
- [ ] 必要に応じてドキュメントが更新されている
- [ ] コミット履歴が整理されている

### メトリクス比較

リファクタリング前後で複雑度解析を実施する。
```bash
python scripts/analyze-complexity.py <file>
```

改善点を提示する。
- コード行数の変化
- 循環的複雑度の変化
- 保守性指数の変化

### ユーザーレビュー

最終結果を提示する。
- 全変更のサマリー
- Before / After のコード比較
- メトリクスの改善
- 残る技術的負債
- **質問**: 「この変更内容で問題ないか?」

### 次のステップ

ユーザーと議論する。
- 追加で対処すべきスメルはあるか?
- フォローアップのリファクタリングを計画するか?
- 同様の変更を他箇所にも適用するか?

---

## 重要なガイドライン

### STOP してユーザーに相談すべきタイミング

次の場合、必ず一旦止まりユーザーに相談する。
- ビジネスロジックに不確実性がある
- 外部 API に影響しうる変更
- テストカバレッジが不十分
- 重大なアーキテクチャ判断が必要
- リスクレベルが上昇する
- 想定外の複雑さに遭遇した

### 安全のためのルール

1. **テストなしでリファクタリングしない**(ユーザーが明示的にリスクを受容しない限り)
2. **大きな変更を一度にしない** - 微小なステップに分割する
3. **各変更後のテスト実行を省略しない**
4. **テスト失敗時は続行しない** - 修正かロールバックを先に行う
5. **思い込みで進めない** - 疑問があれば確認する

### やってはいけないこと

- リファクタリングと機能追加を同時に行わない
- 本番障害対応中にリファクタリングしない
- 理解していないコードをリファクタリングしない
- 過剰設計をしない - シンプルに保つ
- 全てを一度にリファクタリングしない

---

## クイックスタート例

### シナリオ: 重複を含む長い関数

**Before:**
```javascript
function processOrder(order) {
  // 150 行のコードに以下が混在:
  // - 重複したバリデーションロジック
  // - インラインの計算処理
  // - 複数の責務
}
```

**リファクタリング手順:**

1. processOrder() に対する**テストの存在を確認**
2. バリデーションを validateOrder() に**抽出**
3. **テスト** - パスすること
4. 計算を calculateOrderTotal() に**抽出**
5. **テスト** - パスすること
6. 通知を notifyCustomer() に**抽出**
7. **テスト** - パスすること
8. **レビュー** - processOrder() は明確な 3 関数の調整役となる

**After:**
```javascript
function processOrder(order) {
  validateOrder(order);
  const total = calculateOrderTotal(order);
  notifyCustomer(order, total);
  return { order, total };
}
```

---

## 参考文献

- [Code Smells Catalog](references/code-smells.md) - コードスメルの完全な一覧
- [Refactoring Catalog](references/refactoring-catalog.md) - リファクタリング技法
- [Refactoring Plan Template](templates/refactoring-plan.md) - 計画用テンプレート

## スクリプト

- `scripts/analyze-complexity.py` - コード複雑度メトリクスの分析
- `scripts/detect-smells.py` - スメルの自動検出

## バージョン履歴

- v1.0.0 (2025-01-15): Fowler の方法論、段階的アプローチ、ユーザー相談ポイントを備えた初版リリース
