AgentSkillsCN

refactoring

基于 Martin Fowler 的重构方法论,掌握系统的代码优化技能。从代码异味的识别到安全重构的实施,以测试为安全网,逐步提升代码质量。在实施过程中,时刻谨记“两顶帽子”的原则,将功能新增与代码分离,分步推进。

SKILL.md
--- frontmatter
name: refactoring
description: |
  Martin Fowlerのリファクタリング方法論に基づいた体系的なコード改善スキル。
  コードスメルの検出から安全なリファクタリングの実施まで、テストを安全網として
  段階的に品質を向上させます。「2つの帽子」を意識し、機能追加と分離して実施。

Refactoring Skill

外部から見た振る舞いを変えずに、内部の構造を改善するスキル。

対応領域

領域フォーカス詳細ガイド
Code Smell Detectionコードスメルの特定と優先順位付け./agents/code-smell-detector.md
BackendPython/FastAPIコードのリファクタリング./agents/backend-refactorer.md
FrontendTypeScript/SvelteKitコードのリファクタリング./agents/frontend-refactorer.md

判断フロー

code
リファクタリングが必要な状況は?
│
├─ 大規模コードベースの改善 ────────→ ✅ サブエージェント並列実行
│
├─ Backend/Frontend両方の改善 ────→ ✅ サブエージェント並列実行
│
├─ 単一の関数/クラスの改善 ────────→ ✅ 直接リファクタリング
│
├─ 変数名/メソッド名の変更のみ ───→ ✅ 直接リファクタリング(軽量)
│
├─ テストがない/不十分 ────────────→ ❌ 先にテストを追加
│
├─ 本番リリース直前 ───────────────→ ❌ リファクタリング延期
│
└─ 機能追加と同時に行おうとする ──→ ❌ 別々に実施

サブエージェント並列リファクタリング

大規模なリファクタリングが必要な場合、専門サブエージェントを並列起動。

code
┌──────────────────────────────────────────────────────────────┐
│ 1. 分析フェーズ                                              │
│    └── Code Smell Detector でコードスメルを特定              │
├──────────────────────────────────────────────────────────────┤
│ 2. 計画フェーズ                                              │
│    └── 検出結果に基づいてリファクタリング計画を策定          │
├──────────────────────────────────────────────────────────────┤
│ 3. 実行フェーズ(並列可能)                                  │
│    ├── Backend Refactorer  → Pythonコードのリファクタリング  │
│    └── Frontend Refactorer → TypeScriptコードのリファクタリング│
├──────────────────────────────────────────────────────────────┤
│ 4. 検証フェーズ                                              │
│    └── テスト実行と動作確認                                  │
└──────────────────────────────────────────────────────────────┘

基本原則(Martin Fowler)

リファクタリングとは

「外部から見た振る舞いを変えずに、内部の構造を改善すること」

重要な特性:

  • 小さなステップで進める
  • 各ステップ後にテストが通ることを確認
  • 新機能の追加とリファクタリングを混ぜない

2つの帽子

code
🎩 機能追加の帽子          🧢 リファクタリングの帽子
├── 新しい機能を追加       ├── コードの構造を改善
├── 既存コードは変更しない  ├── 機能は追加しない
└── テストを追加           └── 既存のテストが通り続ける

⚠️ 両方の帽子を同時にかぶらない!

3回の法則

code
1回目: とにかく実装する
2回目: 似たようなことをする時、重複を感じつつも進める
3回目: 同じことを3回目にする時、リファクタリングする

リファクタリングワークフロー(5ステップ)

code
    ┌───────────────────────────────────────────────────────┐
    │                                                       │
    ▼                                                       │
┌────────┐   ┌────────┐   ┌────────┐   ┌────────┐         │
│準備    │──→│テスト  │──→│小さな  │──→│繰り返し│         │
│        │   │確認    │   │ステップ│   │        │         │
└────────┘   └────────┘   └────────┘   └────────┘         │
                                            │              │
                                            ▼              │
                                       ┌────────┐         │
                                       │完了確認│─────────┘
                                       └────────┘

Step 1: 準備

項目内容
テストカバレッジ確認対象コードのテストが存在するか確認
コードスメル特定問題のあるコードパターンを識別
範囲決定影響範囲を特定、小さな単位に分割

Step 2: テストの確認

bash
# Backend
poetry run pytest
poetry run pytest --cov=src --cov-report=term-missing

# Frontend
npm run test
  • すべてのテストがグリーンであること
  • カバレッジが十分であること(目標: 80%以上)

Step 3: 小さなステップで変更

  1. 1つのリファクタリングを選択 → 最小単位に分解
  2. 変更を適用 → コンパイル/構文チェック
  3. テストを実行poetry run pytest -x
  4. コミット → 小さな単位でコミット

Step 4: 繰り返し

  • Step 3を繰り返す
  • 各ステップ後にテストを実行
  • 問題があれば即座にロールバック

Step 5: 完了確認

  • 全テストを実行
  • コードレビュー(変更前後の比較)
  • 動作確認(開発サーバーでの確認)

コードスメル一覧

Bloaters(肥大化)

コードスメル症状対処法
Long Method長すぎるメソッドExtract Method
Large Class責務が多すぎるクラスExtract Class
Primitive Obsessionプリミティブ型の多用Replace Primitive with Object
Long Parameter Listパラメータが多すぎるIntroduce Parameter Object

Object-Orientation Abusers(OOP違反)

コードスメル症状対処法
Switch Statements条件分岐の多用Replace Conditional with Polymorphism
Temporary Field時々しか使わないフィールドExtract Class
Refused Bequest継承の誤用Replace Inheritance with Delegation

Change Preventers(変更困難)

コードスメル症状対処法
Divergent Change1つのクラスが複数の理由で変更Extract Class
Shotgun Surgery1つの変更が複数クラスに影響Move Method, Move Field

Dispensables(不要なもの)

コードスメル症状対処法
Duplicate Code重複コードExtract Method, Pull Up Method
Dead Code使われていないコード削除
Speculative Generality過剰な汎用化不要な抽象化を削除

Couplers(結合度の問題)

コードスメル症状対処法
Feature Envy他クラスのデータを多用Move Method
Inappropriate Intimacyクラス間の過度な結合Move Method, Extract Class
Message Chains長いメソッドチェーンHide Delegate

主要リファクタリングカタログ

Extract Method(メソッドの抽出)

python
# Before: 長いメソッド
def print_owing(self):
    print("***********************")
    print("*** Customer Owes ***")
    print("***********************")
    outstanding = sum(order.amount for order in self._orders)
    print(f"name: {self._name}")
    print(f"amount: {outstanding}")

# After: メソッドを抽出
def print_owing(self):
    self._print_banner()
    outstanding = self._calculate_outstanding()
    self._print_details(outstanding)

def _print_banner(self): ...
def _calculate_outstanding(self) -> float: ...
def _print_details(self, outstanding: float): ...

Extract Class(クラスの抽出)

python
# Before: 責務が多すぎるクラス
class Person:
    def __init__(self, name: str, office_area_code: str, office_number: str):
        self._name = name
        self._office_area_code = office_area_code
        self._office_number = office_number

# After: 電話番号を別クラスに抽出
@dataclass
class TelephoneNumber:
    area_code: str
    number: str

class Person:
    def __init__(self, name: str, telephone: TelephoneNumber):
        self._name = name
        self._telephone = telephone

Replace Conditional with Polymorphism

python
# Before: switch文による条件分岐
def calculate_pay(employee_type: str, hours: int) -> float:
    if employee_type == "engineer":
        return hours * 50
    elif employee_type == "manager":
        return hours * 75 + bonus()
    # ...

# After: ポリモーフィズムを使用
class Employee(ABC):
    @abstractmethod
    def calculate_pay(self, hours: int) -> float: pass

class Engineer(Employee):
    def calculate_pay(self, hours: int) -> float:
        return hours * 50

安全なリファクタリングルール

DO ✅

  • テストファースト: リファクタリング前にテストがグリーンであることを確認
  • 小さなステップ: 1つのリファクタリングを完了 → テスト → コミット → 次へ
  • 機能追加との分離: リファクタリングを完了してから機能追加
  • ロールバック準備: git reset --hard HEAD で即座に戻れる状態を維持

DON'T ❌

  • 複数のリファクタリングを同時に実施
  • テストを実行せずに進める
  • 「ついでに機能も追加しよう」
  • 「このバグも一緒に直そう」

レイヤー別リファクタリング

Domain層

python
# Before: プリミティブ型の多用
class Order:
    def __init__(self, amount: float, currency: str): ...

# After: 値オブジェクトの抽出
@dataclass(frozen=True)
class Money:
    amount: Decimal
    currency: str

class Order:
    def __init__(self, total: Money): ...

UseCase層

python
# Before: 複数の責務を持つユースケース
class UserUseCase:
    def create_user(self, data): ...
    def update_user(self, id, data): ...
    def delete_user(self, id): ...

# After: 単一責務に分割
class CreateUserUseCase:
    def execute(self, input: CreateUserInput) -> CreateUserOutput: ...

API層

python
# Before: ルーターにロジックが混在
@router.post("/users")
async def create_user(data: dict):
    if not data.get("email"):
        raise HTTPException(400, "Email required")
    # ビジネスロジックがここに...

# After: ルーターは薄く
@router.post("/users", response_model=UserResponse)
async def create_user(
    data: UserCreateRequest,
    usecase: CreateUserUseCase = Depends(get_create_user_usecase)
):
    return await usecase.execute(data)

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

🔴 開始前(必須)

  • テストが存在し、すべてグリーン
  • コードスメルを特定した
  • リファクタリングの範囲を決めた
  • 影響範囲を把握した

🟡 各ステップ(推奨)

  • 1つのリファクタリングのみを実施
  • テストを実行した
  • テストがグリーン
  • 変更をコミットした

🟢 完了時

  • すべてのテストがグリーン
  • コードの可読性が向上した
  • 新たなコードスメルが発生していない

ベストプラクティス

DO ✅

  • テストを安全網として活用
  • 小さなステップで進める
  • 各ステップ後にコミット
  • 80%の改善で良しとする
  • 残りは次のイテレーションで

DON'T ❌

  • テストなしでリファクタリング
  • 大きな変更を一度に実施
  • 機能追加と同時に実施
  • 完璧主義に陥る
  • 範囲を広げすぎる

参照ファイル

ファイル説明
./agents/code-smell-detector.mdコードスメル検出詳細
./agents/backend-refactorer.mdBackendリファクタリング詳細
./agents/frontend-refactorer.mdFrontendリファクタリング詳細
.claude/rules/code-style.mdコードスタイル規約
.claude/rules/backend/layer-rules.mdBackendレイヤールール

参考資料