Files

5.7 KiB

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