code-refactoring
49
总安装量
50
周安装量
#4299
全站排名
安装命令
npx skills add https://github.com/supercent-io/skills-template --skill code-refactoring
Agent 安装分布
opencode
42
claude-code
39
gemini-cli
36
github-copilot
30
antigravity
25
Skill 文档
Code Refactoring
When to use this skill
- ì½ë 리뷰: ë³µì¡íê±°ë ì¤ë³µë ì½ë ë°ê²¬
- ì ê¸°ë¥ ì¶ê° ì : 기존 ì½ë ì 리
- ë²ê·¸ ìì í: 근본 ìì¸ ì ê±°
- 기ì ë¶ì± í´ì: ì 기ì ì¸ ë¦¬í©í ë§
Instructions
Step 1: Extract Method (ë©ìë ì¶ì¶)
Before (긴 í¨ì):
function processOrder(order: Order) {
// ê²ì¦
if (!order.items || order.items.length === 0) {
throw new Error('Order must have items');
}
if (!order.customerId) {
throw new Error('Order must have customer');
}
// ê°ê²© ê³ì°
let total = 0;
for (const item of order.items) {
total += item.price * item.quantity;
}
const tax = total * 0.1;
const shipping = total > 100 ? 0 : 10;
const finalTotal = total + tax + shipping;
// ì¬ê³ íì¸
for (const item of order.items) {
const product = await db.product.findUnique({ where: { id: item.productId } });
if (product.stock < item.quantity) {
throw new Error(`Insufficient stock for ${product.name}`);
}
}
// 주문 ìì±
const newOrder = await db.order.create({
data: {
customerId: order.customerId,
items: order.items,
total: finalTotal,
status: 'pending'
}
});
return newOrder;
}
After (ë©ìë ì¶ì¶):
async function processOrder(order: Order) {
validateOrder(order);
const total = calculateTotal(order);
await checkInventory(order);
return await createOrder(order, total);
}
function validateOrder(order: Order) {
if (!order.items || order.items.length === 0) {
throw new Error('Order must have items');
}
if (!order.customerId) {
throw new Error('Order must have customer');
}
}
function calculateTotal(order: Order): number {
const subtotal = order.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
const tax = subtotal * 0.1;
const shipping = subtotal > 100 ? 0 : 10;
return subtotal + tax + shipping;
}
async function checkInventory(order: Order) {
for (const item of order.items) {
const product = await db.product.findUnique({ where: { id: item.productId } });
if (product.stock < item.quantity) {
throw new Error(`Insufficient stock for ${product.name}`);
}
}
}
async function createOrder(order: Order, total: number) {
return await db.order.create({
data: {
customerId: order.customerId,
items: order.items,
total,
status: 'pending'
}
});
}
Step 2: Remove Duplication (ì¤ë³µ ì ê±°)
Before (ì¤ë³µ):
async function getActiveUsers() {
return await db.user.findMany({
where: { status: 'active', deletedAt: null },
select: { id: true, name: true, email: true }
});
}
async function getActivePremiumUsers() {
return await db.user.findMany({
where: { status: 'active', deletedAt: null, plan: 'premium' },
select: { id: true, name: true, email: true }
});
}
After (ê³µíµ ë¡ì§ ì¶ì¶):
type UserFilter = {
plan?: string;
};
async function getActiveUsers(filter: UserFilter = {}) {
return await db.user.findMany({
where: {
status: 'active',
deletedAt: null,
...filter
},
select: { id: true, name: true, email: true }
});
}
// ì¬ì©
const allActiveUsers = await getActiveUsers();
const premiumUsers = await getActiveUsers({ plan: 'premium' });
Step 3: Replace Conditional with Polymorphism
Before (긴 if-else):
class PaymentProcessor {
process(payment: Payment) {
if (payment.method === 'credit_card') {
// ì ì©ì¹´ë ì²ë¦¬
const cardToken = this.tokenizeCard(payment.card);
const charge = this.chargeCreditCard(cardToken, payment.amount);
return charge;
} else if (payment.method === 'paypal') {
// PayPal ì²ë¦¬
const paypalOrder = this.createPayPalOrder(payment.amount);
const approval = this.getPayPalApproval(paypalOrder);
return approval;
} else if (payment.method === 'bank_transfer') {
// ìí ì´ì²´ ì²ë¦¬
const transfer = this.initiateBankTransfer(payment.account, payment.amount);
return transfer;
}
}
}
After (ë¤íì±):
interface PaymentMethod {
process(payment: Payment): Promise<PaymentResult>;
}
class CreditCardPayment implements PaymentMethod {
async process(payment: Payment): Promise<PaymentResult> {
const cardToken = await this.tokenizeCard(payment.card);
return await this.chargeCreditCard(cardToken, payment.amount);
}
}
class PayPalPayment implements PaymentMethod {
async process(payment: Payment): Promise<PaymentResult> {
const order = await this.createPayPalOrder(payment.amount);
return await this.getPayPalApproval(order);
}
}
class BankTransferPayment implements PaymentMethod {
async process(payment: Payment): Promise<PaymentResult> {
return await this.initiateBankTransfer(payment.account, payment.amount);
}
}
class PaymentProcessor {
private methods: Map<string, PaymentMethod> = new Map([
['credit_card', new CreditCardPayment()],
['paypal', new PayPalPayment()],
['bank_transfer', new BankTransferPayment()]
]);
async process(payment: Payment): Promise<PaymentResult> {
const method = this.methods.get(payment.method);
if (!method) {
throw new Error(`Unknown payment method: ${payment.method}`);
}
return await method.process(payment);
}
}
Step 4: Introduce Parameter Object
Before (ë§ì íë¼ë¯¸í°):
function createUser(
name: string,
email: string,
password: string,
age: number,
country: string,
city: string,
postalCode: string,
phoneNumber: string
) {
// ...
}
After (ê°ì²´ë¡ 그룹í):
interface UserProfile {
name: string;
email: string;
password: string;
age: number;
}
interface Address {
country: string;
city: string;
postalCode: string;
}
interface CreateUserParams {
profile: UserProfile;
address: Address;
phoneNumber: string;
}
function createUser(params: CreateUserParams) {
const { profile, address, phoneNumber } = params;
// ...
}
// ì¬ì©
createUser({
profile: { name: 'John', email: 'john@example.com', password: 'xxx', age: 30 },
address: { country: 'US', city: 'NYC', postalCode: '10001' },
phoneNumber: '+1234567890'
});
Step 5: SOLID ìì¹ ì ì©
Single Responsibility (ë¨ì¼ ì± ì):
// â ëì ì: ì¬ë¬ ì±
ì
class User {
constructor(public name: string, public email: string) {}
save() {
// DB ì ì¥
}
sendEmail(subject: string, body: string) {
// ì´ë©ì¼ ë°ì¡
}
generateReport() {
// 리í¬í¸ ìì±
}
}
// â
ì¢ì ì: ì±
ì ë¶ë¦¬
class User {
constructor(public name: string, public email: string) {}
}
class UserRepository {
save(user: User) {
// DB ì ì¥
}
}
class EmailService {
send(to: string, subject: string, body: string) {
// ì´ë©ì¼ ë°ì¡
}
}
class UserReportGenerator {
generate(user: User) {
// 리í¬í¸ ìì±
}
}
Output format
리í©í ë§ ì²´í¬ë¦¬ì¤í¸
- [ ] í¨ìë í ê°ì§ ì¼ë§ íë¤ (SRP)
- [ ] í¨ì ì´ë¦ì´ íë ì¼ì ëª
íí ì¤ëª
íë¤
- [ ] í¨ìë 20ì¤ ì´í (ê°ì´ëë¼ì¸)
- [ ] 매ê°ë³ìë 3ê° ì´í
- [ ] ì¤ë³µ ì½ë ìì (DRY)
- [ ] if ì¤ì²©ì 2ë¨ê³ ì´í
- [ ] ë§¤ì§ ëë² ìì (ììë¡ ì¶ì¶)
- [ ] 주ì ìì´ë ì´í´ ê°ë¥ (ì기 문ìí)
Constraints
íì ê·ì¹ (MUST)
- í ì¤í¸ 먼ì : 리í©í ë§ ì í ì¤í¸ ìì±
- ìì ë¨ê³: í ë²ì íëì© ë³ê²½
- ëì ë³´ì¡´: ê¸°ë¥ ë³ê²½ ìì
ê¸ì§ ì¬í (MUST NOT)
- ëìì ì¬ë¬ ìì : 리í©í ë§ + ê¸°ë¥ ì¶ê° ëì ê¸ì§
- í ì¤í¸ ìì´ ë¦¬í©í ë§: íê· ìí
Best practices
- Boy Scout Rule: ì½ë를 ë°ê²¬íì ëë³´ë¤ ê¹¨ëíê²
- 리í©í ë§ íì´ë°: Red-Green-Refactor (TDD)
- ì ì§ì ê°ì : ìë²½ë³´ë¤ ê¾¸ì¤í
- íë ë³´ì¡´: 리í©í ë§ì ê¸°ë¥ ë³ê²½ ìì
- ìì 커ë°: í¬ì»¤ì¤ë ë¨ìë¡ ì»¤ë°
Behavior Validation (Code Simplifier Integration)
Step A: Understand Current Behavior
리í©í ë§ ì íì¬ ëì ìì í ì´í´:
## Behavior Analysis
### Inputs
- [ì
ë ¥ íë¼ë¯¸í° 목ë¡]
- [íì
ë° ì ì½ì¬í]
### Outputs
- [ë°íê°]
- [ë¶ì í¨ê³¼ (side effects)]
### Invariants
- [íì ì°¸ì´ì´ì¼ íë ì¡°ê±´ë¤]
- [ê²½ê³ ì¡°ê±´ (edge cases)]
### Dependencies
- [ì¸ë¶ ìì¡´ì±]
- [ìí ìì¡´ì±]
Step B: Validate After Refactoring
# 1. í
ì¤í¸ ì¤í
npm test -- --coverage
# 2. íì
ì²´í¬
npx tsc --noEmit
# 3. ë¦°í¸ íì¸
npm run lint
# 4. ì´ì ëìê³¼ ë¹êµ (ì¤ë
ì· í
ì¤í¸)
npm test -- --updateSnapshot
Step C: Document Changes
## Refactoring Summary
### Changes Made
1. [ë³ê²½ 1]: [ì´ì ]
2. [ë³ê²½ 2]: [ì´ì ]
### Behavior Preserved
- [x] ëì¼í ì
ë ¥ â ëì¼í ì¶ë ¥
- [x] ë¶ì í¨ê³¼ ëì¼
- [x] ìë¬ ì²ë¦¬ ëì¼
### Risks & Follow-ups
- [ì ì¬ì ìí]
- [íì ìì
]
### Test Status
- [ ] Unit tests: passing
- [ ] Integration tests: passing
- [ ] E2E tests: passing
Troubleshooting
Issue: Tests fail after refactor
Cause: ëì ë³ê²½ì´ ë°ìí¨ Solution: ëëë¦¬ê³ ë³ê²½ì 격리íì¬ ì¬ìë
Issue: Code still complex
Cause: íëì í¨ìì ì¬ë¬ ì± ì í¼í© Solution: ëª íí ê²½ê³ë¡ ë ìì ë¨ì ì¶ì¶
Issue: Performance regression
Cause: ë¹í¨ì¨ì ì¸ ì¶ìí ëì Solution: íë¡íì¼ë§ í í« í¨ì¤ ìµì í
Multi-Agent Workflow
Validation & Retrospectives
- Round 1 (Orchestrator): íë ë³´ì¡´ ì²´í¬ë¦¬ì¤í¸ ê²ì¦
- Round 2 (Analyst): ë³µì¡ë ë° ì¤ë³µ ë¶ì
- Round 3 (Executor): í ì¤í¸ ëë ì ì ë¶ì ê²ì¦
Agent Roles
| Agent | Role |
|---|---|
| Claude | 리í©í ë§ ê³í, ì½ë ë³í |
| Gemini | ëê·ëª¨ ì½ëë² ì´ì¤ ë¶ì, í¨í´ íì§ |
| Codex | í ì¤í¸ ì¤í, ë¹ë ê²ì¦ |
Workflow Example
# 1. Gemini: ì½ëë² ì´ì¤ ë¶ì
ask-gemini "@src/ ë³µì¡ë ëì í¨ì ëª©ë¡ ì¶ì¶"
# 2. Claude: 리í©í ë§ ê³í ë° ì¤í
# IMPLEMENTATION_PLAN.md ê¸°ë° ìì
# 3. Codex: ê²ì¦
codex-cli shell "npm test && npm run lint"
References
Metadata
ë²ì
- íì¬ ë²ì : 1.0.0
- ìµì¢ ì ë°ì´í¸: 2025-01-01
- í¸í íë«í¼: Claude, ChatGPT, Gemini
ê´ë ¨ ì¤í¬
íê·¸
#refactoring #code-quality #DRY #SOLID #design-patterns #clean-code