티스토리 뷰

목차

1. 계층형 아키텍처

2. DTO(Data Transfer Object)

3. 의존 역전 원칙

4. 전략적 설계 - ANTICORRUPTION LAYER

 

 

 

 

1. 계층형 아키텍처

도메인 주도 설계의 아키텍처가 별도로 정의되어 있는 것은 아니지만

계층형 아키텍처, 클린 아키텍처, 헥사고날 아키텍처 처럼 도메인을 보호하는 아키텍처의 개념이 중요하다.

계층형 아키텍처의 비즈니스 로직은 도메인 모델에서 수행되도록 한다.

Entity, Value Object 는 물론이고 비즈니스 로직이 Application Service 로 넘어가지 않도록 하는 Domain Service도 도메인 모델에 속한다.

 

 

1) Presentation Layer

  • 사용자가 시스템을 사용할 수 있는 (화면) 흐름을 제공하고 제어
  • 사용자가의 요청을 알맞은 응용 서비스에 전달하고 결과를 사용자에게 제공한다.
  • 사용자의 세션을 관리한다.

 

2) Application Layer

응용 영역은 시스템이 사용자에게 제공해야 할 기능을 구현한다.

 

Application Service

  • 사용자의 요청을 처리하기 위해 리포지터리로부터 도메인 객체를 구하고, 도메인 객체를 사용한다.
  • 로직을 직접 수행하기보다는 도메인 모델에 로직 수행을 위임한다.
  • 도메인 객체 간의 실행 흐름을 제어
  • 트랜잭션 처리
  • 도메인 영역에서 발생시킨 이벤트를 처리
public Result doSomeFunc(SomeReq req) {
    // 1. 리포지터리에서 애그리거트를 구한다.
    SomeAgg agg = someAggRepository.findById(req.getId());
    checkNull(agg);
    // 2. 애그리거트의 도메인 기능을 실행한다.
    agg.doFunc(req.getValue());
    // 3. 결과를 리턴한다.
    return createSuccessResult(agg);
}

 

[ 메서드 파라미터와 값 리턴 ]

  • 응용 서비스에 데이터로 전달할 파라미터가 두 개 이상 존재하면 데이터 전달을 위한 별도 클래스를 사용하는 것이 편리하다.
  • 응용 서비스는 표현 영역에서 필요한 데이터만 리턴하는 것이 기능 실행 로직의 응집도를 높이는 확실한 방법이다.

 

[ 값 검증 ]

  • 값 검증은 표현 영역과 응용 서비스 두 곳에서 모두 수행할 수 있다.
  • 원칙적으로 모든 값에 대한 검증은 응용 서비스에서 처리한다.
  • 표현 영역에서 필수 값과 값의 형식을 검사하면 실질적으로 응용 서비스는 아이디 중복 여부와 같은 논리적 오류만 검사하면 된다.

 

3) Domain Layer

도메인 영역은 도메인 모델을 구현한다.

 

Domain Service

  • 도메인 서비스는 애플리케이션 서비스와 달리 도메인 로직을 다룬다.
  • 엔티티와 값 객체만으로 표현하기 어려운 비즈니스 로직을 도메인 서비스를 통해 애플리케이션 계층으로 넘어가지 않도록 한다.
  • 도메인 서비스는 상태가 없을 수 있고 절차적일 수 있으며 클래스 이름이 Service로 작성되지 않을 수 있다.
  • Spring Framework에서 애플리케이션 서비스에 @Service를 사용한다면 차별을 위해 @Component를 사용하거나 별도로 어노테이션을 만들어 관리한다.

예) 송금과 관련된 정책을 처리하는 도메인 서비스

public class TransactionValidator {
    public boolean isValid(Money amount, Account from, Account to) {
        if (!from.getCurrency().equals(amount.getCurrency())) {
            return false;
        }
        if (!to.getCurrency().equals(amount.getCurrency())) {
            return false;
        }
        if (from.getBalance().isLessThan(amount)) {
            return false;
        }
        if (amount.isGreaterThan(someThreshold)) {
            return false;
        }
        return true;
    }
}

 

Domain Model

[ 값 검증 ]

도메인 모델에서의 값 검증은 유효성 검사의 개념보다는 모델링을 구현하고 모델링의 검증에 대한 개념이 강하다.

public class PhoneNumber {
    private final String phoneNumber;

    public PhoneNumber(String phoneNumber) {
        Objects.requireNonNull(phoneNumber, "phoneNumber must not be null"); // 
        var sb = new StringBuilder();
        char ch;
        for (int i = 0; i < phoneNumber.length(); ++i) {
            ch = phoneNumber.charAt(i);
            if (Character.isDigit(ch)) { // 
                sb.append(ch);
            } else if (!Character.isWhitespace(ch) && ch != '(' && ch != ')' && ch != '-' && ch != '.') { // 
                throw new IllegalArgument(phoneNumber + " is not valid");
            }
        }
        if (sb.length() == 0) { // 
            throw new IllegalArgumentException("phoneNumber must not be empty");
        }
        this.phoneNumber = sb.toString();
    }

    @Override
    public String toString() {
        return phoneNumber;
    }
}

 

 

4) Infrastructure Layer

인프라스트럭처 영역은 구현 기술에 대한 것을 다룬다.

 


2. DTO(Data Transfer Object)

1) 응용 서비스의 출력

응용 프로그램 서비스를 설계 할 때 중요한 한 가지 결정은 사용할 데이터와 반환 할 데이터를 결정하는 것

  • 도메인 모델을 직접 사용하거나, - Domain Model Everywhere
  • 별도의 DTO(Data Transfer Object) 사용하기 - Pure Domain Model

 

2) DTO(Data Transfer Object)

  • 프로세스 간에 데이터를 전달하는 객체
  • 구조체
VALUE OBJECT는 DTO가 아니다. - Martin Fowler

DTO의 용도로 VO를 사용할 수는 있지만 VO는 DTO를 의미하지 않는다.

 

3) Domain Model Everywhere

  • 도메인 모델을 모든 계층에서 사용
    • 이미 가지고 있는 클래스를 사용할 수 있다.
    • 도메인 모델과 DTO 간에 변환이 필요 없다.
  • OSIV(Open Session In View) 사용
  • Getter 메서드, Setter 메서드 사용
  • DTO는 나쁘다!

 

4) Pure Domain Model

  • 클라이언트와 도메인 모델 간의 분리
  • 애플리케이션의 외부 요구 사항과 내부 요구 사항을 분리

항상 DTO를 만드는 것은 실용적이지 않다.

 


 

3. 의존 역전 원칙

1) 고수준 모듈, 저수준 모듈

고수준 모듈

  • 어떤 의미 있는 단일 기능을 제공하는 모듈
  • e.g. 가격 할인 계산

예) 고객 정보를 구한다.

      룰을 이용해서 할인 금액을 구한다.

 

저수준 모듈

  • 고수준 모듈의 기능을 구현하기 위해 필요한 하위 기능의 실제 구현
  • e.g. 가격 할인 계산

예) RDBMS에서 JPA로 구한다.

      Drools로 룰을 적용한다.

 

2) 고수준 모듈의 의존 문제

  • 고수준 모듈이 저수준 모듈을 의존
  • 저수준 모듈의 변경에 따라 고수준 모듈이 영향을 받는다.
  • 고수준 모듈만 테스트하기 어렵다.
  • 다른 구현 기술을 사용하려면 코드의 많은 부분을 고쳐야 한다.

 

3) DIP

  • 저수준 모듈이 고수준 모듈에 의존한다고 해서 이를 DIP(Dependency Inversion Principle, 의존 역전 원칙)라고 부른다.
  • 인프라스트럭처 영역에 의존할 때 발생했던 구현 교체가 어렵다는 문제와 테스트가 어려운 문제를 해소할 수 있다.
  • 고수준 모듈은 더 이상 저수준 모듈에 의존하지 않고 구현을 추상화한 인터페이스에 의존한다.

  • DIP를 적용할 때 하위 기능을 추상화한 인터페이스는 고수준 모듈 관점에서 도출한다.
  • 추상화한 인터페이스는 저수준 모듈이 아닌 고수준 모듈에 위치한다.

 

계층형 아키텍처에서 DTO(Pure Domain Model)를 사용하고 DIP를 적용하는 이유는 도메인을 보호하기 위함이다.

결국 계층형 아키텍처에서 도메인을 보호하는 개념의 헥사고날, 어니언, 클린 아키텍처로 가게된다.

 

4) 육각형, 양파, 클린 아키텍처

육각형 아키텍처(hexagonal architecture), 양파 아키텍처(onion architecture) 및 클린 아키텍처(clean architecture)의 기본 규칙

 

4. 전략적 설계 - ANTICORRUPTION LAYER

손상 방지 레이어를 다른 하위 시스템 사이에 배치하여 격리한다.

이 레이어는 두 시스템 간의 통신을 변환하여, 다른 응용 프로그램이 해당 디자인 및 기술 방식을 손상시키지 않도록 하여 해당 시스템을 변경되지 않은 상태로 유지하도록 할 수 있다.

 

 

 

 

 

 

출처

NEXTSTEP: DDD 세레나데 3기

728x90

'DDD' 카테고리의 다른 글

[DDD] 5. 도메인 이벤트와 CQRS  (0) 2022.05.31
[DDD] 3. 도메인 주도 설계 기본 요소  (0) 2022.05.30
[DDD] 2. 도메인 모델링  (0) 2022.05.28
[DDD] 1. 도메인 주도 설계 이해  (0) 2022.05.27