도메인 주도 설계 및 구현 (3)
값 객체 (Value Object)
-> 값 객체는 DDD의 필수적인 구성 요소 이다.
*값 이점에 대해 알라
측정하고 수량화하거나 설명해주는 값 타입은 생성, 테스트, 사용, 최적화, 유지관리가 더 쉽다.
모델 요소의 특성에만 신경을 쓰고 있다면, 이를 값 객체로 분리하라.
값 객체가 담을 특성의 의미를 표현하고, 그에 관한 기능도 부여하자.
값 객체를 변경이 불가능한 것으로 취급하자.
식별자는 부여하지 말고, 엔티티를 유지할 때 필요한 설계 복잡성을 피하도록 하자.
값의 특징
-
도메인 내의 어떤 대상을 측정하고, 수량화하고, 설명한다.
-
불변성이 유지될 수 있다.
-
관련 특성을 모은 필수 단위로 개념적 전체를 모델링한다.
-
측정이나 설명이 변경 될 땐 완벽히 대체 가능하다.
-
다른 값과 등가성(value equlity)을 사용해 비교할 수 있다.
-
협력자(collaborator)에게 부작용이 없는 행동 (side effect free behavior)을 제공한다.
(와트 커닝 햄 전체 값(whole value) 패턴)
– 사설 –
-
요즘은 DDD 관련해서 잘 정리되지 않은 체 상상한 대로 하다보니 조금 패키지 나누는 것 부터 문제가 발생되곤 한다.
-
값 객체인 경우 예로는 상품 정보중 가격 정보에 해당되는 것을 값 객체로 빼고, 내부적으로 들어오는 값에 대해 처리하는 로직으로 작성했었다. 불변형 객체를 맞춰서 작성하였다.
-
그 밖의 각 계층별 나누는 것은 아직 익숙하지 않은데, 어디 참고할 만한 코드를 봤으면 좋겠다.
함수형의 길
함수형 프로그래밍 언어는 일반적으로 이런 특성을 강화 시킨다.
사실 순수한 함수형 언어는 오직 부작용 없는 행동만 하며, 모든 클로저는 오직 불변성 값 객체만 받아들이거나 들어내도록 요구한다.
일관된 바운디드 컨텍스트 내에 유비쿼터스 언어를 모델링 하는 문제이다.
서비스
도메인 고유의 바운디드 컨텍스트 내에 유비쿼터스 언어를 모델링 하는 문제이다.
도메인 모델은 일반적으로 비즈니스의 특징 측면에 집중된 소단위 행동을 처리 하기 때문에,
도메인 서비스는 도메인 모델과 비슷한 원칙을 고수하는 경향이 있다.
도메인 서비스는 다음과 같은 경우에 사용할 수 있다.
-
중요한 비즈니스 프로세스를 수행할 때
-
어떤 컴포지션에서 다른 컴포지션으로 도메인 객체를 변형 할 때
-
하나 이상의 도메인 객체에서 필요한 입력값을 계산 할 때
특정 범주 안에 들어가는 것을 바운디드 컨텍스트로 분리하고, 정적 메서드 형태로 불러와서 사용할 수 있도록 한다. 이때 서비스는 무상태이다.
책에선 예제에 레지스트리 객체가 있었는데, 도메인과 구현 세부사항 사이의 결합을 분리해준다. 하지만 선호하는 방식은 아니라고 한다.
-
도메인 서비스를 과용하면 안티 패턴인 애너믹 모델로 이어질 수 있다.
-
서비스를 구현하는 구체적인 실행 단계
-
분리된 인터페이스를 사용하는 장, 단점
도메인 이벤트
도메인에서 발생한 사건을 포착하기 위해 도메인 이벤트를 사용하자.
도메인 이벤트를 나타낼 수 있는 경우는 아래와 같다.
-
~할 때
-
그런일이 일어나면
-
~하면 저에게 알려주세요. ~와 하면 저에게 통보해주세요.
-
~한 일의 발생
애그리게잇으로 이벤트를 발행할 땐 이벤트의 이름에 과거 시점을 반영하는 것이 좋다.
- 이벤트가 언제 일어 났는지 나타내는 timestamp가 필요하다.
(현재 나는 위 사항을 중요하게 처리하지 않고 있었다.)
Event에 해당되는 모델에 위의 timestamp를 설정할 수 있는 인터페이스를 만들자.
이벤트 저장소 내용은 있었지만 간략했다.
멱등한 오퍼레이션
멱등한 오퍼레이션 (Idempotent operation)은 같은 오퍼레이션이 두 번 이상 수행되어도, 한번만 수행 했을 때와 같은 결과에 이르는 동작을 한다.
모듈
시스템에 관한 이야기를 알려주고 응집력 있는 개념의 집합을 담을 수 있도록 모듈을 선택하자.
이는 보통 모듈 사이에 낮은 결합도를 유지하게 해주지만, 만약 그렇지 않다면 모델을 변경해서 개념을 서로 분리하는 방법을 찾도록 하자. 모듈에는 유비쿼터스 언어의 한 부분을 이루는 이름을 부여하자.
모듈과 이름은 반드시 도메인에 관한 통찰을 반영해야 한다.
모듈 설계 예제
ex)
com.myservice.identityaccess.domain
com.myservice.identityaccess.domain.model
com.myservice.identityaccess.domain.service
애그리게이트(aggregate)
-> 스크럼 모델링의 핵심이 살아 있는 곳.
각 모델들은 별도의 패키지로 분리하여 관리한다.
일관성의 경계 (consistency boundary)
애그리게잇에서 영속성에 따라 가져오는 데이터량이 많다면 메모리 사용량도 고려해야한다.
하나의 트랜젝션 -> 일관성 경계
경계의 밖에선 결과적 일관성을 사용하라.
-> transaction 범위를 벗어난 부분에서는 결과로 리턴된 객체를 이용하여 사용하라는 것 같음
애그리게잇에게 의존성 주입은 피하라.
데메테르의 법칙
그 자신, 자신에게 전달된 매개변수, 자신의 인스턴스화 하는 객체 자신이 직접 엑세스 할 수 있는 스스로가 포함된 파트 객체
매개변수로 전달된 객체의 내부 변수들를 바로 접근 할 수 있도록 하는 것을 제한 하고, 전달 받은 객체의 메소드를 이용하여 사용하는 것.