[Domain Driven Design] 7. 응용 서비스, 인프라스트럭처 개요, 모듈 구조

반응형
728x90
반응형

응용 서비스

사용자 입장에서 봤을때 웹 애플리케이션이나 데스크톱 애플리케이션과 같은 소프트웨어는 기능을 제공한다. 사용자가 애플리케이션에 기능 실행을 요청하면 그 요청을 처음 받는 영역은 표현 영역이다. 

스프링 MVC를 사용해서 웹 애플리케이션을 구현했다면 컨트롤러가 사용자의 요청을 받아 처리하게 된다.

 

표현 영역은 사용자가 전송한 데이터 형식이 올바른지 검사하고 문제가 없다면 데이터를 이용해서 응용 서비스에 기능 실행을 위임한다. 이때 표현 영역은 사용자가 전송한 데이터를 응용 서비스가 요구하는 형식으로 변환해서 전달한다. 웹 브라우저를 이용해서 기능 실행을 요청하면 표현 영역에 해당하는 컨트롤러는 과정 1.1에서 HTTP 요청 파라미터를 응용 서비스가 필요로 하는 데이터로 변환해서 응용 서비스를 실행할때 인자로 전달한다. 

 

https://minkukjo.github.io/dev/2020/11/02/DDD-02/

 

응용 서비스는 도메인 모델을 이용해서 기능을 구현한다.

기능 구현에 필요한 도메인 객체를 리포지터리에서 가져와 실행하거나 신규 도메인 객체를 생성해서 리포지터리에 저장한다. 두 개 이상의 도메인 객체를 사용해서 구현하기도 한다.

 

'예매하기', '예매 취소'와 같은 기능을 제공하는 응용 서비스는 도메인의 상태를 변경하므로 변경 상태가 물리 저장소에 올바르게 반영되도록 트랜잭션을 관리해야한다. 

 

응용 서비스는 @Transactional 어노테이션을 이용해서 트랜잭션을 관리한다.
package com.myshop.order.command.application;

import com.myshop.order.NoOrderException;
import com.myshop.order.command.domain.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class CancelOrderService {
    ...

    @Transactional
    public void cancel(OrderNo orderNo, Canceller canceller) {
        Order order = orderRepository.findById(orderNo)
                .orElseThrow(() -> new NoOrderException());
        if (!cancelPolicy.hasCancellationPermission(order, canceller)) {
            throw new NoCancellablePermission();
        }
        order.cancel();
    }

}

 

 

인프라스트럭처 개요

인프라스트럭처(infrastructure)는 표현 영역, 응용 영역, 도메인 영역을 지원한다. 도메인 객체의 영속성 처리, 트랜잭션, REST 클라이언트 등 다른 영역에서 필요로 하는 프레임워크, 구현 기술, 보조 기능을 지원한다. DIP에서 언급한 것처럼 도메인 영역과 응용 영역에서 인프라스트럭처의 기능을 직접 사용하는 것보다 이 두 영역에 정의한 인터페이스를 인프라스트럭처 영역에서 구현하는 것이 시스템을 더 유연하고 테스트하기 쉽게 만들어준다.

 

DIP

https://devfunny.tistory.com/873

 

[Domain Driven Design] 5. DIP(Dependency Inversion Principle, 의존 역전 원칙)

인프라스트럭처 의존성 문제점 표현 계층, 응용 계층, 도메인 계층이 상세한 구현 기술을 다루는 인프라스트럭처 계층에 의존성이 존재하는 경우의 문제점 https://devfunny.tistory.com/872 [Domain Driven D

devfunny.tistory.com

 

하지만 모든 인프라스트럭처에 대한 의존을 없앨 필요는 없다. 예를들어 스프링을 사용할 경우 응용 서비스는 트랜잭션 처리를 위해 스프링이 제공하는 @Transactional을 사용하는 것이 편리하다. 영속성 처리를 위해 JPA를 사용할 경우 @Entity나 @Table과 같은 JPA 전용 어노테이션을 도메인 모델 클래스에 사용하는 것이 XML 매핑 설정을 이용하는 것보다 편리하다. 

 

구현의 편리함은 DIP가 주는 장점(변경의 유연함, 테스트가 쉬움)만큼 중요하기 때문에 DIP의 장점을 해치지 않는 범위에서 응용 영역과 도메인 영역에서 구현 기술에 대한 의존을 가져가는 것이 나쁘지 않다고 생각한다.

 

 

모듈 구성

아키텍처의 각 영역은 별도 패키지에 위치한다. 

https://minkukjo.github.io/dev/2020/11/02/DDD-02/

도메인이 크면 각 하위 도메인으로 나누고, 각 하위 도메인마다 별도 패키지를 구성한다.

https://minkukjo.github.io/dev/2020/11/02/DDD-02/

도메인 모듈은 도메인에 속한 애그리거트를 기준으로 다시 패키지를 구성한다.

예를들어 카탈로그 하위 도메인이 상품 애그리거트와 카테고리 애그리거트로 구성될 경우 도메인을 두개의 하위 패키지로 구성할 수 있다.

https://minkukjo.github.io/dev/2020/11/02/DDD-02/

애그리거트, 모델, 리포지터리는 같은 패키지에 위치한다.

예를들어 주문과 관련된 Order, OrderLine, Orderer, OrderRepository 등은 com.myshop.order.domain 패키지에 위치시킨다.

도메인이 복잡하면 도메인 모델과 도메인 서비스를 다음과 같이 별도 패키지에 위치시킬 수도 있다.

 

  • com.myshop.order.domain.order : 애그리거트 위치
  • com.myshop.order.domain.service : 도메인 서비스 위치

 

응용 서비스도 다음과 같이 별도 패키지로 구분할 수 있다.

 

  • com.myshop.catalog.application.product
  • com.myshop.catalog.application.category

 

 

반응형

Designed by JB FACTORY