Refactoring Skill
外部から見た振る舞いを変えずに、内部の構造を改善するスキル。
対応領域
| 領域 |
フォーカス |
詳細ガイド |
| Code Smell Detection |
コードスメルの特定と優先順位付け |
./agents/code-smell-detector.md |
| Backend |
Python/FastAPIコードのリファクタリング |
./agents/backend-refactorer.md |
| Frontend |
TypeScript/SvelteKitコードのリファクタリング |
./agents/frontend-refactorer.md |
判断フロー
リファクタリングが必要な状況は?
│
├─ 大規模コードベースの改善 ────────→ ✅ サブエージェント並列実行
│
├─ Backend/Frontend両方の改善 ────→ ✅ サブエージェント並列実行
│
├─ 単一の関数/クラスの改善 ────────→ ✅ 直接リファクタリング
│
├─ 変数名/メソッド名の変更のみ ───→ ✅ 直接リファクタリング(軽量)
│
├─ テストがない/不十分 ────────────→ ❌ 先にテストを追加
│
├─ 本番リリース直前 ───────────────→ ❌ リファクタリング延期
│
└─ 機能追加と同時に行おうとする ──→ ❌ 別々に実施
サブエージェント並列リファクタリング
大規模なリファクタリングが必要な場合、専門サブエージェントを並列起動。
┌──────────────────────────────────────────────────────────────┐
│ 1. 分析フェーズ │
│ └── Code Smell Detector でコードスメルを特定 │
├──────────────────────────────────────────────────────────────┤
│ 2. 計画フェーズ │
│ └── 検出結果に基づいてリファクタリング計画を策定 │
├──────────────────────────────────────────────────────────────┤
│ 3. 実行フェーズ(並列可能) │
│ ├── Backend Refactorer → Pythonコードのリファクタリング │
│ └── Frontend Refactorer → TypeScriptコードのリファクタリング│
├──────────────────────────────────────────────────────────────┤
│ 4. 検証フェーズ │
│ └── テスト実行と動作確認 │
└──────────────────────────────────────────────────────────────┘
基本原則(Martin Fowler)
リファクタリングとは
「外部から見た振る舞いを変えずに、内部の構造を改善すること」
重要な特性:
- 小さなステップで進める
- 各ステップ後にテストが通ることを確認
- 新機能の追加とリファクタリングを混ぜない
2つの帽子
🎩 機能追加の帽子 🧢 リファクタリングの帽子
├── 新しい機能を追加 ├── コードの構造を改善
├── 既存コードは変更しない ├── 機能は追加しない
└── テストを追加 └── 既存のテストが通り続ける
⚠️ 両方の帽子を同時にかぶらない!
3回の法則
1回目: とにかく実装する
2回目: 似たようなことをする時、重複を感じつつも進める
3回目: 同じことを3回目にする時、リファクタリングする
リファクタリングワークフロー(5ステップ)
┌───────────────────────────────────────────────────────┐
│ │
▼ │
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│準備 │──→│テスト │──→│小さな │──→│繰り返し│ │
│ │ │確認 │ │ステップ│ │ │ │
└────────┘ └────────┘ └────────┘ └────────┘ │
│ │
▼ │
┌────────┐ │
│完了確認│─────────┘
└────────┘
Step 1: 準備
| 項目 |
内容 |
| テストカバレッジ確認 |
対象コードのテストが存在するか確認 |
| コードスメル特定 |
問題のあるコードパターンを識別 |
| 範囲決定 |
影響範囲を特定、小さな単位に分割 |
Step 2: テストの確認
# Backend
poetry run pytest
poetry run pytest --cov=src --cov-report=term-missing
# Frontend
npm run test
- すべてのテストがグリーンであること
- カバレッジが十分であること(目標: 80%以上)
Step 3: 小さなステップで変更
- 1つのリファクタリングを選択 → 最小単位に分解
- 変更を適用 → コンパイル/構文チェック
- テストを実行 →
poetry run pytest -x
- コミット → 小さな単位でコミット
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 Change |
1つのクラスが複数の理由で変更 |
Extract Class |
| Shotgun Surgery |
1つの変更が複数クラスに影響 |
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(メソッドの抽出)
# 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(クラスの抽出)
# 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
# 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層
# 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層
# 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層
# 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)
リファクタリングチェックリスト
🔴 開始前(必須)
🟡 各ステップ(推奨)
🟢 完了時
ベストプラクティス
DO ✅
- テストを安全網として活用
- 小さなステップで進める
- 各ステップ後にコミット
- 80%の改善で良しとする
- 残りは次のイテレーションで
DON'T ❌
- テストなしでリファクタリング
- 大きな変更を一度に実施
- 機能追加と同時に実施
- 完璧主義に陥る
- 範囲を広げすぎる
参照ファイル
| ファイル |
説明 |
./agents/code-smell-detector.md |
コードスメル検出詳細 |
./agents/backend-refactorer.md |
Backendリファクタリング詳細 |
./agents/frontend-refactorer.md |
Frontendリファクタリング詳細 |
.claude/rules/code-style.md |
コードスタイル規約 |
.claude/rules/backend/layer-rules.md |
Backendレイヤールール |
参考資料