---
title: "잘못된 추상화보다 중복이 낫다는 샌디 메츠의 고전 조언"
published: 2026-06-21T16:08:23.000Z
canonical: https://jeff.news/article/4180
---
# 잘못된 추상화보다 중복이 낫다는 샌디 메츠의 고전 조언

샌디 메츠는 중복을 없애려다 잘못된 추상화를 만들면 코드가 조건문과 파라미터로 부풀어 더 위험해진다고 말한다. 이미 틀어진 추상화는 억지로 보존하지 말고, 다시 호출부에 인라인해서 중복을 되살린 뒤 현재 요구사항에 맞는 새 구조를 찾는 편이 빠르다는 주장이다.

- 샌디 메츠의 핵심 문장은 이거임. “중복은 잘못된 추상화보다 훨씬 싸다.”
  - RailsConf 2014 발표에서 나온 문장이고, 이후에도 계속 반응이 커서 글로 다시 정리한 내용임
  - 보통 개발자는 중복을 보면 본능적으로 뽑아내고 싶어 하는데, 이 글은 그 반사신경에 브레이크를 검

- 잘못된 추상화는 대개 아주 선한 의도에서 시작됨
  - 프로그래머 A가 중복을 발견함
  - 중복을 메서드나 클래스로 추출하고 이름을 붙임
  - 호출부의 반복 코드를 새 추상화로 바꿈
  - 여기까지만 보면 코드가 깔끔해 보이고, 다들 뿌듯하게 퇴근함

- 진짜 문제는 다음 요구사항이 들어오는 순간부터 터짐
  - 새 요구사항은 기존 추상화와 “거의” 맞지만 완전히 같지는 않음
  - 프로그래머 B는 기존 추상화를 유지해야 한다는 압박을 느낌
  - 그래서 파라미터를 하나 추가하고, 그 값에 따라 다르게 동작하는 조건문을 넣음
  - 다음 요구사항이 오면 또 파라미터가 늘고, 또 조건문이 늘어남

> [!IMPORTANT]
> 글에서 말하는 위험 신호는 명확함. 공용 코드에 파라미터와 조건 분기가 계속 붙고 있다면, 그건 더 이상 공통 추상화가 아니라 여러 아이디어가 뒤엉킨 절차 코드일 가능성이 큼.

- 기존 코드는 생각보다 강한 권위를 가짐
  - 이미 존재한다는 사실만으로 “맞고 필요하니까 있는 코드”처럼 보임
  - 심지어 코드가 복잡할수록 “이 정도로 복잡하면 중요한 이유가 있겠지”라는 착각이 생김
  - 메츠는 이걸 매몰 비용 오류(sunk cost fallacy)로 설명함

- 그래서 잘못된 추상화를 만났을 때 빠른 길은 앞으로 더 밀어붙이는 게 아니라 뒤로 감는 것임
  - 추상화된 코드를 각 호출부에 다시 인라인함
  - 각 호출부에서 전달하던 파라미터를 기준으로 실제 실행되는 코드만 남김
  - 해당 호출부에 필요 없는 분기와 코드를 삭제함
  - 이렇게 하면 공용 추상화와 조건문이 사라지고, 각 호출부는 자기에게 필요한 코드만 갖게 됨

- 흥미로운 건, 이렇게 되돌려 보면 “공통”이라고 믿었던 코드가 실제로는 꽤 다르다는 사실이 드러난다는 점임
  - 호출부마다 비슷해 보였지만 실제 실행 경로가 달랐던 경우가 많음
  - 중복을 다시 드러내면 현재 요구사항 기준으로 무엇이 진짜 공통인지 다시 볼 수 있음
  - 그다음에야 새 추상화를 뽑아도 늦지 않음

- 이 글의 조언은 중복을 찬양하자는 얘기가 아님
  - 중복은 여전히 신호이고, 언젠가는 정리할 수 있음
  - 다만 공통점이 충분히 검증되기 전에 추상화하면 나중에 훨씬 비싼 빚이 됨
  - 잠깐 조건문 몇 개를 쌓아 패턴을 관찰하는 건 괜찮지만, 틀렸다는 게 보이면 빨리 버리는 편이 덜 아픔

- 결론은 꽤 실전적임. 틀린 추상화가 보이면 중복을 다시 도입하라
  - 그건 후퇴가 아니라 더 나은 방향으로 가기 위한 리셋임
  - 특히 팀 코드에서 “공용이라 건드리기 무서운 함수”가 계속 커지고 있다면 이 글을 다시 읽을 타이밍임

---

## 기술 맥락

- 여기서 말하는 선택은 “중복을 제거할 것인가, 잠깐 남겨둘 것인가”예요. 중복 제거가 항상 이득처럼 보이지만, 요구사항이 아직 안정되지 않았을 때는 공통점을 너무 빨리 확정하는 비용이 더 커질 수 있거든요.

- 잘못된 추상화가 무서운 이유는 호출부의 차이를 숨겨버리기 때문이에요. 처음엔 같은 로직처럼 보였는데, 시간이 지나면서 각 호출부가 조금씩 다른 이유를 갖게 되면 파라미터와 조건문이 그 차이를 억지로 떠안게 돼요.

- 메츠가 제안하는 방법은 공용 코드를 다시 호출부에 펼쳐놓고, 각 호출부가 실제로 쓰는 코드만 남기는 거예요. 이렇게 해야 “정말 같은 것”과 “그냥 우연히 비슷했던 것”이 눈에 보이기 때문이에요.

- 이 접근은 리팩터링 순서를 바꾸자는 얘기에 가까워요. 먼저 추상화를 지키려고 애쓰는 대신, 현재 요구사항 기준으로 코드를 다시 관찰하고 나서 새 추상화를 뽑자는 거예요.

## 핵심 포인트

- 중복 제거 자체보다 잘못된 추상화가 더 큰 유지보수 비용을 만든다는 주장
- 처음엔 맞았던 추상화도 요구사항이 바뀌면 조건문 덩어리로 변할 수 있음
- 잘못된 추상화의 신호는 파라미터와 분기 로직이 계속 늘어나는 것
- 해결책은 기존 추상화를 호출부로 되돌리고 각 호출부에 필요한 코드만 남기는 방식
- 매몰 비용 때문에 복잡한 코드를 계속 보존하려는 압박을 경계해야 함

## 인사이트

이 글이 오래된 글인데도 계속 회자되는 이유는 간단함. 리팩터링의 적은 ‘중복’만이 아니라, 팀 전체가 건드리기 무서워하는 그럴듯한 공용 코드이기도 해서임.
