[DDDStart] 2장. 아키텍처 개요

2장. 아키텍처 개요

상위 수준에서 아키텍처의 네 영역과 DIP 패턴을 설명하고, 도메인 영역의 구성요소에 대해 살펴본다

 

@Service
public class CancelOrderService {

    @Transactional
    public void cancelOrder(String orderId) {
        Order order = findOrderById(orderId)
                        .orElseThrow(OrderNotFoundException::new);
        order.cancel();
    }
}

난 order.cancel() 로직을 @Service 에다가 구현했하고, @Entity 에는 getter/setter 만으로 도배했었는데..

@Service 니까 비즈니스 로직 넣으면 되겠지?! 라고 생각했었음. 아 근데 도메인 레이어로 로직을 넣어서 DDD인가?

(@Service 어노테이션 안에 @Transactional 있는 줄 알고 있었는데, 없더라)

 

DIP

전통적인 소프트웨어 개발 방법에서는 상위 모듈이 하위모듈에 의존함. 즉, 구체적인 모듈에 의존하는 경향이 있었음. DIP는 전통적인 의존성 구조에 대해 ‘역전’된 것임 - 오브젝트 p302

하위모듈이 상위모듈에 의존하는 경우가 언제일까?
=> 추상화

 

image

(What is the dependency inversion principle and why is it important? )

 

ServiceMySQLRepository 의존하는 것이 당연한 것 같지만,

위와 같이 추상화를 통해서 의존성 역전이 가능하다

Service는 동일한 계층의 Repository에 의존하고,

하위 계층인 MySQLRepository는 상위계층의 Repository에 의존한다

 

테스트 하기 쉬워진다

Service는 MySQLRepository에 의존하지 않기 때문에 Repository를 목으로 대체해서 테스트할 수 있다

 

결합도가 낮아진다

구현체에 직접 의존하지 않고, 인터페이스에 의존하기 때문에 다른 Repository로 바꿔끼우기 용이해진다

   

도메인 영역 구성요소

 

요소 설명
엔터티 도메인의 고유한 개념 표현. 데이터와 기능을 함께 제공. 고유 식별자를 갖음
밸류 한 도메인 객체의 속성을 표현할 때 사용. 고유 식별자를 갖지 않음
애그리거트 관련된 엔티티와 밸류 객체를 개념적으로 하나로 묶은 것
리포지터리 도메인 모델의 영속성을 처리 (인터페이스 / 추상클래스)
도메인 서비스 특정 엔티티에 속하지 않은 도메인 로직을 제공. 여러 엔티티와 밸류를 필요로 할 경우에 사용함

 

엔터티

1장에서 다룸

밸류

1장에서 다룸

애그리거트

관련 객체를 하나로 묶은 군집

애그리거트 하위 도메인
주문 주문(root), 배송지 정보, 주문자, 주문 목록, 총 결제 금액

개별 객체가 아닌 관련 객체를 묶음. 애그리거트 간의 관계로 도메인 모델을 이해할 수 있게 됨. 도메인을 이해하기가 쉬워짐

외부에서 root가 아닌 도메인(배송지 정보, 주문자, 주문 목록, 총 결제 금액) 등을 접근하기 위해서는 주문(root)을 통해서 접근 가능하다.

애그리거트의 내부 구현을 캡슐화한다.

(3장 계속..)

 

리포지터리

도메인 객체를 지속적으로 사용하기 위해 물리적인 저장소에 보관하는 역할

추상화된 Repository는 도메인 계층에 속하고, 구현체들은 인프라 계층에 속한다

(4장, 5장 계속..)

 

인프라에 대한 의존

인프라 계층에 의존하던 도메인을 추상화를 통해 도메인 계층에 의존하도록 했다

인프라 계층에 의존성을 제거하는 것이 무조건 좋은 것일까?

 

@Transactional

복잡한 설정 대신 트랜잭션 처리를 어노테이션 하나만 붙이면 된다

그렇다고 테스트가 어려워진다거나, 유연성을 해치지 않는다

사용하는게 이득이다

 

@Entity, @Table (JPA)

XML 매핑 설정보다 편리함을 준다.

그렇다고 테스트가 어려워진다거나, 유연성을 해치지 않는다

사용하는게 이득이다

 

표현 계층

표현 계층은 항상 인프라에 맞게 구현할 수 밖에 없다

ex) 스프링 MVC

   

Q1. DTO 쓰는 이유

레이어간 객체를 전달할 때 DTO를 이용하는데, DTO를 왜 쓸까?

엔티티에 있는 것만 담아서 쓰면 안되나?

Entity는 도메인 로직으로 가득 차있음

정작 레이어간 통신에서 필요한 것은 로직들이 아닌, 값을 넣고 빼는것이 필요함

또한, Response를 상위 계층으로 보내는 행위는 외부에 객체를 변경시킬 수 있는 여지를 남김

 

Q2. 테스트하기 어려운 코드

자동차 경주 게임에서 자동차가 랜덤하게 이동을 해야 한다면?

테스트 작성하기 어려움. 자동차의 거리를 예측할 수 없음.

-> 자동차의 이동을 담당하는 로직을 따로 빼서 의존하자!

테스트 할 때 랜덤한 부분을 목으로 대체 가능해짐