본문 바로가기
여러가지

가짜중복과 진짜중복

by 고선제 2024. 11. 14.

[가짜중복과 진짜중복]

개발자들은 공부하면서 코드의 중복은 최대한 줄여야한다고 정말 많이 듣습니다. 코드의 중복을 줄이는 것이 객체 지향 프로그래밍을 목표 중 하나입니다.

이런 세뇌(?)를 받아서인지 저는 중복 코드를 보기 싫어 최대한 줄이고 싶어했습니다.

하지만 문득 종종 “코드가 중복된다면 무조건 하나로 통일해야할까?!”라는 생각이 들었습니다.

이런 애매모호한 의심을 가지고 개발하던 중 최근에 가짜 중복이라는 단어를 보고 이 글을 작성하게 되었습니다. 가짜 중복에 대해 글을 써보면서 정확한 이해를 해보고자 합니다.

가짜 중복에 대해 제가 고민했던 경우를 바탕으로 아래 예시를 들어보겠습니다.

(변수명 혹은 클래스명이 불편해도 참아주시길 바랍니다)

 

다음은 계약이라는 Contract 클래스가 있고, 그 안에는 계약이라는 상태를 관리해주는 ContractStatus가 있습니다.

public class Contract {

    private int id;
    
    private String title;
    
    private String content;
    
    private ContractStatus contractStatus;
}

 

이 밑은 ContractStatus의 구현 내용입니다.

Approve, Deny, Pending 총 3가지 상태를 가지고 있습니다.

public enum ContractStatus {
    APPROVE,
    DENY,
    PENDING;
}

 

아래는 보험이라는 Insurance 클래스입니다. 이 클래스도 InsuranceStatus라는 Enum클래스로 상태를 관리하는 것을 볼 수 있습니다.

public class Insurance {

    private Long id;

    private String title;

    private String content;

    private InsuranceStatus insuranceStatus;
}

 

이 밑은 InsuranceStatus의 구현 내용입니다.

APPROVE, DENY, PENDING 총 3가지 상태를 가지고 있습니다..

public enum InsuranceStatus {
    APPROVE,
    DENY,
    PENDING;
}

 

두 클래스를 살펴보면 두 클래스 모두 Status라는 상태를 관리해주는 enum클래스를 가지고 있고 3개의 똑같은 상태를 가지고 있습니다.

즉, 코드가 중복이 되고 있습니다. 그래서 저는 ContractStatus와 InsuranceStatus를 합쳐 다음과 같이 코드를 변경했습니다.

public enum ApproveStatus {
    APPROVE,
    DENY,
    PENDING;
}

 

그리고 이를 Contract클래스와 Insurance클래스에 적용하였습니다.

public class Contract {

    private int id;
    
    private String title;
    
    private String content
    
    private ApproveStatus approveStatus;
}
public class Insurance {

    private Long id;

    private String title;

    private String content;

    private ApproveStatus approveStatus;
}

 

이 방법을 사용하여 코드 중복을 제거하였습니다.

하지만 이것은 올바르게 중복을 제거한 것일까? 고민해봐야할 필요성이있습니다.

현재는 프로젝트의 규모가 작기 때문에 혹은 요구사항 정의가 덜 되었기 때문에 Contract의 상태와 Insurance의 상태가 동일한 것은 아닐까?

만약 프로젝트가 커지고 요구하는 상태가 많아진다면 어떨까? 그때도 Contract와 Insurance의 상태가 동일할 수 있을까?

다음은 이해를 돕기 위해 각 Contract와 Insurance에 추가될 수 있을만한 상태를 GPT에게 물어보니 아래와 같이 나열해줬습니다.

 

Contract 상태 목록

  1. DRAFT: 계약이 작성 중인 상태.
  2. PENDING_APPROVAL: 계약이 승인을 기다리는 상태.
  3. APPROVED: 계약이 승인된 상태.
  4. ACTIVE: 계약이 유효하게 실행 중인 상태.
  5. SUSPENDED: 계약이 일시적으로 중단된 상태.
  6. TERMINATED: 계약이 종료된 상태.
  7. EXPIRED: 계약이 만료된 상태.
  8. CANCELLED: 계약이 취소된 상태.

Insurance 상태 목록

  1. QUOTE: 보험 견적 상태.
  2. PENDING_UNDERWRITING: 언더라이팅(심사) 대기 중인 상태.
  3. UNDER_REVIEW: 언더라이팅 심사 중인 상태.
  4. APPROVED: 보험이 승인된 상태.
  5. ACTIVE: 보험이 발효된 상태.
  6. SUSPENDED: 보험이 일시 정지된 상태.
  7. LAPSED: 보험료 미납으로 인해 효력이 상실된 상태.
  8. EXPIRED: 보험 기간이 만료된 상태.
  9. CLAIMED: 보험 청구가 접수된 상태.
  10. SETTLED: 보험 청구가 처리된 상태.
  11. CANCELLED: 보험이 취소된 상태.

위를 보면 모두 동일할 수 없다는 결과가 나옵니다.

[결론]

제가 앞서 설명한 예시는 Contract와 Insurance에 직접적으로 연관된 코드의 중복이었습니다. 이것을 제가 가짜 중복이라고 말하면서 중복을 없애면 안된다고 하였습니다.

 

그래서 가짜 중복과 진짜 중복을 나누는 기준에 대해 얘기해보겠습니다.

제가 검색해보고 이해한 바로는 비즈니스의 영역 차이라고 생각합니다. 이를 쉽게 설명하면 하나의 비지니스 Contract라는 영역 내에서 중복이 일어난다면 이것은 진짜 중복이고, 서로 다른 비즈니스 영역 내에서 중복이 일어난다면 가짜 중복이라고 정의할 수 있을 것 같습니다.

 

주의할 점은 비즈니스 영역이 앞서 설명한 Contract와 Insurance처럼 무조건 도메인으로 구분짓지는 않습니다.

아래는 그 예시입니다.

하나의 비즈니스 영역 내에서도 create DTO와 update DTO가 서로 비슷한 필드를 가지고 있어 명세가 중복될 수 있습니다. 하지만 두 DTO가 처리하는 작업의 목적과 내용이 다르기 때문에 이를 동일한 클래스로 합치는 것은 좋지 않습니다.. create DTO는 새로운 객체를 생성하기 위한 명세를 담고 있고, update DTO는 기존 객체를 수정하기 위한 명세를 담고 있기 때문에, 각 DTO의 역할에 맞게 분리된 클래스로 유지하는 것이 비즈니스 로직의 명확성과 변경에도 유연하게 대처할 수 있습니다.

 

정말 개발에는 정해진 정답은 없는 것 같습니다!

제가 말한 것도 정답은 아니고 이런 고민을 생각해보는 것도 좋을 것 같아 글을 작성한것입니다.

 

 

[Reference]

https://mangkyu.tistory.com/399

'여러가지' 카테고리의 다른 글

우아한 테크코스 7기 최종합격 후기(BE)  (3) 2024.12.31