# duplication 기준 ## 목적 중복은 무조건 제거하지 않는다. 반복 수정 비용이 큰 **진짜 중복**은 제거하고, 서로 다른 이유로 바뀔 가능성이 있는 **우연히 비슷한 코드**는 성급히 합치지 않는다. ## 공식/실무 기준 요약 - 중복 코드는 수정/리팩터링 시 같은 변경을 여러 곳에 반복하게 만들고, 누락 위험을 높인다. - 정적 분석 도구는 일정 크기 이상의 구조적 중복을 duplication으로 탐지한다. - 하지만 DRY를 너무 빨리 적용하면 premature abstraction이 생겨 이후 변경을 더 어렵게 만들 수 있다. - 특히 테스트 코드는 production code보다 DRY보다 가독성을 더 우선할 수 있다. ## 기본 규칙 ### 1. 기본 원칙: “같아 보인다”와 “같은 이유로 바뀐다”를 구분 다음 둘을 구분한다. - **진짜 중복** - 같은 의미 - 같은 정책 - 같은 이유로 바뀜 - 한 군데 고치면 나머지도 같이 바뀌어야 함 - **우연한 유사성** - 지금은 비슷해 보여도 - 맥락/책임/변화 이유가 다름 - 나중에 독립적으로 진화할 가능성이 큼 기본적으로 **같은 이유로 바뀌는 경우만 추출**한다. ### 2. Rule of Three를 기본값으로 사용 추상화는 보통 아래 순서를 따른다. - 1회: 그냥 작성 - 2회: 비슷한 패턴을 인식하되 아직 참음 - 3회 이상: 변화 이유가 같다면 추출을 적극 검토 단, 보안/예외 번역/외부 API 호출처럼 실수 비용이 큰 중복은 2회부터도 추출 가능하다. ### 3. 반복 수정 비용이 크면 추출 다음 조건이 크면 중복 제거를 우선 검토한다. - 같은 정책 변경을 여러 파일에 반복해야 함 - 누락 시 장애/보안/데이터 불일치 위험이 큼 - 테스트도 같이 여러 군데 바뀌어야 함 - 팀원이 쉽게 한쪽만 수정할 수 있음 ### 4. 추상화 비용이 더 크면 중복 허용 다음 경우는 중복을 허용한다. - 서로 다른 레이어 책임을 억지로 합쳐야 하는 경우 - 공통화하면 이름이 모호해지는 경우 - 분기 옵션이 계속 늘어나 helper가 더 복잡해지는 경우 - 미래 변화 방향이 아직 불확실한 경우 - 테스트 가독성이 helper 때문에 더 나빠지는 경우 ### 5. 레이어를 넘는 중복 제거는 특히 신중 중복 제거를 위해 레이어 경계를 깨지 않는다. 금지 예: - presentation과 infrastructure의 비슷한 코드라는 이유로 공통 유틸로 합치기 - domain 규칙과 controller 검증을 한 helper로 합치기 - 외부 API 포맷과 내부 도메인 규칙을 같은 mapper로 합치기 ### 6. 복붙보다 작은 추출부터 중복 제거는 아래 순서로 작게 시작한다. 1. local variable 추출 2. private method 추출 3. mapper/helper 추출 4. 같은 클래스 계층이면 pull up / template method 검토 5. 그래도 명확할 때만 더 큰 추상화 처음부터 범용 util/service/common으로 키우지 않는다. ### 7. helper는 “짧아진 코드”보다 “명확해진 이름”이 있을 때만 다음 중 하나가 아니면 helper 추출을 보류한다. - 반복되는 의미를 정확히 설명하는 이름이 있음 - 공통 정책/계약을 하나로 모아야 함 - 테스트/검증/예외 처리 중복을 안정적으로 줄임 “줄 수 있으니까 줄인다”는 이유만으로 추출하지 않는다. ### 8. 테스트는 DRY보다 가독성 우선 가능 테스트는 production code와 기준이 다를 수 있다. 기본: - 테스트는 사람이 바로 읽어 이해할 수 있어야 함 - 과한 helper, loop, setup 공유로 의미가 숨겨지면 중복을 허용 - DAMP를 우선하고, 진짜 반복 보일러플레이트만 줄인다 ### 9. 생성/변환/정책 중복은 추출 우선 다음은 실수 비용이 높아 추출을 우선 검토한다. - 에러 응답 조립 - 외부 API request/response 변환 - 시간 생성/포맷 정책 - 권한/역할 판별 정책 - 공통 validation 규칙 - persistence <-> domain 매핑 규칙 - exception translation 규칙 ### 10. 우연한 한두 줄 중복은 허용 다음은 무리해서 추출하지 않는다. - 간단한 guard clause - 명확한 builder/setter 호출 몇 줄 - 테스트의 준비/검증 코드 - 각 레이어에서 맥락상 당연한 짧은 변환 코드 ### 11. 중복 제거는 behavior-preserving으로 작게 중복 제거는 리팩터링이다. 행동 보존을 전제로 작은 단계로 진행한다. 기본: - 테스트가 있으면 먼저 보호 - 한 번에 큰 범용 추상화로 가지 않음 - 단계적으로 추출 후 검증 ### 12. common/util 모듈은 중복 제거 수단으로 남용 금지 중복을 본다고 바로 `common`, `util`, `helper`로 보내지 않는다. 먼저 묻는다: - 이 중복의 소유 레이어는 어디인가? - 정말 여러 모듈이 같은 이유로 바뀌는가? - 경계를 안 깨고도 추출 가능한가? ### 13. 도구 경고는 “신호”이지 자동 수정 명령은 아님 Sonar/PMD가 duplication을 잡았다고 무조건 추출하지 않는다. 다음 둘을 함께 본다. - 구조적 중복 크기 - 변화 이유의 동일성 ### 14. 문서화 기준 중복을 의도적으로 남겼다면 이유를 짧게 남길 수 있다. 특히 아래 경우: - 테스트 가독성 - 레이어 분리 유지 - 조기 추상화 방지 - 외부 계약의 독립 진화 가능성 ## 프로젝트 기준 요약 - 진짜 중복만 제거 - 같은 이유로 바뀌는 경우만 추출 - Rule of Three 기본 - 레이어 경계를 깨는 공통화 금지 - 작은 추출부터 시작 - 테스트는 DAMP 우선 가능 - 도구 경고는 신호일 뿐 자동 추출 근거가 아님