--- id: quality-refactoring title: Refactoring — 작은 step / 안전 변경 category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [quality, refactoring, vibe-coding] tech_stack: { language: "Various", applicable_to: ["Engineering"] } applied_in: [] aliases: [refactoring, extract function, rename, move, code smell, inline, parallel change] --- # Refactoring > **작은 reversible step**. 매 step 후 test. Behavior 변경 X — 단지 structure. Martin Fowler 의 카탈로그 + IDE refactoring tools. ## 📖 핵심 개념 - Code smell: 변경 신호. - Extract / Inline / Move / Rename. - Test first — 안전망. - Parallel change — 큰 변경 점진. ## 💻 코드 패턴 ### 가장 일반 refactoring ``` 1. Extract function/method: 긴 function → 작은 function 2. Inline: 과도한 indirection 제거 3. Rename: 의미 명확 4. Move: 적절 위치 5. Extract variable: 복잡 expression 명명 6. Replace conditional with polymorphism 7. Replace magic number with constant 8. Encapsulate field ``` ### Extract function (가장 자주) ```ts // Before function processOrder(order: Order) { // Calculate tax (10 lines) let tax = 0; for (const item of order.items) { tax += item.price * 0.08; } // Calculate shipping (15 lines) let shipping = 0; if (order.weight > 10) shipping = 20; else if (order.weight > 5) shipping = 10; else shipping = 5; // Apply discount (8 lines) // ... return order.subtotal + tax + shipping - discount; } // After function processOrder(order: Order) { const tax = calculateTax(order.items); const shipping = calculateShipping(order.weight); const discount = applyDiscount(order); return order.subtotal + tax + shipping - discount; } function calculateTax(items: Item[]): number { return items.reduce((sum, i) => sum + i.price * 0.08, 0); } function calculateShipping(weight: number): number { if (weight > 10) return 20; if (weight > 5) return 10; return 5; } ``` → 의미 명명 + test 가능. ### Replace conditional with polymorphism ```ts // Before class Animal { sound(): string { if (this.type === 'dog') return 'Woof'; if (this.type === 'cat') return 'Meow'; if (this.type === 'cow') return 'Moo'; return ''; } } // After abstract class Animal { abstract sound(): string; } class Dog extends Animal { sound() { return 'Woof'; } } class Cat extends Animal { sound() { return 'Meow'; } } class Cow extends Animal { sound() { return 'Moo'; } } ``` 또는 lookup table: ```ts const sounds: Record = { dog: 'Woof', cat: 'Meow', cow: 'Moo', }; function sound(type: AnimalType): string { return sounds[type]; } ``` ### Parallel change (큰 변경) ``` 3 phase: 1. Expand: New 가 추가됨 (old 도 keep) 2. Migrate: 사용자가 new 로 이동 3. Contract: Old 제거 각 phase = deployable. ``` ```ts // Phase 1: Add new method class API { oldMethod(x: number) { return x * 2; } newMethod(x: number, y: number) { return x * 2 + y; } } // Phase 2: Migrate callers (PR by PR) api.oldMethod(5) → api.newMethod(5, 0) // Phase 3: Remove old method class API { newMethod(x: number, y: number) { ... } } ``` → Big bang 보다 안전. ### Strangler fig ``` 큰 system 의 일부 점진 교체: Phase 1: Old system 그대로. Phase 2: New system + facade — 일부 traffic. Phase 3: 점진 traffic 이동. Phase 4: Old system 제거. ``` ```ts // Facade class OrderService { async create(order: Order) { if (featureFlag('use-new-system')) { return newSystem.create(order); } return oldSystem.create(order); } } ``` ### Code smells (refactor 신호) ``` 1. Long method (50+ lines): extract function 2. Large class (500+ lines): extract / split 3. Long parameter list (5+): parameter object 4. Duplicate code: extract + reuse 5. Switch statements: polymorphism / lookup 6. Feature envy (다른 class 의 데이터): move method 7. Data clumps (같은 그룹 매번): data class 8. Primitive obsession: value object 9. Comments explaining what: extract function (이름 붙임) 10. Dead code: delete ``` ### Test first ```ts // 1. Test 작성 (현재 behavior) test('processOrder calculates correctly', () => { const order = makeOrder(...); expect(processOrder(order)).toBe(95.20); }); // 2. Refactor function processOrder(order: Order) { const tax = calculateTax(order.items); // ... } // 3. Test 통과 = behavior 같음 ``` ### IDE refactoring (안전) ``` VS Code / WebStorm: - F2: Rename (모든 reference) - Ctrl+Shift+R: Extract method - Ctrl+Alt+M: Extract variable - Move file (drag) - Auto-import organize → Manual 보다 안전 + 빠름. ``` ### TS 의 점진 typing ```ts // Phase 1: any 만 function process(input: any): any { ... } // Phase 2: 입력 type function process(input: Order): any { ... } // Phase 3: 출력 type function process(input: Order): Result { ... } // Phase 4: 내부 변수 type ``` → 점진 strict. ### Inline (과도 indirection 제거) ```ts // Before function getEmail(user: User): string { return user.email; } const email = getEmail(user); // 의미 없는 wrapping // After const email = user.email; ``` ### Rename (semantic) ```ts // Before function calc(x: number, y: number) { ... } // After function calculateTotalPrice(quantity: number, unitPrice: number) { ... } ``` → 의미 명확. ### Extract variable ```ts // Before if (order.items.length > 10 && order.totalAmount > 1000 && order.user.tier === 'gold') { // ... } // After const isLargeOrder = order.items.length > 10; const isHighValue = order.totalAmount > 1000; const isVipUser = order.user.tier === 'gold'; if (isLargeOrder && isHighValue && isVipUser) { // ... } ``` ### Encapsulate field ```ts // Before class User { email: string; // 누가나 변경 가능 } user.email = '...'; // validation 없음 // After class User { #email: string; get email(): string { return this.#email; } setEmail(value: string) { if (!isValid(value)) throw new Error('invalid'); this.#email = value; } } ``` ### Replace magic number ```ts // Before if (statusCode === 429) { ... } // After const TOO_MANY_REQUESTS = 429; if (statusCode === TOO_MANY_REQUESTS) { ... } // 또는 import { StatusCode } from './http-status'; if (statusCode === StatusCode.TooManyRequests) { ... } ``` ### Move method to better class ```ts // Before — Order class 가 customer 데이터 사용 class Order { getCustomerDiscount() { return this.customer.tier === 'gold' ? 0.1 : 0; } } // After — Customer class 안 class Customer { getDiscount() { return this.tier === 'gold' ? 0.1 : 0; } } ``` → Feature envy 제거. ### Replace inheritance with composition ```ts // Before class Reader extends FileSystem { ... } // After class Reader { constructor(private fs: FileSystem) { ... } } ``` ### Simplifying conditionals ```ts // Before if (x) { return true; } else { return false; } // After return Boolean(x); // Before if (x === null || x === undefined) return defaultVal; return x; // After return x ?? defaultVal; ``` ### Refactor in sprint ``` Friday: refactor day. 또는 매 PR 의 작은 cleanup. 큰 refactor = 별 sprint 또는 분기. ``` ### Continuous refactoring ``` Boy scout rule + 매 PR + IDE 도구 = 코드 점차 개선. Big-bang refactor 거의 안 함. ``` ### When NOT to refactor ``` - 작동하는 코드 + 안 변경할 영역 - Critical path + test 없음 - Deadline 임박 - 이해 안 됐을 때 (먼저 이해) - 명확 owner X ``` → Refactor = 변경 시 우선. ### Communication ``` PR description: "This PR is pure refactor — no behavior change. Reduces complexity score from 25 → 12." → Reviewer 가 변경 검사. ``` ### Test gap (refactor 전) ``` Test 없으면: 1. 작은 black-box test (입력/출력) 2. Refactor 3. Test 가 behavior lock ``` ### Tools ``` - VS Code / WebStorm refactoring - ESLint --fix - ts-prune (unused exports) - knip (unused files / deps) - prettier (style — refactor 의 friend) - AI assist (Cursor, Copilot) ``` ### Refactor categories (Fowler) ``` 1. Composing methods 2. Moving features between objects 3. Organizing data 4. Simplifying conditional expressions 5. Making method calls simpler 6. Dealing with generalization 7. Big refactorings ``` → refactoring.com 무료. ## 🤔 의사결정 기준 | 상황 | 추천 | |---|---| | 매 PR | Boy scout (작은 cleanup) | | Code review 발견 | 즉시 또는 follow-up issue | | Hot spot (자주 변경) | 우선 refactor | | 큰 architecture | Strangler fig + parallel change | | Library version | Phased migration | | Critical path | Test 먼저 | ## ❌ 안티패턴 - **Big bang refactor**: 깨짐 위험. - **Test 없는 refactor**: behavior 변경 모름. - **Refactor + new feature 같은 PR**: review 어려움. - **Style only refactor**: lint / formatter 가 처리. - **모든 코드 refactor 시도**: focus 잃음. - **이해 못 한 코드 refactor**: bug 가능성. - **Refactor 미공지 (대규모)**: surprise. ## 🤖 LLM 활용 힌트 - 작은 reversible step. - IDE refactoring 도구 활용. - Test first 안전. - Parallel change / strangler 큰 변경. ## 🔗 관련 문서 - [[Quality_Tech_Debt]] - [[Productivity_Code_Review]] - [[Testing_Test_Pyramid]]