refactoring-specialist について
refactoring-specialist は、開発者向けのコードリファクタリング支援スキルです。よくあるコードスメルに対し、動作を保ちながらテストで確認する段階的な手法を示します。
主な機能
- 01コードスメルの特定
- 02リファクタリング手法の提案
- 03動作を保つ段階的な変更
- 04変更前後のテスト確認
- 05リファクタリング用チェックリスト
活用シーン
- 01長いメソッドや大きなクラスの分割
- 02重複コードの解消
- 03テストに基づく安全な変更計画
- 04変更前後の準備と結果の確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ zhaono1/ agent-playbook --skill refactoring-specialistインストール後、Claude Code で/refactoring-specialistを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdreferences/checklist.mdsmells.mdtechniques.md詳細
リファクタリングの専門家
機能を維持しながら、構造、可読性、保守性を向上させるコードのリファクタリングに関する専門的なガイダンスです。
このスキルが有効になる状況
次の場合に有効になります:
- コードのリファクタリングを依頼する
- コードの整理や改善を依頼する
- 「技術的負債」や「コードの臭い」に言及する
- コード品質を向上させたい
リファクタリングの原則
- 振る舞いを維持する:リファクタリングによって外部から見た振る舞いを変えてはいけません
- 小さな手順で進める:小さく段階的に変更します
- テストでカバーする:変更の前後でテストが通ることを確認します
- こまめにコミットする:リファクタリングが成功するたびにコミットします
対処するコードの臭い
1. 長すぎるメソッド
症状: 関数が20~30行を超える
リファクタリング: メソッドの抽出
// Before:
function processOrder(order) {
// 50 lines of code
}
// After:
function processOrder(order) {
validateOrder(order);
calculateTotals(order);
saveOrder(order);
sendConfirmation(order);
}
2. コードの重複
症状: 複数の場所に似たコードがある
リファクタリング: メソッドの抽出/テンプレートメソッド
// Before:
class UserService {
async validateEmail(email) {
if (!email || !email.includes('@')) return false;
const domain = email.split('@')[1];
return domain.length > 0;
}
}
class AdminService {
async validateEmail(email) {
if (!email || !email.includes('@')) return false;
const domain = email.split('@')[1];
return domain.length > 0;
}
}
// After:
class EmailValidator {
async validate(email) {
if (!email || !email.includes('@')) return false;
return email.split('@')[1].length > 0;
}
}
3. 大きすぎるクラス
症状: クラスが多くのことを行っている
リファクタリング: クラスの抽出
// Before:
class User {
// Authentication
// Profile management
// Notifications
// Reporting
}
// After:
class User { /* Core user data */ }
class UserAuth { /* Authentication */ }
class UserProfile { /* Profile management */ }
class UserNotifier { /* Notifications */ }
4. 長すぎるパラメーターリスト
症状: 関数のパラメーターが4つ以上ある
リファクタリング: パラメーターオブジェクトの導入
// Before:
function createUser(name, email, age, address, phone, role) { ... }
// After:
function createUser(user: UserData) { ... }
interface UserData {
name: string;
email: string;
age: number;
address: string;
phone: string;
role: string;
}
5. 他クラスへの過度な依存
症状: メソッドが他クラスのデータをより多く使用している
リファクタリング: メソッドの移動
// Before:
class Report {
formatSummary(formatter) {
const options = formatter.getFormattingOptions();
// ...
}
}
// After:
class Formatter {
formatReport(report) {
const discount = this.discountLevel;
// ...
}
}
6. データのまとまり
症状:同じデータが一緒に現れる
リファクタリング:値オブジェクトの抽出
// Before:
function drawShape(x, y, width, height) { ... }
function moveShape(x, y, width, height, dx, dy) { ... }
// After:
class Rectangle {
constructor(x, y, width, height) { ... }
}
function drawShape(rect: Rectangle) { ... }
7. プリミティブ型への過度な依存
症状:小さなオブジェクトの代わりにプリミティブ型を使用している
リファクタリング:プリミティブ型をオブジェクトに置き換える
// Before:
function createUser(name, email, phone) { ... }
// After:
class Email {
constructor(value) {
if (!this.isValid(value)) throw new Error('Invalid email');
this.value = value;
}
// ...
}
8. switch文
症状:型に応じた大きなswitch文がある
リファクタリング:条件分岐をポリモーフィズムに置き換える
// Before:
function calculatePay(employee) {
switch (employee.type) {
case 'engineer': return employee.salary * 1.2;
case 'manager': return employee.salary * 1.5;
case 'sales': return employee.salary * 1.1;
}
}
// After:
interface Employee {
calculatePay(): number;
}
class Engineer implements Employee {
calculatePay() { return this.salary * 1.2; }
}
9. 一時フィールド
症状:特定の状況でのみ使用される変数がある
リファクタリング:クラスの抽出
// Before:
class User {
calculateRefund() {
this.tempRefundAmount = 0;
// complex calculation
return this.tempRefundAmount;
}
}
// After:
class RefundCalculator {
calculate(user) {
// ...
}
}
10. コメント
症状:コードに大量のコメントが必要
リファクタリング:明確な名前を付けてメソッドを抽出する
// Before:
// Calculate the total price including discounts
// and tax based on user location
function calc(u, i) {
let t = 0;
// discount logic
if (u.vip) t *= 0.9;
// tax logic
if (u.state === 'CA') t *= 1.08;
return t;
}
// After:
function calculateTotalPrice(user: User, items: Item[]): number {
let total = items.sum(i => i.price);
if (user.isVIP) {
total = applyVIPDiscount(total);
}
return applyTax(total, user.state);
}
リファクタリングの手順
- 臭いを特定する - このコードを扱いにくくしている原因は何ですか?
- リファクタリングを決める - どの手法が適用できますか?
- テストが通ることを確認する - 開始前にテストが成功している状態にします
- リファクタリングを適用する - 変更を加えます
- テストを実行する - 振る舞いが変わっていないことを確認します
- コミットする - 小さく、アトミックなコミットにします
安全にリファクタリングするための実践方法
- IDEのリファクタリングツール(名前の変更、抽出、移動)を使用します
- こまめにテストを実行します(変更のたびに)
- コミットは小さく、対象を絞ります
- 内容がわかるコミットメッセージを書きます
- 複雑なリファクタリングではコードレビューを検討します
リファクタリングの前
- テストが通っている
- コードの動作を理解している
- 特定のコードの臭いを特定している
- 適用するリファクタリングがわかっている
- ロールバックの計画がある
リファクタリングの後
- テストが引き続き通る
- コードの可読性が向上している
- コードの保守が容易になっている
- 新たなコードの臭いが生じていない
- 必要に応じてドキュメントが更新されている
参考資料
references/smells.md- コードの臭いの完全な一覧references/techniques.md- リファクタリング手法references/checklist.md- リファクタリングのチェックリスト
コメント
Markdown 対応