DRY(Don’t Repeat Yourself, 중복 배제)는 소프트웨어 개발에서 동일한 지식이나 로직이 시스템 내 여러 곳에 중복되어 존재해서는 안 된다는 설계 원칙이다. 이 용어는 앤디 헌트(Andy Hunt)와 데이브 토머스(Dave Thomas)가 1999년 저서 《실용주의 프로그래머: 견습생에서 명인으로》(The Pragmatic Programmer: From Journeyman to Master)에서 처음 정식화했으며, 두 저자는 이를 시스템 내의 모든 지식은 단일하고 모호하지 않으며 권위 있는 하나의 표현으로만 존재해야 한다는 명제로 규정했다. DRY 원칙이 적용된 시스템에서는 어떤 요소를 수정할 때 논리적으로 무관한 다른 요소까지 함께 고쳐야 하는 상황이 발생하지 않으며, 서로 연관된 요소들은 예측 가능하고 일관된 방식으로 함께 변경된다.
헌트와 토머스는 DRY를 단순히 소스 코드 텍스트의 중복을 피하는 문제로 한정하지 않고, 데이터베이스 스키마, 테스트 계획, 빌드 시스템, 문서화 등 소프트웨어 개발의 전 영역에 걸쳐 폭넓게 적용했다. 이들은 함수와 서브루틴 같은 전통적인 코드 재사용 기법 외에도 코드 생성기, 자동화된 빌드 시스템, 스크립팅 언어 등을 동원해 여러 계층에 걸쳐 지식이 중복되지 않도록 하는 방법을 제시했다. 이후 소프트웨어 개발자 마티아스 베라스(Mathias Verraes) 등은 DRY가 문자 그대로의 코드 중복이 아니라 코드가 표현하는 지식의 중복을 다루는 원칙이라는 점을 강조하며, 겉보기에 동일한 코드라도 서로 다른 의도나 규칙을 표현한다면 이를 하나로 통합하는 것이 오히려 원칙에 어긋날 수 있다고 설명했다.
DRY라는 용어 자체는 1999년에 처음 사용되었지만, 이와 유사한 발상은 이전부터 소프트웨어 공학 여러 갈래에서 독립적으로 등장했다. 베르트랑 메예르(Bertrand Meyer)는 1988년 저서 《객체지향 소프트웨어 구축》(Object-Oriented Software Construction)에서 여러 대안의 목록을 오직 하나의 모듈만이 알고 있어야 한다는 단일 선택 원칙(Single Choice Principle)을 제시했고, 켄트 벡(Kent Beck)은 같은 1999년에 발표한 《익스트림 프로그래밍 설명》에서 단순한 설계가 갖춰야 할 네 가지 규칙 가운데 하나로 “한 번, 오직 한 번만”(Once and Only Once) 원칙을 제시했다. 이러한 사례는 정보와 규칙의 중복을 줄여야 한다는 문제의식이 1980~90년대 객체지향 설계와 애자일 방법론 진영에서 공통적으로 형성되었음을 보여준다.
DRY 원칙은 함수와 클래스 단위의 코드 재사용, 데이터베이스 정규화를 통한 데이터 중복 제거, 관례를 통해 반복적인 설정을 줄이는 프레임워크 설계 등 다양한 층위에서 실천된다. 그러나 이 원칙을 기계적으로 적용해 성급하게 추상화를 만들 경우, 서로 다른 목적을 지닌 요소가 억지로 결합되어 오히려 유지보수가 어려워질 수 있다는 지적도 꾸준히 제기되어 왔다. 소프트웨어 저술가 샌디 메츠(Sandi Metz)는 잘못된 추상화보다 중복을 유지하는 편의 비용이 더 낮은 경우가 있다고 지적했으며, 이는 성급한 추상화를 경계하는 AHA(Avoid Hasty Abstractions) 프로그래밍이나 리팩터링 시점을 판단하는 세 번의 규칙(Rule of Three) 같은 보완적 발견법으로 이어졌다. 테스트 코드나 마이크로서비스 간 경계처럼 가독성이나 서비스 간 독립성이 중복 제거보다 우선시되는 영역에서는 DRY의 적용 범위와 방식을 둘러싼 논의가 계속되고 있다.
DRY는 KISS(Keep It Simple, Stupid), YAGNI(You Aren’t Gonna Need It), SOLID 원칙 등 소프트웨어 설계의 다른 지침들과 나란히 언급되는 경우가 많으며, 이들 원칙은 서로 겹치기도 하고 강조점이 다르기도 하다. 이 원칙은 좁게는 개별 함수나 모듈 수준의 코드 재사용 지침으로, 넓게는 시스템 전체에서 지식과 정보의 단일한 출처를 유지해야 한다는 단일 진실 공급원(Single Source of Truth) 개념과 결부되어 논의된다. 소프트웨어 공학 교육과 실무 현장에서 DRY는 코드 품질을 논할 때 가장 자주 언급되는 원칙 가운데 하나로 남아 있다.
정의와 유래
형식적 정의
헌트와 토머스는 《실용주의 프로그래머》에서 DRY 원칙을 시스템 내의 모든 지식은 단일하고 모호하지 않으며 권위 있는 하나의 표현을 가져야 한다는 명제로 정의했다. 이 정의에서 핵심이 되는 단어는 코드가 아니라 지식이다. 두 저자는 이 원칙이 소스 코드 한 줄 한 줄의 문자적 중복을 금지하는 규칙이 아니라, 비즈니스 규칙이나 데이터 형식, 문서, 테스트 계획, 빌드 절차처럼 프로젝트 전반에 존재하는 모든 형태의 결정과 정보에 적용된다는 점을 분명히 했다.
DRY가 성립하는 시스템에서는 하나의 사실이나 규칙이 바뀔 때 그 변경을 반영해야 할 지점이 시스템 내에 단 하나만 존재한다. 반대로 이러한 상태가 지켜지지 않아 동일한 지식이 여러 곳에 중복되어 있는 상태는 흔히 WET로 불린다. WET는 “Write Everything Twice”, “We Enjoy Typing”, “Waste Everyone’s Time” 등 여러 방식으로 풀어 쓰이며, DRY의 반대 개념을 가리키는 통칭으로 통용된다.
지식과 코드의 구분
표면적으로 동일해 보이는 코드라도 항상 같은 지식을 표현하는 것은 아니다. 마티아스 베라스는 서로 다른 두 가지 비즈니스 규칙이 우연히 같은 수치나 로직을 사용하는 경우를 예로 들었다. 예를 들어 장바구니에 담을 수 있는 상품 개수 제한과 배송 상자에 담을 수 있는 상품 개수 제한이 우연히 동일한 상한값을 갖는다고 해서 두 규칙을 하나의 코드로 통합하면, 이후 두 규칙이 서로 다른 이유로 독립적으로 바뀌어야 할 때 원치 않는 결합이 발생한다. 베라스는 이러한 경우를 우연한 중복이라 부르며, DRY 위반 여부를 판단하는 기준은 코드의 겉모습이 아니라 그 코드가 나타내는 지식이나 의도가 실제로 동일한가에 있다고 설명했다.
역사적 배경
실용주의 프로그래머와 원칙의 공식화
DRY 원칙은 1999년 10월 애디슨웨슬리에서 출간된 앤디 헌트와 데이브 토머스의 《실용주의 프로그래머》를 통해 처음 이름이 붙고 정식화되었다. 데이브 토머스는 이후 2001년 애자일 소프트웨어 개발 선언의 공동 서명자 중 한 명으로 참여했으며, 실용주의 서적을 전문으로 출간하는 출판사 프래그매틱 북셸프(Pragmatic Bookshelf)를 공동 창립해 소프트웨어 공학 서적 출간을 이어갔다. 《실용주의 프로그래머》는 이후 여러 대학의 소프트웨어공학 교육과정과 업계의 필독서 목록에 포함되며 DRY라는 용어를 업계 전반에 확산시켰다.
유사 개념의 동시대적 등장
DRY라는 명칭이 붙기 이전에도 유사한 문제의식은 여러 경로로 독립적으로 등장했다. 베르트랑 메예르는 1988년 초판, 1997년 개정판으로 출간된 《객체지향 소프트웨어 구축》에서 단일 선택 원칙을 제시했다. 이 원칙은 시스템이 지원하는 여러 대안의 목록에 관한 지식은 단 하나의 모듈만이 알고 있어야 하며, 그 목록에 변화가 생기면 해당 모듈만 수정하면 되도록 설계해야 한다는 내용이다. 켄트 벡은 1999년 저서 《익스트림 프로그래밍 설명》에서 단순한 설계를 이루는 네 가지 규칙 중 하나로 “한 번, 오직 한 번만”을 제시했으며, 마틴 파울러는 자신의 블로그에서 이 네 규칙의 내용을 정리해 소개했다.
프로그래밍 언어 이론에서도 유사한 개념이 다루어졌다. 벤저민 피어스(Benjamin C. Pierce)는 2002년 저서 《타입과 프로그래밍 언어》(Types and Programming Languages)에서 프로그램의 의미 있는 기능 단위는 소스 코드 내 단 한 곳에서만 구현되어야 한다는 추상화 원칙을 정식화했으며, 이는 DRY의 한 형태로 함께 언급되기도 한다. 이처럼 정보와 규칙의 중복을 줄여야 한다는 발상이 객체지향 설계, 애자일 방법론, 프로그래밍 언어 이론 등 서로 다른 갈래에서 비슷한 시기에 유사한 형태로 나타났다는 점은, 이 문제의식이 특정 저자 한 사람의 독창적 발명이라기보다 당시 소프트웨어 공학계가 공통으로 마주하고 있던 유지보수성 문제에 대한 여러 갈래의 응답이었음을 보여준다.
핵심 구성 요소
DRY 원칙이 다루는 지식의 중복은 크게 세 가지 층위에서 논의된다. 각 층위는 강조하는 대상이 다를 뿐 시스템 내에 존재하는 특정 정보가 단일하고 권위 있는 하나의 표현만을 가져야 한다는 동일한 발상을 공유한다.
graph TD
DRY["DRY 원칙"] --> OAOO["한 번, 오직 한 번만<br/>로직의 중복 배제"]
DRY --> SPOT["단일 진실 공급원<br/>데이터의 단일 표현"]
DRY --> SCP["단일 선택 원칙<br/>대안 목록의 단일 표현"]
로직의 중복 배제: 한 번, 오직 한 번만
가장 널리 알려진 층위는 동일한 계산이나 처리 로직이 여러 함수나 모듈에 걸쳐 중복 작성되지 않고 시스템 내 단 한 곳에만 존재해야 한다는 것이다. 켄트 벡이 제시한 “한 번, 오직 한 번만” 규칙이 이 층위를 대표하며, 함수, 메서드, 클래스, 모듈과 같은 전통적인 추상화 도구를 통해 구현된다.
데이터의 단일 표현: 단일 진실 공급원
두 번째 층위는 데이터에 관한 것이다. 동일한 데이터 항목이 시스템 여러 곳에 별도로 저장되지 않고 단 하나의 신뢰할 수 있는 출처에서만 관리되어야 한다는 개념으로, 흔히 단일 진실 공급원(Single Source of Truth, SSOT 또는 SPOT)이라 불린다. 관계형 데이터베이스의 정규화가 이 층위를 구현하는 대표적인 방식으로 논의된다.
대안의 단일 표현: 단일 선택 원칙
세 번째 층위는 메예르가 제시한 단일 선택 원칙에 해당한다. 시스템이 지원하는 여러 대안이나 옵션의 목록이 있을 때, 그 목록 자체에 대한 지식은 시스템 내 단 하나의 모듈만이 가지고 있어야 하며, 다른 모듈들은 이 목록을 직접 알지 못한 채 해당 모듈을 통해서만 대안을 다루어야 한다는 원칙이다.
실제 적용
코드 수준의 재사용
가장 기본적인 적용은 함수, 서브루틴, 클래스 상속, 제네릭 프로그래밍과 같은 전통적인 기법을 통해 동일한 로직의 반복 작성을 피하는 것이다. 헌트와 토머스는 이러한 전통적 기법에 더해 코드 생성기, 자동화된 빌드 시스템, 스크립팅 언어를 함께 활용함으로써 소스 코드 계층을 넘어 빌드 절차나 설정 파일 계층에서도 지식이 중복되지 않도록 하는 방법을 제안했다.
데이터베이스 정규화
관계형 데이터베이스 설계에서 정규화는 동일한 사실이 여러 테이블에 중복 저장되지 않도록 데이터를 여러 테이블로 분해하고 참조 관계로 연결하는 절차이며, DRY 원칙이 데이터 계층에 적용된 대표적인 사례로 논의된다. 반면 실무에서는 조회 성능 향상이나 시스템 간 데이터 동기화의 편의를 위해 의도적으로 데이터를 중복 저장하는 비정규화 기법도 함께 사용되며, 이는 DRY가 다른 요구사항과 저울질해야 할 지침으로 다루어지는 사례로 볼 수 있다.
프레임워크와 코드 생성
프레임워크 설계 차원에서 DRY를 반영한 대표적 사례로 데이비드 하이네마이어 핸슨(David Heinemeier Hansson)이 만든 웹 프레임워크 루비 온 레일스(Ruby on Rails)가 꼽힌다. 레일스는 반복적인 설정 파일 작성을 줄이는 관례 우선 원칙(Convention over Configuration)을 핵심 설계 철학으로 삼는다. 데이브 토머스는 핸슨과 함께 2005년 《Agile Web Development with Rails》를 공동 집필하며, 레일스가 설정 파일과 코드 주석 작업을 줄임으로써 실용주의 프로그래머의 DRY 원칙을 지향하는 프레임워크라고 소개했다. 이는 DRY 원칙을 만든 저자가 그 원칙을 구현한 프레임워크의 공식 해설서 집필에 직접 참여한 사례이기도 하다. 서버 구성과 배포 절차를 코드로 관리하는 인프라 as 코드(Infrastructure as Code) 관행 역시 반복적인 수동 설정 작업을 코드 형태로 통합함으로써 DRY의 적용 범위를 운영 영역으로 확장한 사례로 논의된다.
추상화 시점의 판단
DRY 원칙을 따르려는 시도는 언제, 어느 시점에 중복을 추상화로 전환할 것인가라는 실무적 질문을 낳는다. 이에 대응해 몇 가지 보완적인 발견적 규칙이 제시되어 왔다.
세 번의 규칙
마틴 파울러 등이 1999년 저서 《리팩터링》에서 소개한 세 번의 규칙(Rule of Three)은 동일한 코드가 처음 등장할 때는 그대로 두고, 두 번째로 유사한 코드가 나타날 때는 중복을 허용하되 주의를 기울이며, 세 번째로 유사한 코드가 등장할 때 비로소 리팩터링을 통해 추상화하라는 지침이다. 이 규칙은 소프트웨어 개발자 돈 로버츠(Don Roberts)의 언급을 인용해 책에 소개되었으며, 중복이 발견되는 즉시 기계적으로 추상화를 시도하기보다 반복되는 패턴이 우연이 아니라는 확신이 설 때까지 기다리라는 절충안으로 논의된다.
성급한 추상화 회피
AHA(Avoid Hasty Abstractions, 성급한 추상화 회피)는 소프트웨어 엔지니어 셰어 스칼렛(Cher Scarlett)이 제시한 용어로, 프런트엔드 개발자 켄트 C. 도즈(Kent C. Dodds)가 2020년 자신의 블로그 글에서 이를 소개하며 널리 알려졌다. 도즈는 이 접근을 매몰비용 오류와 연관지어 설명했다. 즉 엔지니어가 특정 추상화에 깊이 투자할수록 그 투자를 회수할 수 없다는 인식 때문에 요구사항이 바뀌어도 기존 추상화를 계속 고쳐 쓰려는 경향이 생긴다는 것이다. 도즈는 특정 횟수의 중복이 나타나는 즉시 추상화를 시도하기보다, 중복 자체가 실질적인 문제가 되는 시점에 어떤 형태의 추상화가 필요한지 명확해졌을 때 비로소 추상화하는 편이 더 유연하고 견고한 코드로 이어진다고 설명했다.
관련 논쟁과 비판적 시각
잘못된 추상화에 대한 비판
소프트웨어 저술가 샌디 메츠는 2016년 글 “The Wrong Abstraction”에서, 겉보기에 비슷한 코드를 성급하게 하나의 추상화로 묶은 뒤 이후 요구사항이 갈라지면서 그 추상화 내부에 조건 분기가 계속 덧붙는 상황을 지적했다. 메츠는 이런 경우 잘못된 추상화를 유지하며 조건 분기를 계속 쌓아 올리기보다, 차라리 중복된 코드를 그대로 둔 채 각각을 독립적으로 다루는 편의 비용이 더 낮다는 견해를 밝혔다. 이러한 관점은 이후 AHA 프로그래밍을 비롯해 성급한 추상화를 경계하는 여러 논의에서 자주 인용되는 근거가 되었다.
테스트 코드에서의 DAMP
구글의 소프트웨어 엔지니어링 관행을 정리한 2020년 저서 《Software Engineering at Google》은 테스트 코드에서는 DRY보다 DAMP(Descriptive And Meaningful Phrases)를 우선해야 한다고 설명한다. 이 책은 테스트 간에 공통 로직을 추출해 중복을 없애려는 시도가 오히려 각 테스트가 무엇을 검증하는지 한눈에 파악하기 어렵게 만들 수 있다고 지적하며, 테스트 코드에서는 가독성과 개별 테스트의 독립적 이해 가능성이 중복 제거보다 우선시되어야 하는 경우가 있다고 설명한다. 다만 이 책은 값이나 설정과 같은 일부 요소는 여전히 공유하는 것이 합리적이라는 절충적 입장도 함께 제시한다.
마이크로서비스 아키텍처에서의 긴장
소프트웨어 컨설턴트 샘 뉴먼(Sam Newman)은 2021년 저서 《Building Microservices》 2판에서, 여러 마이크로서비스가 공통 로직을 공유 라이브러리로 추출하는 방식이 코드 중복은 줄이지만 서비스 간 결합도를 높여 독립적인 배포와 팀 간 자율성이라는 마이크로서비스 아키텍처의 목표를 저해할 수 있다고 설명했다. 이러한 논의는 분산 시스템에서는 DRY를 서비스 경계를 넘어 기계적으로 적용하기보다, 결합도 증가라는 대가와 함께 견주어 판단해야 한다는 관점으로 제시된다.
경험적 연구 결과
소프트웨어 공학 연구에서는 중복된 코드, 이른바 코드 클론을 자동으로 탐지하고 그 영향을 분석하는 연구가 오랫동안 이루어져 왔다. 다블리시 라탄(Dhavleesh Rattan), 라제시 바티아(Rajesh Bhatia), 마닌더 싱(Maninder Singh)이 2013년 학술지 《Information and Software Technology》에 발표한 체계적 문헌 검토는, 복사와 붙여넣기를 통한 코드 재사용이 실제 소프트웨어 개발에서 흔히 나타나는 활동이며 코드 클론이 결함의 전파와 유지보수 문제로 이어질 수 있다고 정리했다. 이 분야의 연구는 주로 중복 코드를 탐지하는 기법을 개발하고 그 분포와 영향을 분석하는 데 초점을 맞추고 있으며, 중복 코드가 실제 유지보수 비용에 미치는 영향의 구체적인 정도는 분석 대상 시스템과 연구 방법에 따라 다르게 보고된다.
관련 개념과의 비교
DRY는 소프트웨어 설계를 논할 때 다른 여러 원칙과 나란히 언급되며, 이들 원칙은 서로 겹치는 부분도 있고 강조점이 다른 부분도 있다.
| 원칙 | 최초 제시자 또는 문헌 | 핵심 초점 |
|---|---|---|
| DRY | 앤디 헌트, 데이브 토머스 (1999) | 지식과 로직의 중복 배제 |
| KISS | 미 해군 및 켈리 존슨(Kelly Johnson)과 관련된 용례 (1960년대) | 설계와 구현의 단순성 |
| YAGNI | 켄트 벡 등, 익스트림 프로그래밍 (1990년대 말) | 당장 필요하지 않은 기능의 선제적 구현 지양 |
| SOLID | 로버트 C. 마틴(Robert C. Martin) (2000년대 초) | 객체지향 클래스 설계의 응집도와 유연성 |
KISS는 단순성을 강조하는 원칙으로, 중복 제거를 위한 추상화가 과도한 간접 참조나 복잡한 구조를 만들어낼 경우 KISS와 긴장 관계에 놓일 수 있다는 점이 함께 논의된다. YAGNI는 당장 필요하지 않은 기능을 미리 만들지 말라는 원칙으로, 이미 존재하는 중복을 제거하라는 DRY와는 초점이 다르지만 두 원칙 모두 성급한 일반화나 과도한 사전 설계를 경계한다는 공통점을 지닌다. SOLID 원칙 중 단일 책임 원칙은 종종 DRY와 혼동되지만, 단일 책임 원칙은 하나의 클래스가 변경되어야 할 이유를 하나로 유지해야 한다는 응집도에 관한 원칙인 반면 DRY는 동일한 지식이 여러 곳에 흩어져 있는지에 관한 원칙이라는 점에서 구분된다. 단일 진실 공급원 개념은 앞서 핵심 구성 요소에서 다룬 것처럼 DRY의 데이터 차원 적용으로 논의되는 경우가 많다.
같이 보기
- 리팩터링
- 코드 스멜
- 관심사의 분리
- 데이터베이스 정규화와 비정규화
- 코드 재사용
- 관례 우선 원칙
- KISS 원칙
- YAGNI
- SOLID 원칙
- 단일 진실 공급원
- 추상화 원칙
- 코드 클론
참고 자료
- Hunt, Andrew; Thomas, David (1999), The Pragmatic Programmer: From Journeyman to Master, Addison-Wesley
- Beck, Kent (1999), Extreme Programming Explained: Embrace Change, Addison-Wesley
- Meyer, Bertrand (1997), Object-Oriented Software Construction (2nd ed.), Prentice Hall
- Fowler, Martin; Beck, Kent; Brant, John; Opdyke, William; Roberts, Don (1999), Refactoring: Improving the Design of Existing Code, Addison-Wesley
- Fowler, Martin (2015), “BeckDesignRules”, martinfowler.com
- Metz, Sandi (2016), “The Wrong Abstraction”, sandimetz.com
- Dodds, Kent C. (2020), “AHA Programming”, kentcdodds.com
- Verraes, Mathias (2014), “DRY is about Knowledge”, verraes.net
- Thomas, Dave; Hansson, David Heinemeier; Breedt, Leon (2005), Agile Web Development with Rails: A Pragmatic Guide, Pragmatic Bookshelf
- Newman, Sam (2021), Building Microservices (2nd ed.), O’Reilly Media
- Winters, Titus; Manshreck, Tom; Wright, Hyrum (2020), Software Engineering at Google: Lessons Learned from Programming Over Time, O’Reilly Media
- Rattan, Dhavleesh; Bhatia, Rajesh; Singh, Maninder (2013), “Software clone detection: A systematic review”, Information and Software Technology, 55(7), 1165–1199
- Pierce, Benjamin C. (2002), Types and Programming Languages, MIT Press
- Martin, Robert C. (2002), Agile Software Development, Principles, Patterns, and Practices, Prentice Hall
- IEEE-USA InSight (2023), “KISS? ‘Yes.’ TMO? ‘No.’”