---
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<AnimalType, string> = {
  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]]
