#01장 도메인 모델의 시작
최범균 저「DDD START!, 2016」를 읽고 정리하였습니다.
다룰 내용
도메인 모델
앤티티와 밸류
도메인 용어
도메인
책 구매
목차와 평가 보기, 장바구니담기, 쿠폰찾기, 카드결제/가상계좌입금, 배송추적
이러한 기능을 가진 온라인서점은 소프트웨어로 해결하고자 하는 도메인 영역이 된다.
도메인은 다시 하위도메인으로
주문
결제, 배송, 혜택, etc
(경우에 따라) 외부 시스템 이용
결제 - 외부 PG
배송 - 외부 물류
즉, 도메인 밑에 서브도메인이 필요에 따라 변경이 될 수도
도메인 모델
특정 도메인을 개념적으로 표현한 것.
UML이든 객체 관계도로 표현하든 개념적으로만 표현하면 된다. (아래 그림)
사례: 주문 과정
주문수량 설정 -> 배송지 입력 -> 결제수단 선택 후 계산 -> 주문 완료 -> 출발안했음, 배송지 변경 가능

객체 뿐만 아니라 도메인을 나타낼 수 있다면, 이해와 지식 공유 도움되면 다른 대체제도 모두 가능하다.
e.g. 상태 다이어그램 (아래 확인)
결제 여부에 따라 상품 준비
출고가 완료되면 취소 불가

도메인 모델 패턴
가장 흔한 Application 아키텍처
4 계층: 표현 - 응용 - 도메인 - 인프라(DB) (Layer Architecture 링크)
표현 - UI. 사용자/외부시스템 요청 처리하고 보여준다.
응용 - 사용자 요청 기능 실행. 업무 로직 X. 도메인 계층 조합해서 기능 실행.
도메인 - 도메인 규칙 구현.
인프라 - DB나 메시징 외부 시스템 연동하여 처리
예측: 주문- 주문, 계산, 배송
어떤 코드가 도메인 계층에?
사례: 주문 도메인 규칙
규칙1: 출고 전에 배송지 변경 가능
규칙2: 주문 취소는 배송전에만 가능
아래는 반영 코드
포인트: 주문과 관련된 중요한 업무 규칙을 주문 도메인 모델인 아래 2개의 객체에서 하고 있다는것.
리팩토링: OrderState는 Order에 속한 데이터이다. 즉, 배송지 변경 가능 여부 판단 코드는 Order로 이동 가능.
개념모델 vs 구현모델
문제를 분석하고 개념 모델로 결과물을 뽑아낸 뒤, 구현 모델로 전환한다.
도메인 모델 도출
모델 도출하기 위해선, 기획서, USE CASE, 사용자 스토리로 초안 만들기.
모델링 기본 작업들
핵심 구성 요소
규칙
기능
주문 관련 요구사항
최소 한 종류 이상의 상품을 주문해야 한다 .
한 상품을 한개 이상 주문할 수 있다.
총 주문 금액은 각 상품의 구매 가격합을 모두 더한 금액 이다 .
각 상품의 구매 가격 합은 상품 가격에 구매 개수를 곱한 값 이다 .
주문할 때 배송지 정보를 반드시 지정해야 한 다 .
배송지 정보는 받는 사람 이름, 전화번호, 주소로 구성 된다 .
출고를 하면 배송지 정보를 변경 할 수 없다 .
출고 전에 주문을 취소할 수 있다 .
고객이 결제를 완료 하기 전에는 상품을 준비 하지 않는다 .
이로 알 수 있는 4가지 기능
이 기능들을 메소드로 추가할 경우
2, 4 요구사항에 의해 주문 항목이 어떤 데이터로 구성될 지 알 수 있다.
OrderLine 객체 참고
요구사항 1과 3은 Order와 OrderLine의 관계를 보여준다. 따라서 Order를 다음과 같이 변경.
ShippingInfo
요구사항 5에 따라, Order를 생성 할때 OrderLine 뿐만 아니라 ShippingInfo도 함께 전달해야 한다.
생성자에 반영
요구사항 7, 8 (9번도 관련)
Enum 이용하여 상태로 표현하기
Order에 해당 요구사항을 적용하면,
주목: isShippingChangeable -> verifyNotYetShipped
시간이 흐르며 도메인을 더 잘 알았기에, 리팩토링
배송지 정보 변경와 주문취소가 "출고전에 가능" 이라는 제약조건을 찾게되었기에~
Entity와 Value
도출한 모델은 엔티티와 밸류로 구분 가능
도메인 구현을 위해, 둘의 차이를 명확하게 이해해야 한다.
여기선 Value를 '값'으로 사용하지 않을것.

엔티티
식별자를 갖는다.
e.g. 주문번호 (orderNumber)
배송지가 바껴도 주문번호가 바뀌지 않으므로, 식별자는 변경 x. 즉, 삭제될때 까지 유지.
equals와 hashCode를 구현하면 다음과 같다
엔티티의 식별자 생성
특정 규칙에 따라 생성
UUID
값 직접 입력
일련번호 사용
특정 규칙에 따라 생성
사례: 아마존/알라딘 온라인서점
주문번호, 운송장번호, 카드번호는 특정 규칙에 따라 생성
흔히 사용 방법
시간과 다른 값을 함께 조합
2015년 05월 29일 09시 46분 44초
20150529094644
같은 시간에 생성시, 같은 식별자 만들어질 수 있으므로, 주의해야 한다.
UUID
e.g. java.util.UUID
값 직접 입력
e.g. 사용자 아이디나 이메일
일련번호
e.g. 시퀀스나 DB의 자동 증가 컬럼
자동 증가 컬럼의 경우, 데이터를 삽입해야 값을 알수 있기에, 객체 생성시 식별자를 전달할 수 없다.
4장에서 자세히
밸류 타입
밸류 타입 = 개념적으로 완전한 하나를 표현
사람과 주소에 대한 데이터
밸류 타입에 따라, 쪼갤 경우
결과적으로 ShippingInfo는 이렇게 바뀐다.
또 다른 사례로 OrderLine에 밸류타입을 활용 해보자.
Money타입을 사용했기에 price나 amount가 금액을 의미함을 명확히 알 수 있다.
밸류 타입의 추가적 장점 - 밸류 타입을 위한 기능 추가 가능.
요약, 밸류 타입 = 코드의 의미 명확화 특징 - 기존 데이터를 변경하긴 보단, 새로운 객체 생성 선호하는 편임 불변 = 안전한 코드 작성 가능
line과 price의 값이 다르다.

발생 방지를 위한 추가 조치로
다만, Money가 불변이었다면, 이런 코드를 작성할 필요가 없었다.
엔티티타입 객체 비교는 식별자를 사용했다면, 두 밸류 객체는 모든 속성값들을 비교한다.
엔티티 식별자와 밸류 타입
식별자는 단순한 문자열이 아니라 도메인에서 특별한 의미를 가지는 경우가 많다. (e.g. 주문 객체의 주문번호)
도메인 모델에 setter 메서드 넣지 않기
고쳐야할것: 습관적 추가 = set 메서드
의미적 차이
changeShippingInfo(ShippingInfo newShippingInfo): 배송지 정보 새로 변경
setShippingInfo(ShippingInfo shippingInfo): 배송지 값을 설정
의미적으로 올바른 메서드명으로 써야한다.
set 사용시 문제코드
더 나은 코드
생성자 호출 시점 데이터 유효 검사 가능
완성 코드
여기서도 set 사용하잖아요!?
접근 범위를 보자: private = 불변 밸류 타입
도메인 용어
도메인 용어는 중요하기에 코드를 작성하는데 이를 이용해야 한다.
결제대기중, 상품준비중, 출고완료, 배송중, 배송완료, 주문취소
를 아래와 같이 표현하면?
도미노 처럼
다른 코드도 이상해 진다
올바른 단어 선택: state vs status, kind vs type
어렵지만, 시간 들여 찾아 적절한 단어를 고르자.
Last updated