도메인 영역의 주요 구성요소로는 1장의 엔티티, 밸류 외에 애그리거트Aggregate, 리포지터리Reposisotry, 도메인서비스 가 있다.
1. 아키텍처 설계의 4개 영역
(2.1, 2.2장)
표현, 응용, 도메인, 인프라스트럭처의 4개의 영역.
표현
UI영역, 웹 브라우저, api client 등.
사용자의 요청을 해석해서 응용서비스에 전달하고, 응용의 결과를 사용자가 이해할 수 있는 형식으로 변환하여 응답한다.
응용
서비스 영역.
도메인 모델을 이용해서 사용자에게 제공할 기능을 구현하고, 실제 도메인 로직 구현은 도메인 모델에 위임한다.
도메인
도메인의 핵심 로직을 구현한다.
인프라스트럭처
구현 기술을 다룬다. ex. RDB, Redis, SMTP 등
논리적인 개념을 표현하기 보다는 실제 구현을 의미한다.
계층 구조 아키텍처
계층 구조에서 상위 계층에서 하위 계층으로의 의존만 존재한다.
ex. 표현 계층은 응용 계층에 의존한다. 인프라스트럭처 계층은 도메인에 의존하지 않는다.
구현의 편리함을 위해 계층 구조를 유연하게 적용할 수도 있다.
이런 의존성으로 인해 ‘테스트의 어려움’, ‘기능확장의 어려움’ 이 발생할 수 있다.
이를 위해 DIP가 있다.
2. DIP
(2.3장)
고수준, 저수준 구분.
의존 역전 원칙. Dependency Inversion Principle
저수준 모듈이 고수준 모듈에 의존하게 됨.
고수준 모듈은 더이상 저수준 모듈에 의존하지 않고, 구현을 추상화한 인터페이스에 의존한다.
//사용할 저수준 객체 생성 후
RuleDiscounter ruleDiscounter = new DroolsRuleDiscounter(); // <= 저수준 구현을 바꿀 시에는 이곳만 수정
// 고수준 모델에서 생성자 방식으로 주입
CalculateDiscountService disService = new CalculateDiscountService(ruleDiscounter);
이를 통해 인터페이스를 활용한 대역 객체를 사용해서 테스트를 손쉽게.
고수준 모듈인 서비스에서 저수준 모듈에 직접 의존하지 않으므로
RDB를 이용한 Respotiory 와 Drools를 이용한 Discounter 구현 클래스가 없어도 목을 이용해 테스트가 가능.
단순히 인터페이스와 구현 클래스를 분리하는 정도로만 받아들이면 안된다.
핵심은 고수준 모델이 저수준 모듈에 의존하지 않도록 하기 위함.
잘못된 예
잘된 예
dip와 아키텍처
아키텍처에 dip를 적용하게 되면 인프라 스트럭처 영역이 응용과 도메인 영역에 의존하는 구조가 된다.
도메인과 응용영역에 대한 영향 없이 구현 기술을 변경할 수 있다.
Notifier을 바라보고 있기 때문에, Email에서 SMS 로 손쉽게 변경 가능
orderRepository를 바라보고 있기 때문에, mybatis에서 jpa로 변경 가능.
DIP를 항상 적용할 필요는 없고, 추상화 대상이 어려운 경우도 있으니 무조건 DIP를 적용하기 보단 이점을 얻는 수준에서 적용 범위를 검토해보자.
3. 도메인 영역의 주요 구성요소
(2.4장)
(1장에서 살펴본) 엔티티와 밸류타입 복습
엔티티 : 각 엔티티 객체마다 고유한 식별자를 가진다. 주문, 상품과 같이 도메인의 고유한 개념을 표현.
밸류 : 식별자 없이 개념적으로 하나의 값을 표현할 떄 사용. ex. 주소정보
여기서 추가로 3가지 요소를 이야기해보자.
애그리거트 Aggregate
연관된 엔티티와 밸류 객체를 개념적으로 묶은 것. ex. Order 엔티티, Orderder밸류 객체를 ‘주문’ 애그리거트로 묶을 수 있다. -> 3장
리포지터리 Repository
도메인 모델의 영속성을 제공 -> 4장, 5장
도메인 서비스
특정 엔티티에 속하지 않은 도메인 로직을 제공하는 서비스. -> 7장
엔티티와 밸류
(다음 장들을 위한 용어 정리!)
db 테이블의 엔티티와 도메인 모델의 엔티티는 어떻게 구분 되는가?
1.도메인 모델의 엔티티는 데이터와 함께 기능을 제공한다는 점.
도메인 관점에서 기능을 구현하고 캡슐화 해서 데이터가 임의로 변경되는 것을 막음.
도메인 모델의 엔티티는 두개 이상의 데이터가 개념적으로 하나인 경우 밸류 타입을 이용해서 표한할 수 있다는 것.
ERD만 봐서는 밸류 타입을 제대로 표한하기가 힘들다.
1장에서 설명했듯이 밸류는 불변으로 구현할 것을 권장. setter를 통해 데이터가 변경된다는 것은 객체 자체가 완전히 교체 된다는 것.
애그리거트 Aggregate
도메인이 커질 수록 많은 엔티티와 밸류가 출현하고 복잡성이 높아짐.
따라서 관련된 객체를 애그리거트로 묶어서 복잡한 도메인 모델을 관리하자.
애그리거트는 군집에 속한 객체를 관리하는 루트 엔티티를 가짐.
외부에서는 애그리거트 루트로만 접근할 수 있도록 캡슐화
루트에서 간접적으로 다른 엔티티나 밸류 객체에 접근 하도록 하자.
상품 외부에서는 상품객체만 볼 수 있도록.(3장에 자세히)
리포지터리 Repository
리퐅지터리는 애그리거트 단위로 도메인 객체를 저장하고 조회하는 기능을 정의.
엔티티/밸류가 요구사항에서 도출되는 도메인모델인 반면, 리포지터리는 구현을 위한 도메인 모델
리포지터리 인터페이스는 도메인 모델 영역에 속하며, 실제 구현 클래스는 인프라스트럭처 영역에 속한다.
응용 서비스와 리포지터리는 밀접한 연관이 있다.
응용 서비스는 필요한 도메인 객체를 구하거나 저장할 때 리포지터리를 사용한다.
응용 서비스는 트랜잭션을 관리하는데, 이 처리는 리포지터리 구현 기술의 영향을 받는다
기타
2.5 요청 처리 흐름
2.6 인프라스트럭처 개요
@transactional, @entity, @table등의 스프링이나 jpa에서 제공하는 기능을 직접적으로 사용하는 것은 DIP가 아니다.
인프라스트럭처의 기능을 직접 사용하는 것
but, 구현이 주는 편리함이 dip의 장점보다 (변경 유연성, 테스트) 크고 사용하기에 편리하다.
만약 의존을 없애려면, 자칫 구현을 더 복잡하고 어렵게 만들 수 있다. (그니까 써도 된다)
요약
표현
,응용
,도메인
,인프라스트럭처
4개의 영역으로 구분한다.DIP
를 이용하여, 테스트와 기능 확장을 손쉽게 할 수 있다.도메인
영역의 주요 구성요소로는 1장의엔티티
,밸류
외에애그리거트Aggregate
,리포지터리Reposisotry
,도메인서비스
가 있다.1. 아키텍처 설계의 4개 영역
(2.1, 2.2장)
표현
응용
도메인
인프라스트럭처
계층 구조 아키텍처
계층 구조에서 상위 계층에서 하위 계층으로의 의존만 존재한다.
구현의 편리함을 위해 계층 구조를 유연하게 적용할 수도 있다.
이런 의존성으로 인해 ‘테스트의 어려움’, ‘기능확장의 어려움’ 이 발생할 수 있다.
2. DIP
(2.3장)
의존 역전 원칙. Dependency Inversion Principle
저수준 모듈이 고수준 모듈에 의존하게 됨.
고수준 모듈은 더이상 저수준 모듈에 의존하지 않고, 구현을 추상화한 인터페이스에 의존한다.
이를 통해 인터페이스를 활용한 대역 객체를 사용해서 테스트를 손쉽게.
고수준 모듈인 서비스에서 저수준 모듈에 직접 의존하지 않으므로
단순히 인터페이스와 구현 클래스를 분리하는 정도로만 받아들이면 안된다.
잘못된 예
잘된 예
dip와 아키텍처
아키텍처에 dip를 적용하게 되면 인프라 스트럭처 영역이 응용과 도메인 영역에 의존하는 구조가 된다. 도메인과 응용영역에 대한 영향 없이 구현 기술을 변경할 수 있다.
3. 도메인 영역의 주요 구성요소
(2.4장)
(1장에서 살펴본) 엔티티와 밸류타입 복습
여기서 추가로 3가지 요소를 이야기해보자.
애그리거트 Aggregate
리포지터리 Repository
도메인 서비스
엔티티와 밸류
(다음 장들을 위한 용어 정리!)
1장에서 설명했듯이 밸류는 불변으로 구현할 것을 권장. setter를 통해 데이터가 변경된다는 것은 객체 자체가 완전히 교체 된다는 것.
애그리거트 Aggregate
도메인이 커질 수록 많은 엔티티와 밸류가 출현하고 복잡성이 높아짐.
따라서 관련된 객체를 애그리거트로 묶어서 복잡한 도메인 모델을 관리하자.
애그리거트는 군집에 속한 객체를 관리하는 루트 엔티티를 가짐.
리포지터리 Repository
리퐅지터리는 애그리거트 단위로 도메인 객체를 저장하고 조회하는 기능을 정의. 엔티티/밸류가 요구사항에서 도출되는 도메인모델인 반면, 리포지터리는 구현을 위한 도메인 모델
리포지터리 인터페이스는 도메인 모델 영역에 속하며, 실제 구현 클래스는 인프라스트럭처 영역에 속한다. 응용 서비스와 리포지터리는 밀접한 연관이 있다.
기타
2.5 요청 처리 흐름
2.6 인프라스트럭처 개요
@transactional
,@entity
,@table
등의 스프링이나 jpa에서 제공하는 기능을 직접적으로 사용하는 것은 DIP가 아니다.2.7 모듈 구성
이미지 참조