흔히 반복되지만 결과가 나쁜 설계.
대표적인 것들
-
God Object — 한 클래스가 너무 많은 책임을 갖는다
- 아무도 못 고치는 코드가 된다
- SRP 로 쪼갠다
-
Spaghetti Code — 흐름이 얽혀 따라갈 수 없다
- 깊은 중첩 · 전역 상태 · goto 성 분기
-
Golden Hammer — 익숙한 도구를 모든 문제에 쓴다
- "모든 게 못으로 보인다"
-
Lava Flow — 아무도 안 쓰지만 지우기 무서워 남아 있는 코드
- 테스트가 없어서 못 지운다
-
Magic Number — 의미를 알 수 없는 숫자가 코드에 박혀 있다
- 상수로 이름을 준다
-
Premature Optimization — 측정 없이 최적화한다
- 복잡도만 늘고 실제 병목은 다른 곳이다
-
Copy-Paste — 같은 로직이 여러 곳에 복제된다
- 한 곳만 고치고 나머지를 놓친다
패턴 자체가 안티패턴이 되는 경우
- 구현이 하나뿐인데 인터페이스를 만든다
- 바뀔 일이 없는 것을 Strategy 로 추상화한다
- 세 줄짜리 로직을 Command 객체로 감싼다
- 팩토리를 만드는 팩토리를 만든다
"패턴을 썼다" 가 목표가 되면 복잡도만 남는다 패턴은 '실제로 바뀌는 축' 을 찾았을 때 그 축에만 적용한다
리팩토링으로 가는 경로
- 긴 if-else 체인 → Strategy · 다형성
- 타입 코드로 분기 — → State · 다형성
- 생성자 인자가 너무 많다 — → Builder
- 조건에 따라 다른 객체 생성 → Factory
- 기능 조합이 폭발한다 — → Decorator
- 하위 시스템이 복잡하다 — → Facade
- 외부 라이브러리에 묶였다 — → Adapter
- 순환 의존이 생겼다 — → 이벤트 · Mediator · DIP
언제 리팩토링하나
-
같은 곳을 세 번째 고칠 때 (Rule of Three)
-
새 기능을 넣기 전에 넣기 쉽게 만들 때
-
버그를 고치며 원인 구조를 발견했을 때
-
"언젠가 필요할 것 같아서" 는 근거가 아니다
면접 함정
- ❌ "패턴을 많이 쓴 코드가 좋은 코드" → 필요 없는 추상은 순수한 비용이다.
- ❌ "안티패턴은 실력 부족의 결과" → 마감·요구 변화 속에서 자연스럽게 쌓인다. 알아보고 되돌리는 것이 실력이다.
냄새(smell)와 패턴의 대응
Long Method 메서드가 너무 길다 → 추출 · Template Method
Large Class 클래스가 너무 크다 → 추출 · SRP
Feature Envy 남의 데이터를 자꾸 쓴다 → 메서드를 그쪽으로 옮긴다
Shotgun Surgery 하나 고치면 여러 곳을 고쳐야 → 응집도 재배치
Divergent Change 한 클래스가 여러 이유로 바뀐다 → SRP 로 분리
Primitive Obsession 원시 타입으로 도메인을 표현 → 값 객체
리팩토링의 전제
테스트가 없으면 리팩토링이 아니라 '개조' 다
- 동작이 같다는 것을 보장할 수 없다
순서
- ① 현재 동작을 고정하는 테스트를 먼저 쓴다 (characterization test)
- ② 작게 바꾸고 테스트를 돌린다
- ③ 반복한다
"한 번에 크게 갈아엎기" 는 거의 항상 실패한다
패턴 남용을 판별하는 질문
-
이 추상이 실제로 두 가지 이상의 구현을 갖는가?
-
갖지 않는다면, 6개월 안에 가질 근거가 있는가?
-
이 간접층을 없애면 코드가 더 읽기 쉬워지는가?
-
세 번째 질문에 "그렇다" 면 그 패턴은 부채다