1.1 도메인(domain)이란?
- 소프트웨어로 해결하고자 하는 문제 영역
- 한 도메인은 다시 하위 도메인으로 나눌 수 있다.
링크오션의 도메인

1.3 도메인 모델을 표현하는 방법
- 객체 모델링
- 상태 다이어그램
- 그외 도메인을 이해하는데 도움이 될 수 있는 어떠한 표현방식
1.4도메인 모델 패턴
- 도메인 모델 (객체)에 비즈니스 로직을 녹이는 방식

일반적인 애플리케이션 아키텍처
영속성 모델을 분리하면서 일반적인 리포지토리의 구현 계층을 아예 인프라 스트럭쳐 취급 해버리는 방식같다. 비슷한 표현방식을 Hexagonal Architecture의 경우 만배클아에서 본적이 있는데 Layered Architecture에서도 이런식으로 표현된 그림을 보니 또 색다르게 느껴진다.
- 도메인 모델 패턴 예시
적용 전
public enum BookmarkStatus { REGISTERED, REMOVED } public void remove() { this.status = BookmarkStatus.REMOVED; this.updatedAt = now(); }
적용 후
@Getter @RequiredArgsConstructor public enum BookmarkStatus { REGISTERED(true), REMOVED(false), private final boolean removable; } public void remove() { checkCondition(status.isRemovable()); this.status = BookmarkStatus.REMOVED; this.updatedAt = now(); } public
BookmarkStatus
에 REGISTERED
상태만이 REMOVED
상태로 변경 될 수 있다는 비즈니스 로직이 담겨있다. 적용 전에는 서비스에서 Bookmark#remove( )
를 호출할때 항상 REGISTERED 상태의 북마크만 전달할것이라는 기대가 깔려있다. 물론 서비스를 구현하는 개발자는 당연히 비즈니스를 이해하고 구현할 것이기 때문에 규칙을 준수하였으며 코드에 문제는 없다. (서비스에서는 영속성 계층에서 항상 REGISTERED
상태의 북마크 만을 조회 할 수 있다.)또한 현재 북마크의 상태는 두가지 밖에 없으며 관련된 비즈니스 로직은 매우 간단하다.
/** * 북마크 상태 * 생성시 `등록` 상태를 가지며 북마크 삭제를 통해 `제거` 상태가 된다. */ public enum BookmarkStatus ...
이러한 주석을 통해서 팀에 새로 합류한 개발자는 쉽게 룰을 이해할 수 있을것이다.
하지만 상태가 많아지고 비즈니스 로직이 복잡해짐에 따라 새로운 개발자가 이런 주석만으로 비즈니스 로직을 완전히 이해하리라 기대할 수 없다. 개발자가 가장 잘 이해 할 수 있는것은 주석 보다 코드이다.
단일 엔티티와 연관된 비즈니스 로직은 최대한 도메인 모델에 녹이기 위해 노력하자.
1.5 도메인 모델 도출
요구사항을 도메인에 녹이는
도메인 모델 도출
작업에 있어 - 가장 중요한 것은 요구사항을 메서드로 표현하는 것이다.
- 두 번째로 중요한 것은 도메인의 상태를 표현하는 것이다.
위의 경우(북마크) 처럼
도메인을 구현하다 보면 특정 조건이나 상태에 따라 제약이나 규칙이 달리 적용되는 경우가 많다. 주문 요구사항에는 다음 내용이 제약과 규칙에 해당된다. - 출고를 하면 배송지 정보를 변경할 수 없다. - 출고 전에 주문을 취소할 수 있다. - 고객이 결제를 완료하기 전에는 상품을 준비하지 않는다. -p.39
나는 코딩을하며 주로
도메인의 상태 표현
을 많이 신경쓰지 못한것 같다. 모 개발자에 따르면 본인은 개발을 할때 일단 주요 엔티티의 경우 EntityStatus
를 하나 만들고 CREATED
상태를 하나 넣고 시작한다고 한다. 좋은 방식은 아니라고 하며 소개하긴 했지만 상태에 대한 정확한 도메인 모델 도출이 되지 않았고 개발일정이 급하다면 나쁘지 않은 방식같다.1.6 엔티티와 밸류
도출한 모델은 크게 엔티티(Entity)와 밸류(Value)로 나눌 수 있다.
엔티티와 밸류를 제대로 구분해야 도메인을 올바르게 설계하고 구현할 수 있기 때문에 이 둘의 차이를 명학하게 이해하는 것은 도메인을 구현하는 데 있어 중요하다. -p.42
1.6.1 엔티티
- 식별자를 가진다.
- 식별자는 바뀌지 않고 고유하다.
- 따라서 식별자를 통해 두 엔티티의 동등성을 판별할 수 있다.

EqualsAndHashCode
를 통해 이를 상속한 모든 엔티티는 기본적으로 id 값을 통해 동등성을 판별할 수 있다. 이를 도입해서 엔티티의 특징을 표현하면서도 테스트의 용이성이 상당히 올라가서 프로젝트의 코드 중 상당히 마음에 들었던 부분이다.1.6.2 엔티티의 식별자 생성
- 특정 규칙 (e.g. timestamp + 다른 값)
- UUID/nano ID
- 값을 직접 입력
- 일련 번호 사용 (Sequnce(oracle)/ auto increment(mysql))
- 링크 오션에서 채택한 방식 (~ @GeneratedValue)
1.6.3 밸류 타입 (VO)
- 개념적으로 완전한 하나를 표현할 때 사용
- vo 에는 기능 (로직)이 추가 될 수 있다.
- vo 는 불변(immutable)으로 구현해야 한다.
- 이를 통해 안전한 코드를 작성할 수 있다.
- Java에서 String, WrapperType을 불변으로 구현한 이유와 비슷한 이유
- 개인적인 선호)
- vo의 필드가 하나인 경우 필드명을
value
로 잡자
1.6.4 엔티티의 식별자와 밸류 타입
- 식별자를 위한 밸류 타입을 사용해서 의미가 잘 드러나도록 할 수 있다.
- 구현상 한계) Jpa의 경우 id를 vo로 빼고 싶다면
@IdClass
혹은@EmbeddedId
를 사용해야 하는데 두 경우 모두@GeneratedValue
를 사용할 수 없다.
Use of theGeneratedValue
annotation is not supported for derived primary keys. -@GeneratedValue
javadoc 일부
1.7 도메인 용어와 유비쿼터스 언어
- 코드를 작성할 때 도메인에서 사용하는 용어는 매우 중요하다.
- 정리된 용어를 문서화하고 도메인 모델의 주석으로 남기는 것은 좋은 습관
Status
orState
?Type
orKind
? 심지어 발음 나는 대로Gubun
도 가능
- 개인적으로 아주 좋아하는 가치이다.
알맞은 영단어를 찾는 것은 쉽지 않은 일이지만 시간을 들여 찾는 노력을 해야한다. 그렇지 않으면 코드는 도메인과 점점 멀어진다. -p.59