본문 바로가기
책/도메인 주도 개발 시작하기

[도메인 주도 개발하기] 2장 아키텍처 개요

by 오오오니 2024. 1. 30.

2장 아키텍처 개요

생성일: 2024년 1월 29일 오후 10:32

아키텍처


웹브라우저에서 요청(HTTP)→표현영역에서 요청을 가공 후 응용영역에 전달 → 응용영역이 처리 결과를 표현영역에 전달 →표현영역이 응답결과를 가공 후 사용자(웹브라우저)에게 보여줌

  • 표현영역은 HTTP요청을 변환 → 응용영역에 전달 , 응용영역의 응답을 HTTP응답으로 변환→웹 브라우저에 전송
    • ex) HTTP 파라미터를 객체타입으로 변환 , 응용영역의 결과를 JSON형식으로 변환
  • 응용영역은 제공해야할 기능을 직접 구현 X, 도메인 모델에 로직 수행을 위임
    • ex) 주문 취소 로직을 직접 구현 X, Order 객체에 취소 처리를 위임.
  • 도메인 영역은 도메인 모델 구현과 핵심 로직 구현
    • ex) ‘배송지 변경’, ‘결제완료’, ‘주문 총액 계산’
  • 인프라 스트럭처 영역은 구현 기술을 다룸.
    • ex) RDBMS 연동, 메시징 큐에 메시지 전송, SMTP 를 이용한 발송기능 구현

DIP

  • 계층 구조는 상위 계층에서 하위 계층으로의 의존만 존재 (응용계층이 도메인 계층을 의존)
  • 계층 구조를 유연하게 적용해서 (그림 2) 응용→ 도메인, 응용→ 인프라 스트럭처 의존하기도함.

→ 나머지 계층이 구현 기술을 다루는 인프라스트럭처 계층에 종속

ex) 룰엔진 Drools 를 사용하는 가격 계산 예제

문제점

  1. 테스트가 어려움
  2. 구현변경의 어려움
public class CalculateDiscountService {
    private DroolsRuleEngine ruleEngine;

    public CalculateDiscountService() {
        ruleEngine = new DroolsRuleEngine();
    }

    public Money calculateDiscount(OrderLine orderLines, String customerId) {
        Customer customer = findCusotmer(customerId);
    //====   Drools에 의존
        MutableMoney money = new MutableMoney(0); //룰 적용 결괏값 보곤하기 위해 추가한 타입 
        List<?> facts = Arrays.asList(customer, money);
        facts.addAll(orderLines);
        ruleEngine.evalute("discountCalculation", facts); //"dis~ " 는 Drools의 세션 이름
        //===   Drools에 의존
        return money.toImmutableMoney();
    }


}

→ DIP로 해결

  • 고수준→ 저수준 의존에서 고수준 ←저수준 의존으로 바꿈
    • how? 추상화한 인터페이스
    • 고수준 모듈이 기능이 구현된 클래스를 의존하던 것을 인터페이스를 의존하게 하고 바꾸고,기능 구현을 인터페이스를 상속받는 클래스에서 함.
      • 고수준 모듈이 저수준 모듈을 사용할 때 저수준 모듈에 의존해야하는데, 반대로 저수준 모듈이고수준 모듈에의존한다해서 DIP라고 함 (Dependency inversion principle)

위 1,2의 문제 해결

  1. 테스트의 어려움ex) Mock 프레임 워크 : Mockito
  2. → 의존하는 것이 클래스에서 인터페이스에서 바뀌었으므로,
    구현클래스가 없어도 테스트 대역 객체를 사용해 거의 모든 기능 테스트 가능
  3. 구현 변경의 어려움→ 구현 객체를 생성하는 코드만 변경
  4. // 사용할 저수준 객체 생성 RuleDiscounter ruleDiscounter = new DroolsRuleDiscounter(); // 구현 하는 객체를 바꾸기만 하면 됨 RuleDiscounter ruleDiscounter = new SimpleRuleDiscounter(); //구현 객체를 의존주입을 통해 전달 받음. 수정 필요없음. //구현 기술을 변경해도 고수준 모듈을 (CalculateDiscountService)를 수정할 필요 없음 CalculateDiscountService disService = new CalculateDiscountService(ruleDiscounter);
  5. → 구현을 추상화한 인테페이스에 의존하므로 구현객체를 의존주입을 이용해 전달 받음

⇒ DIP를 적용하면 도메인 영역과 응용영역에 영향을 최소화해 구현 기술을 변경할 수 있지만 무조건으로 적용하지 말고 DIP의 이점을 얻는 수준에서 적용 범위를 검토

ex) @Transactional 을 이용하면 스프링에 대한 의존은 있지만 다양한 이점이 존재.

도메인 영역의 주요 구성요소


  • 엔티티 : 고유의 식별자를 갖음. Order, Member, Product 와 같이 고유한 개념을 표현하고 관련된 기능을 제공
  • 밸류 : 식별자를 가지지 않음 개념적으로 하나의 값을 표현. ex) Money, Address
  • 애그리거트 : 개념적으로 연관된 엔티티와 벨류를 묶음 ex) ‘주문’ 에그리거트
  • 리포지터리 : 도메인 모델의 영속성을 처리. DBMS 테이블에서 엔티티 객체를 로딩,저장
  • 도메인 서비스 : 특정한 엔티티에 속하지 않은 도메인 로직 제공. 여러 엔티티와 밸류를 빌요로 할때 도메인 서비스에서 로직을 구현.
    ex) 할인 금액 계산.

사진

https://velog.io/@aoqlsdl/DDD-2장.-아키텍처-개요