9.8 KiB
9.8 KiB
Rule of Three (3의 법칙)
📌 Brief Summary
**Rule of Three (3의 법칙)**은 소프트웨어 프로그래밍에서 유사한 코드 조각을 언제 리팩토링하여 중복을 피할지 결정하기 위한 경험 법칙(Rule of thumb)입니다 [1]. 마틴 파울러(Martin Fowler)의 저서를 통해 대중화되었으며 돈 로버츠(Don Roberts)가 제안한 "세 번 스트라이크면 리팩토링하라(Three strikes and you refactor)"는 개념으로 요약됩니다 [1, 2]. 즉, 처음이나 두 번째로 비슷한 코드를 작성할 때는 중복을 허용하되, 세 번째로 동일한 코드가 나타날 때는 새로운 프로시저나 메서드로 추출(Extract)하여 추상화해야 한다는 원칙입니다 [1, 3].
📖 Core Content
- 개념의 기원 및 정의: 3의 법칙은 개발자가 리팩토링을 수행해야 하는 최적의 타이밍을 결정하는 지침입니다. 코드를 처음 작성할 때는 그냥 목적에 맞게 구현하고, 두 번째로 비슷한 작업을 할 때는 중복이 신경 쓰이더라도 그대로 진행하며, 세 번째로 동일한 형태의 작업이 반복될 때 비로소 리팩토링을 수행하라는 것입니다 [2].
- 성급한 추상화(Premature Refactoring) 방지: 리팩토링을 시도하는 많은 개발자가 범하는 실수는 코드를 무조건 작게 분할하여 추상화하려는 것입니다. 30줄짜리 코드를 가독성을 높인다는 명목하에 여러 클래스로 잘게 쪼개면, 코드를 읽을 때마다 함수 본문을 추적해야 하므로 오히려 유지보수를 어렵게 만듭니다 [4-6]. 3의 법칙은 사례가 3개 이상 모일 때까지 기다림으로써 공통점과 차이점을 더 명확히 파악하고 올바른 추상화를 찾을 수 있도록 돕습니다 [3].
- 중복 허용 원칙 (WET - Write Everything Twice): 3의 법칙은 때로는 코드 중복을 그대로 두는 것이 더 나은 선택일 수 있음을 시사합니다 [7]. 두 번의 중복 코드만 있을 경우, 이를 리팩토링하고 잘못된 설계를 도입하는 비용이 단순히 중복을 유지보수하는 비용보다 더 클 수 있습니다 [8]. 하지만 세 번째 복사본이 나타나면 유지보수 비용이 리팩토링 비용을 초과하게 되므로 이때 개입합니다 [8].
- 잘못된 추상화보다 저렴한 중복: 개발자 샌디 메츠(Sandi Metz)는 "중복이 잘못된 추상화보다 훨씬 저렴하다(Duplication is far cheaper than the wrong abstraction)"라고 강조했습니다 [9]. 두 코드가 우연히 비슷해 보일 뿐, 서로 다른 개념을 나타내는 경우라면 중복을 유지하는 것이 낫습니다 [9].
⚖️ Trade-offs & Caveats
- 잘못된 추상화의 부작용: 코드를 조기에 추상화할 경우, 새로운 요구사항이 생겼을 때 유연하게 대처하지 못하는 부작용이 발생합니다. 잘못된 추상화를 억지로 새로운 유즈케이스에 맞추기 위해 불리언 매개변수나 if 문 등을 추가하게 되며, 이는 코드를 끔찍하게 꼬이게 만듭니다 [7, 10].
- 원칙의 도그마화 경계: 3의 법칙은 어디까지나 경험에 기반한 가이드라인일 뿐 절대적인 규칙은 아닙니다 [1, 7]. 3번의 중복이 발생했다고 해서 기계적으로 추상화해야 하는 것은 아닙니다. 만약 추출하려는 추상화 개념에 명확한 이름을 붙일 수 없다면, 이는 아직 올바른 추상화를 찾지 못했다는 뜻이므로 억지로 리팩토링하지 말고 더 많은 중복 사례가 나타날 때까지 기다리는 것이 좋습니다 [7].
- 코드 재사용과 유지보수의 역설: 짧은 코드가 항상 가독성이 높은 것은 아닙니다 [11]. 단지 읽기 좋다는 이유만으로 한 번만 쓰일 헬퍼 함수를 무분별하게 만들어내면, 코드를 이해하기 위한 인지적 컨텍스트 스위칭 비용이 증가하여 유지보수를 저해하는 트레이드오프가 존재합니다 [6].
🔗 Knowledge Connections
Related Concepts
[관계 유형 A: 설계 철학 및 원칙]
- DRY (Don't Repeat Yourself)
- 연결 이유: 3의 법칙은 코드의 중복을 방지하는 원칙이므로 DRY 원칙과 직접적인 대척점 혹은 상호 보완 관계에 있습니다.
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: DRY 원칙을 맹목적으로 추구할 때 발생하는 '잘못된 추상화'의 부작용을 이해하고, 왜 때로는 WET(Write Everything Twice) 전략이나 3의 법칙이 실무적으로 더 안전한지 비교할 수 있습니다 [3, 9].
- YAGNI (You Aren't Gonna Need It)
- 연결 이유: 미래를 미리 예측하여 불필요한 기능이나 구조를 만들지 말라는 원칙입니다.
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 두 번의 중복 시점에서 성급하게 공통화 계층을 만들지 말고 세 번까지 기다리라는 3의 법칙의 밑바탕에 깔린 "확실한 필요성이 증명될 때까지 미뤄라"라는 철학을 깊이 이해할 수 있습니다 [8].
[관계 유형 B: 구체적 실행 기법 및 식별]
- Extract Method (함수 추출하기)
- 연결 이유: 세 번째 중복이 발생했을 때 이를 해결하기 위해 가장 우선적으로 실행하게 되는 핵심 리팩토링 무브(Move)입니다 [1].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 3의 법칙이 발동된 이후, 실제로 중복 코드를 어떻게 떼어내고, 변수 유효 범위(Scope)를 어떻게 처리하며, 이름을 어떻게 부여해야 안전하게 함수로 추출할 수 있는지 실천적인 기법을 배울 수 있습니다 [12-16].
- Code Smells (코드 스멜)
- 연결 이유: 3의 법칙은 특정 코드 스멜, 즉 '중복 코드(Duplicated Code)'가 발견되었을 때 언제 조치를 취해야 할지를 알려주는 진단 도구 역할을 합니다.
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 언제 코드가 악취를 풍기기 시작하는지, 그리고 어떤 스멜이 단순한 방치가 아니라 즉각적인 리팩토링을 필요로 하는 수준의 технический 부채(Technical Debt)인지 진단하는 기준을 확립할 수 있습니다 [17, 18].
Deeper Research Questions
- 성급한 리팩토링으로 인해 이미 잘못 생성된 추상화(Wrong Abstraction)를 다시 원래대로 되돌리는(Defactoring 또는 Inline) 과정에서 결함을 최소화하는 가장 효과적인 전략은 무엇인가?
- 두 번의 중복 코드에서 무리하게 리팩토링을 수행했을 때, 추후 새로운 요구사항(Variation)이 추가됨에 따라 유지보수 비용이 기하급수적으로 증가한 구체적인 실무 사례는 어떠한가?
- TDD(Test-Driven Development)의 'Red-Green-Refactor' 라이프사이클 내에서, 3의 법칙은 어느 시기(개별 커밋 단계 vs 기능 완성 후)에 적용하는 것이 팀 생산성 관점에서 가장 이상적인가?
- 프론트엔드 UI 컴포넌트 개발(예: React, Vue)에서도 비즈니스 로직 중심의 백엔드와 동일하게 3의 법칙을 엄격히 적용할 수 있는가, 아니면 시각적 요소라는 특성상 별도의 임계값이 필요한가?
- 추상화를 진행하기 전, 3개의 중복 코드가 단순히 "우연히 똑같은(Accidental duplication)" 코드인지 아니면 "본질적으로 같은 개념의(Essential duplication)" 코드인지 개발자가 정확히 판별할 수 있는 기준이나 지표는 무엇인가?
Practical Application Contexts
- Implementation: 코드를 처음 작성하거나 기존 코드에 버그를 수정할 때 유사한 코드가 보인다고 즉시 별도의 헬퍼(Helper) 함수로 분리하지 않고, 동일한 로직을 세 번째로 복사해서 붙여넣어야 하는 순간에만 추상화 작업을 시작합니다.
- System Design: 소프트웨어 컴포넌트나 모듈을 설계할 때, 초기부터 완벽한 재사용성을 고려한 인터페이스나 추상 클래스를 설계하는 대신(Big Design Up Front), 충분한 중복 구현 사례가 축적된 후 점진적으로 공통 구조를 뽑아냅니다.
- Operation / Maintenance: 기존 레거시 코드를 유지보수할 때, 수많은 플래그(Flag)나 불리언 매개변수로 점철된 이해하기 힘든 공통 함수를 발견하면, 이를 다시 인라인(Inline)하여 중복된 코드로 되돌린 다음 처음부터 올바른 추상화를 재탐색합니다.
- Learning Path: 리팩토링의 개별 기법(어떻게 코드를 수정할 것인가)을 습득한 개발자가, 언제 리팩토링을 해야 하고 언제는 하지 말아야 하는지에 대한 타이밍과 트레이드오프를 학습하는 다음 단계의 지식으로 활용됩니다.
- My Project Relevance: 팀 프로젝트에서 발생하는 과도한 추상화를 방지하기 위한 코드 리뷰 기준으로 활용할 수 있습니다. 팀원이 두 개의 비슷한 코드를 공통화하려고 할 때, "결합도가 높아질 위험이 있으니 세 번째 유즈케이스가 나올 때까지 기다리자"는 객관적 논거로 쓰입니다.
Adjacent Topics
- Over-engineering (오버엔지니어링)
- 확장 방향: 3의 법칙을 무시하고 너무 조기에 공통화를 시도했을 때, 시스템 아키텍처가 실제로 필요하지 않은 복잡성을 띄게 되는 오버엔지니어링 현상과 그 비용적 손실을 확장하여 조사할 수 있습니다.
- Technical Debt (기술 부채)
- 확장 방향: 3의 법칙을 지키지 않아 방치된 중복 코드로 인해 발생하는 유지보수 부채와, 반대로 너무 이른 추상화로 인해 발생하는 아키텍처 부채 중 어떤 부채가 이자가 더 비싼지 비교 연구해 볼 수 있습니다.
Last updated: 2026-05-03