Files

155 lines
5.7 KiB
Markdown

# 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 우선 가능
- 도구 경고는 신호일 뿐 자동 추출 근거가 아님