Domain driven design
DDD Start #1 도메인 모델 시작 키워드 요약
HaningYa
2021. 10. 10. 00:51
728x90
- 도메인: 소프트웨어로 해결하고자 하는 문제 영역
- 상위 도메인: 온라인 서점
- 하위 도메인: 회원, 주문, 혜택, 결제, 리뷰, 정산 ..etc
- 하위 도메인 중 일부는 외부 시스템을 이용할 수 있다.
- 도메인 모델: 특정 도메인을 개념적으로 표현한것
- 객체 기반 주문 도메인 모델: 기능과 주요 데이터 구성을 파악하는데 적합함
- 상태 다이어그램을 이용한 주문 상태 모델링, 그래프, 수학공식 등으로 표현할 수 있음
- 도메인 모델은 도메인 자체를 이해하기 위한 개념 모델
- 개념 모델과 구현모델은 다르지만 구현모델이 개념모델을 따라가도록 구현가능
ex) 객체 기반 개념 모델 -> 객체 지향 언어 사용, 수학적 모델 -> 함수형 언어 사용 - 하위 도메인을 하나의 다이어그램에 모델링 하면 안됨 -> 하위 도메인에 따라 용어의 의미가 달라지기 때문!
- 도메인 모델 패턴
- 일반적인 아키텍쳐 구성
- UI 또는 Presentation 계층: 사용자의 요청을 처리하고 사용자에게 정보를 보여줌
- Application 계층: 사용자가 요청한 기능 수행, 업무 로직을 직접 구현하지 않고, 도메인 계층을 조합해서 기능을 실행
- Domain 계층: 시스템이 제공할 도메인의 규칙을 구현
- Infrastructure 계층: 디비나 메세징 시스템과 같은 외부 시스템과의 연동 처리
- 위 레이어에서 도메인 계층은 도메인의 핵심 규칙을 구현
ex) 출고전 배송지를 변경할 수 있다. 주문 취소는 배송 전에만 할 수 있다. - 이런 도메인 핵심 규칙을 "객체 지향 기법"으로 구현하는 패턴이 도메인 모델 패턴
- 왜 중요? -> 핵심 규칙을 구현한 코드는 도메인 모델에만 위치하기 때문에 규칙이 바뀌거나 확장될 때 다른 코드에 영향을 덜 주고 변경 내역을 모델에 반영할 수 있음
- 일반적인 아키텍쳐 구성
- 도메인 모델 도출과정 생략
- 엔티티
- 엔티티 객체마다 고유한 식별자(Idenfitier) 를 가짐 (주문 번호)
- 엔티티의 식별자는 바뀌지 않음 (주문에서 배송지 주소나 배송상태가 바뀌어도 주문번호는 바뀌지 않음)
- 두 엔티티 객체의 식별자가 같으면 두 엔티티는 같다고 판단
- 식별자 생성방법
- 특정 규칙에 따라 생성 (현재시간 + 다른값)
- UUID 사용
- 값을 직접 입력
- 일련번호 사용(시퀸스나 DB auto increment)
- 레포지토리: 도메인 객체를 디비에 저장할 때 사용하는 구성요소 (4장에서 나옴)
- 밸류타입: 개념적으로 완전한 하나를 표현할 때 사용
public class ShippingInfo {
// 아래 두 변수는 "받는 사람" 의 개념으로써 동일하다. (하나의 개념을 포함한다.)
private String receiverName;
private String receiverPhoneNumber;
// 아래 두 변수는 "주소" 라는 개념으로써 동일하다. (하나의 개념을 포함한다.)
private String shippingAddress1;
private String shippingAddress2;
private String shippingZipcode;
}
위 예제에서 개념적으로 완전한 하나를 표현하기 위해 Receiver 밸류 타입을 만들 수 있다.
public class Receiver {
private String name;
private String phoneNumber;
public Receiver(String name, String phoneNumber) {
this.name = name;
this.phoneNumber = phoneNumber;
}
public String getName() {
return name;
}
public String getPhoneNuber() {
return phoneNumber;
}
}
밸류 타입을 사용함으로써 개념적으로 완전한 하나를 표현할 수 있다.
- 밸류타입이 꼭 두개 이상의 데이터를 가질 필요는 없다.
예를들어 private int price가 돈이라는 의미를 명확하게 하기 위해
Money타입을 만들어 private Money price라고 표현할 수 있다.
또한 Money 타입에 돈계산을 위한 기능도 추가할 수 있다. - 불변타입: 값을 변경할 수 있는 기능을 제공하지 않는 타입
- 밸류는 불변타입으로 구현한다.
- 안전한 코드 작성 가능-> 참조 투명성, 스레드에 안전함 - 엔티티 비교는 identifier로 했지만 밸류 비교는 모든 속성이 같은지 비교
- 식별자를 위한 밸류 타입을 사용가능
예시) 기존 주문번호를 private int id; 로 선언했다면 OrderNo 밸류타입을 추가하여 private OrderNo id; 로 선언함으로서 해당 필드가 주문번호라는걸 알 수 있음 - 도메인 모델에 set 메서드 넣지 마라
-> set 은 도메인의 핵심 개념이나 의도를 코드에서 사라지게함
예시) changeShippingInfo() -> setShippingInfo() 애써 이해한 도메인 지식이 코드에서 사라지게됨
-> 도메인 객체를 생성할 때 완전한 상태가 아닐 수 있음
예시) init에서 값을 전달하는게 아닌 set으로 객체 값을 전달하면 값이 누락될 수 있음 -> 생성자에서 필요한 데이터 다 받도록 수정
* private set 함수는 외부에서 데이터를 변경할 목적으로 사용X하기 때문에 써도됨 - 불변 밸류 타입을 사용하려면 자연스럽게 set 메서드는 구현하지 않음
- DTO: Data Transfer Object -> Presentation layer과 domain layer 사이 데이터 주고받을 때 사용
- 도메인 용어
public OrderState1 {
STEP1, STEP2, STEP3, STEP4 ...
}
public OrderState2 {
PAYMENT_WAITING, PREPARING, SHIPPED, DELIVERING ...
}
OrderState1은 결제 대기중, 상품 준비중, 출고 완료됨 등등의 도메인 용어가 코드에 반영되있지 않음
OrderState2 처럼 코드에서 중요 규칙이 드러나야함
엔티티
- 고유의 식별자를 갖는 객체
- 자신의 라이프사이클을 가짐
- 주문, 회원, 상품과 같이 도메인의 고유한 개념을 표현
- 도메인 모델의 데이터를 포함하며 해당 데이터와 관련된 기능을 함께 제공
밸류
- 고유의 식별자를 갖지 않는 객체
- 주로 개념으로 하나인 도메인 객체의 속성을 표현할 때 사용
- 배송지 주소를 표현하기 위한 주소(Address), 구매 금액을 위한 금액(Money)와 같은 타입
- 엔티티의 속성으로 사용될 뿐만 아니라 다른 밸류 타입의 속성으로도 사용될 수 있음
에그리거트
- 관련된 엔티티와 벨류 객체를 개념적으로 하나로 묶은것
- 주문과 관련된 Order 엔티티, OrderLine 밸류, Orderer밸류 객체를 '주문' 에그리거트로 묶을 수 있음
리포지토리
- 도메인 모델의 영속성 처리
- DBMS 테이블에서 엔티티 객체를 로딩하거나 저장하는 기능을 제공
도메인 서비스
- 특정 엔티티에 속하지 않은 도메인 로직을 제공
- '할인 금액 계산'은 상품, 쿠폰, 회원등급, 구매금액 등 다양한 조건을 이용하는데
이렇게 여러개의 엔티티와 밸류를 필요로 할 경우 도메인 서비스에서 로직을 구현
생각
- 밸류 타입의 목적이 가독성을 위해 "변수 네이밍" + "변수 타입" 둘다 활용하는 느낌인데 맞는건가
- 엔티티와 밸류를 단순히 class와 내부 프로퍼티로 구분할 수 없는것 같은데 class도 엔티티 또는 밸류가 될수 있고 프로퍼티는 엔티티가 될 수 없고 프로퍼티는 밸류가 될 수 있는건가..?
- 예시) 기존 주문번호를 private int id; 로 선언했다면 OrderNo 밸류타입을 추가하여 private OrderNo id; 로 선언함으로서 해당 필드가 주문번호라는걸 알 수 있음 -> 그냥 변수명을 orderNo로 하면 안되나? 굳이 타입관련한 함수가 없다면?
- 도메인이 소프트웨어로 해결하고자 하는 문제영역이면 도메인 지식은 소프트웨어 요구사항, 도메인 핵심 규칙은 소프트웨어 비즈니스 로직이라고 볼 수 있는건가
- 그럼 결국 도메인 주도 개발이라는게 요구사항에 따라 개발을 진행하는 방법론인건가? 근데 원래 개발할때 요구사항에 따라서 하는거 아닌가 이미 모두가 DDD를 하고 있는건가 뭐지
- 아님 TDD처럼 테스트를 먼저 작성하고 개발하는 뜻과 같이 DDD도 도메인 개념 모델을 먼저 작성하고 개발을 해서 DDD인건가?
728x90