Skip to content

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 を参照。

クイックリファレンス

スメル兆候影響
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 を参照。

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

コードスメル推奨リファクタリング
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 のテンプレートを使用する。

各リファクタリングごとに次の項目を埋める。

  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 };
}

参考文献

スクリプト

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

バージョン履歴

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