도출한 모델은 크게 엔티티(Entity)와 밸류(Value)로 구분할 수 있다. 엔티티와 밸류를 제대로 구분해야 도메인을 올바르게 설계하고 구현할 수 있기 때문에 이 둘의 차이를 명확하게 이해하는 것은 도메인을 구현하는 데 있어 중요하다.

엔티티

엔티티의 가장 큰 특징은 **식별자**를 갖는다는 것이다. 식별자는 엔티티 객체마다 고유해서 각 엔티티는 서로 다른 식별자를 갖는다. (ex. 주문 도메인의 각 주문은 주문번호라는 식별자를 갖는다. 이 주문번호는 각 주문마다 서로 다르다) 주문에서 배송지 주소나 상태가 바뀌더라도 주문번호가 바뀌지 않는 것처럼 엔티티의 식별자는 바뀌지 않는다. 엔티티를 생성하고 엔티티의 속성을 바꾸고 엔티티를 삭제할 때까지 식별자는 유지된다. 엔티티의 식별자는 바뀌지 않고 고유하기 때문에 두 엔티티 객체의 식별자가 같으면 두 엔티티는 갖다고 판단할 수 있다.

엔티티 식별자의 생성

엔티티의 식별자를 생성하는 시점은 도메인의 특징과 사용하는 기술에 따라 달라진다. 흔히 식별자는 다음 중 한 가지 방식으로 생성한다.

주문번호, 운송장번호, 카드번호와 같은 식별자는 특정 규칙에 따라 생성한다. 이 규칙은 도메인에 따라 다르고, 같은 주문번호라도 회사마다 다르다.

흔히 사용하는 규칙은 현재 시간과 다른 값을 함께 조합하는 것이다. 예를들어 주문을 한 시점의 날짜시간정보를 포함하여 주문번호를 정의하는 경우이다. 이런 경우에는 같은 시간에 동시에 식별자를 생성할 때 같은 식별자가 만들어지면 안 된다는 점을 주의해야한다.

UUID(universally unique identifier)를 사용해서 식별자를 생성할 수 있다. 다수의 개발언어가 UUID 생성기를 제공하고 있으므로 마땅한 규칙이 없다면 UUID를 식별자로 사용해도 된다. 자바의 경우 java.util.UUID 클래스를 사용하면 UUID를 생성할 수 있다.

UUID uuid = UUID.randomUUID();

// 615f2abc9-c374-4b50-9420-2154594af151과 같은 형식 문자열 
String srtUuid = uuid.toString(); 

회원의 아이디나 이메일과 같은 식별자는 값을 직접 입력한다. 사용자가 직접 입력하는 값이기 때문에 식별자를 중복해서 입력하지 않도록 사전에 방지하는 것이 중요하다.

식별자로 일련번호를 사용하기도 한다. 일련번호 방식은 주로 데이터베이스가 제공하는 자동 증가 기능을 사용한다. 예를 들어 오라클의 시퀀스, MySQL의 자동 증가 컬럼(auto_increment 컬럼)을 이용해서 일련번호 식별자를 생성한다.

자동 증가 컬럼을 제외한 다른 방식은 다음과 같이 식별자를 먼저 만들고 엔티티 객체를 생성할 때 식별자를 전달할 수 있다.

// 엔티티를 생성하기 전에 식별자 생성 
String orderNumber = orderRepository.generate();

Order order = new Order(orderNumber, ....);
orderRepository.save(order);

자동 증가 칼럼은 DB 테이블에 데이터를 삽입해야 비로소 값을 알 수 있기 때문에 테이블에 데이터를 추가하기 전에는 식별자를 알 수 없다. 이는 엔티티 객체를 생성할 때 식별자를 전달할 수 없음을 뜻한다.

Article article = new Article(author, title, ...);
articleRepository.save(article); // DB에 저장한 뒤 구한 식별자를 엔티티에 반영
Long savedArticleId = article.getId(); // DB에 저장한 후 식별자 참조 가능 

Tip 💡 Repository는 도메인 객체를 데이터베이스에 저장할 때 사용하는 구성요소이다. 자동 증가 칼럼을 사용할 경우 리포지터리라는 DB가 생성한 식별자를 구해서 엔티티 객체에 반영하게 된다.