우테코 5기

도메인 엔티티 ID 부여에 대한 주관적인 생각

teo_99 2023. 5. 27. 13:55

스프링과 데이터베이스 개념을 처음 접하고나서부터 가장 큰 고민은 '도메인 엔티티에 ID를 부여하는 기준은 무엇인가?' 이었습니다. 그리고 레벨 2를 마쳐가는 지금, 어느정도 저만의 생각이 확립된 것 같아 기록의 목적으로 아티클을 작성해두고자 합니다. 추후에 '이때는 이런 생각을 했었구나!' 라는 생각이 들 수 있도록이요. 따라서 아래 내용은 주관적인 생각이 대부분입니다.
 
 

ID의 필요성

영속성 개념을 접하게되면 겪는 가장 큰 문제점은 객체지향과 영속화 사이의 괴리감(패러다임의 불일치)입니다. 분명 객체지향적으로 짜야 하는데, 데이터 중심 설계를 하게 되는 경우도 많고 도메인 엔티티와 영속성 엔티티를 분리하기가 어려운 등... 여러 문제들이 발생합니다. 그리고 이런 괴리감이 드는 이유 중 하나가 도메인 엔티티에 식별자(ID)가 들어가서일텐데요.
 
레벨1을 진행하면서 순수 자바 객체로만 설계를 할 때는 ID가 필요하지 않았습니다. 클라이언트마다 각자의 저장소를 사용하기 때문입니다. 즉, 객체를 식별할 필요가 없어지는거죠. 하지만 웹 개념이 들어오면서 모든 클라이언트는 하나의 저장소를 공유하기 시작합니다. 흔히 Repository라고 부르는 개념이죠.
 
하나의 저장소를 공유하면서 객체간의 식별자가 필요해지게 됩니다. 장바구니 어플리케이션이라고 가정하면, 장바구니가 누구의 장바구니인지 식별할 필요가 존재합니다. 그리고 장바구니를 갖고 있는 멤버도 식별되어야 합니다. 만약 장바구니 어플리케이션에서 Member라는 객체가 ID를 갖고 있지 않다면 어떻게 될까요?
 

public class Member {
	
    private final String email;
    private final String password;
    
    ...
}

 
어떤 멤버가 다른 멤버와 같은지는 무엇으로 판단할까요? email + password에 대한 동등성 비교를 수행할까요? 만약 비즈니스 규칙이 '이메일은 중복되어도 된다'라면요?
 
그리고 다음과 같은 상황에서는 어떨까요?

public class MemberRepository {

	...
    
    public void update(Member member) {
    	// ID가 없는데... 무엇을 기준으로 수정하지?
        // 기존 정보는 무엇이었을까?
    }
}

 Member의 정보가 업데이트 되었다면(이메일, 비밀번호 모두 변경) Repository에 접근하기가 어렵습니다. 식별자가 없으니 이 멤버 객체가 어떤 멤버 객체인지 알 수가 없는거죠. 물론 이메일은 고유해야 한다는 비즈니스 규칙이 있다면 찾을 수 있기는 하나, 이는 불완전한 설계라고 생각합니다. 비즈니스  요구사항은 언제든지 바뀔 수 있는 부분인데 저장소가 이에 직접적으로 의존하는 구조가 되니까요. 만약 'email은 고유하지 않아도 된다' 라는 비즈니스 규칙이 추가되면 변경사항이 너무나도 많습니다. 데이터베이스를 영속화 도구로 사용하고 있다고 한다면 쿼리까지 전부 바뀌어야 합니다.
 
따라서 1. 영속화 과정 관리의 어려움, 2. 동등성 비교의 어려움이 있으므로 도메인 엔티티에서는 ID를 사용하면 좋은 경우가 많습니다.
 
 

ID를 부여하는 기준은?

그렇다면 어느 객체까지 ID를 부여해야 할까요?
이는 답이 없는 문제라고 생각합니다. 즉, 비즈니스 요구사항에 따라 결론이 달라진다고 생각합니다. 그리고 ID를 부여하는 핵심 기준은 '해당 비즈니스에서 추적해야 하는 대상인가'라고 생각합니다. 그리고 DDD에서는 이를 엔티티, 혹은 Reference Object라고 부르기도 합니다.
 
예시를 들어보겠습니다. 비즈니스 요구사항이 다음과 같이 주어졌다고 해보겠습니다.
 

  1. 멤버는 이메일과 비밀번호를 가지는데, 이 두 가지 정보는 수정이 가능하다.
  2. 상품은 이름, 가격을 가지는데, 이 두 가지 정보는 수정이 가능하다. 

 
위 장바구니 어플리케이션에서 멤버는 고유해야합니다. 멤버 정보가 같다고 해서 같은 멤버라는 결론이 나서는 안된다는 의미입니다. 즉, 멤버라는 자원은 값이 어떻게 변하냐에 관계없이 추적되어야 합니다. 어떤 사람이 회원정보관리 페이지에 들어가 이메일, 비밀번호를 수정했는데 다른 사람의 장바구니 페이지를 보게된다면 얼마나 당혹스러울까요.
 
상품도 마찬가지입니다. 이름, 가격이라는 속성을 가지는데 두 가지 정보가 수정되었다고 해서 다른 상품이 되어버리면 안되겠죠. 상품도 고유하게 추적해야 하는 대상입니다. 
 
따라서 멤버, 상품에 대해 ID를 부여하는 건 영속화 과정 및 동등성 비교에 있어 큰 도움이 될 것 같다는 생각이 듭니다.
 
반면 이메일, 비밀번호, 이름, 가격 등은 다릅니다. 피자의 가격인 '2만원'과 치킨의 가격인 '2만원'은 서로 다른 의미를 가질까요? 값이 같다면 같은 객체로 봐도 됩니다. 그리고 앞서 말했던 ID 필드가 없었을 때의 문제점 두 가지, 1. 영속화과정 관리의 어려움, 2. 동등성 비교의 어려움을 가지지 않습니다. 이메일, 비밀번호, 이름, 가격 등의 속성은 단독으로 저장/복원되지 않으니까요. 
 
 
 

정리

즉, ID 부여에 대한 기준을 요약하자면 다음과 같습니다.
 

  • 비즈니스에서 해당 객체가 추적되어야 하는가? 즉, 고유하게 식별되어야 하는가? -> ID 필드 부여
  • 비즈니스에서 해당 객체는 추적될 필요가 없는가? 즉, 값이 같다면 같은 객체인가? -> ID 필드 부여 X

그리고 도메인에 ID가 부여되는 것은 순수 객체지향 설계가 아니지 않나! 라는 의견도 많은데, 저도 동의합니다. 영속화/복원에 대한 어떠한 가정을 하고 있으니까요. 하지만 웹 어플리케이션을 만들기로 했고, 서비스를 제공하기로 했다면 어느정도 내어줘야 하는 부분이라고 생각합니다.
 
현실의 요구사항은 복잡하고 항상 순수한 객체지향 설계, 순수한 데이터 중심 설계를 할 순 없다고 생각합니다. 중요한 것은 이들을 잘 조절해 비즈니스에 맞는 어플리케이션을 만드는 힘이죠. 
 
이렇게 생각하는 건 제가 아직 지식이 얕기 때문일수도 있습니다. 하지만 적어도 레벨2를 마쳐가는 시점에는 이렇게 생각을 하고 있었고, 이를 기록함으로서 추후에 생각을 발전시키는 계기가 되었으면 합니다.
 
혹시 내용에 대해 의문이 드시거나, 지적할만한 부분이 있다면 언제든지 댓글 부탁드립니다 😃