코드 스멜 탐지
Martin Fowler의 코드 스멜 분류체계, AI를 활용한 자동 탐지, 그리고 실무에서 가장 흔한 스멜과 해결 전략을 배웁니다.
프리미엄 강좌 콘텐츠
이 레슨은 프리미엄 강좌의 일부예요. Pro로 업그레이드하면 모든 프리미엄 강좌와 콘텐츠를 이용할 수 있어요.
- 모든 프리미엄 강좌 이용
- 1000개 이상의 AI 스킬 템플릿 포함
- 매주 새로운 콘텐츠 추가
🔄 이전 레슨에서 리뷰의 우선순위 피라미드를 배웠습니다 — 정확성 → 보안 → 에러 처리 → 설계 → 가독성. 이번 레슨의 “코드 스멜"은 설계와 가독성 영역에 해당합니다. 동작은 하지만, 구조적으로 문제가 있는 코드를 찾아내는 기술입니다.
코드 스멜은 버그가 아닙니다. 테스트도 통과합니다. 하지만 유지보수 비용을 높이고, 미래의 버그 확률을 올립니다. Martin Fowler는 이를 “더 깊은 문제의 표면적 징후"라고 정의했습니다.
배울 내용
이 레슨을 마치면 주요 코드 스멜을 분류하고, AI를 활용해 체계적으로 탐지하며, 각 스멜에 맞는 리팩토링 전략을 선택할 수 있게 됩니다.
5대 코드 스멜 카테고리
Fowler의 분류 체계를 기반으로, 실무에서 가장 자주 만나는 스멜을 정리합니다:
1. Bloaters (비대 스멜)
코드가 너무 커져서 관리가 어려운 상태.
| 스멜 | 증상 | AI 탐지 신호 |
|---|---|---|
| Long Method | 함수가 여러 일을 함 | 주석으로 구분되는 블록, 깊은 중첩 |
| Large Class | 클래스의 책임이 3개 이상 | 메서드 그룹이 서로 다른 필드 사용 |
| Long Parameter List | 매개변수 5개 이상 | 같이 전달되는 파라미터 그룹 |
| Primitive Obsession | 객체 대신 원시 타입 남용 | 같은 원시 타입 그룹이 반복 |
# ❌ Long Method — 주문 처리 + 검증 + 알림 + 로깅을 한 함수에서
def process_order(order):
# 검증 (이 블록 자체가 Extract 신호)
if not order.items:
raise ValueError("빈 주문")
if order.total < 0:
raise ValueError("음수 금액")
for item in order.items:
if item.quantity <= 0:
raise ValueError("잘못된 수량")
# 결제 처리
payment = payment_gateway.charge(order.total)
if not payment.success:
send_notification(order.user, "결제 실패")
return None
# 재고 업데이트
for item in order.items:
inventory.decrease(item.product_id, item.quantity)
# 알림
send_notification(order.user, "주문 완료")
logger.info(f"Order {order.id} processed")
return payment
# ✅ 각 블록을 함수로 분리
def process_order(order):
validate_order(order)
payment = charge_payment(order)
if not payment:
return None
update_inventory(order.items)
notify_completion(order)
return payment
2. Dispensables (불필요 스멜)
제거해도 코드가 더 좋아지는 것들.
- Dead Code — 호출되지 않는 함수, 사용되지 않는 변수
- Duplicate Code — 같은 로직이 2곳 이상에 존재
- Speculative Generality — “나중에 필요할 수 있으니까” 만든 추상화
✅ Quick Check: 동료가 “나중에 확장할 수 있도록” 인터페이스와 추상 클래스를 미리 만들어 놨습니다. 현재 구현체는 하나뿐입니다. 이것은 어떤 스멜인가요? (Speculative Generality입니다. 실제 필요가 생기기 전에 만든 추상화는 코드를 복잡하게만 합니다. “지금 필요하지 않으면 지금 만들지 마라” — YAGNI 원칙. 나중에 진짜 필요할 때 리팩토링하는 게 비용이 더 낮습니다.)
3. Couplers (결합 스멜)
클래스/모듈 간 의존성이 너무 강한 상태.
- Feature Envy — 다른 클래스의 데이터에 과도하게 접근
- Inappropriate Intimacy — 두 클래스가 서로의 private 필드에 접근
- Message Chains —
a.getB().getC().getD()— 체인이 길수록 깨지기 쉬움
AI로 코드 스멜 탐지하기
AI에게 체계적으로 스멜을 찾아달라고 요청하는 프롬프트:
시니어 개발자로서 다음 코드의 코드 스멜을 분석해주세요.
Fowler의 5대 카테고리로 분류해주세요:
1. Bloaters (비대)
2. Object-Orientation Abusers (OO 남용)
3. Change Preventers (변경 방해)
4. Dispensables (불필요)
5. Couplers (결합)
각 스멜에 대해:
- 위치 (파일, 줄 번호)
- 스멜 이름
- 심각도 (🔴 높음 / 🟡 중간 / 🔵 낮음)
- 리팩토링 제안
코드:
{여기에 코드}
이 프롬프트를 사용하면 AI가 단순히 “이 함수가 길어요” 대신, 카테고리 분류 + 구체적 리팩토링 전략까지 제안합니다.
스멜별 리팩토링 매핑
| 스멜 | 리팩토링 패턴 | 다음 레슨 |
|---|---|---|
| Long Method | Extract Method | 레슨 4 |
| Large Class | Extract Class | 레슨 4 |
| Long Parameter List | Introduce Parameter Object | 레슨 4 |
| Duplicate Code | Extract Method + Pull Up | 레슨 4 |
| Feature Envy | Move Method | 레슨 4 |
| Primitive Obsession | Replace Primitive with Object | 레슨 4 |
✅ Quick Check: 스멜 탐지 후 바로 리팩토링하면 될까요? (아닙니다. 먼저 테스트가 있는지 확인하세요. 테스트 없이 리팩토링하면 동작이 바뀌었는지 알 수 없습니다. 순서: 1) 스멜 발견 → 2) 테스트 확인/추가 → 3) 리팩토링 → 4) 테스트 통과 확인.)
핵심 정리
- 코드 스멜은 버그가 아니라 구조적 문제의 징후 — 동작하지만 유지보수 비용을 높입니다
- Fowler의 5대 카테고리(Bloaters, OO Abusers, Change Preventers, Dispensables, Couplers)를 사용하면 분류와 해결이 체계적입니다
- Long Method가 가장 흔한 스멜 — “주석으로 구분되는 블록이 있으면 Extract Method의 기회”
- AI에게 카테고리 분류 체계를 알려주면, 스멜 탐지 + 리팩토링 제안을 한 번에 받을 수 있습니다
- 리팩토링 전에 반드시 테스트 존재를 확인하세요
다음 레슨
스멜을 찾았습니다. 이제 고칠 차례입니다. 다음 레슨에서는 실무에서 가장 자주 쓰는 리팩토링 패턴 — Extract Method, Replace Conditional with Polymorphism, Introduce Parameter Object — 을 AI와 함께 안전하게 실행하는 방법을 배웁니다.
이해도 체크
먼저 위의 퀴즈를 완료하세요
레슨 완료!