도메인 주도 개발 시작하기 : 2장 아키텍처 개요

일단 해볼게·2025년 7월 13일
0

book

목록 보기
19/31

2.1 네 개의 영역

  • 표현 영역

    • 사용자의 요청을 받아 응용 영역에 전달하고 응용 영역의 처리 결과를 다시 사용자에게 보여주는 역할

    • 응용 서비스가 요구하는 형식의 객체 타입으로 변환해서 전달

  • 응용 영역

    • 기능을 구현하기 위해 도메인 영역의 도메인 모델을 사용
      • 실제 도메인 로직 구현은 도메인 모델에 위임
  • 도메인 영역

    • 도메인 모델 구현
    • 도메인 핵심 로직 구현
  • 인프라스트럭처 영역

    • 구현 기술에 대한걸 다룬다.
      • RDBMS 연동, 메시징 큐에 메시지 전송/수신, 레디스 연동 등

2.2 계층 구조 아키텍처

  • 상위 계층에서 하위 계층으로의 의존만 존재하고 하위 계층은 상위 계층을 의존하지 않는다.
  • 계층 구조를 엄격하게 적용한다면 상위 계층은 바로 아래의 계층에만 의존을 가져야 하지만 구
    현의 편리함을 위해 계층 구조를 유연하게 적용
  • 만약 인프라스트럭처에서 도메인 영역의 핵심 로직을 수행한다면?
    • 핵심 로직을 담당하는 서비스를 테스트하기 어렵다. → 테스트의 어려움
    • 구현 방식을 변경하기 어렵다. → 확장의 어려움
    • 해결 방법 : DIP

2.3 DIP

  • 고수준 모듈

    • 의미있는 단일 기능을 제공하는 모듈
      • 가격 할인 계산이라는 기능 제공
  • 저수준 모듈

    • 고수준 모듈을 구현하기 위한 하위 기능을 구현
      • JPA, Drools
  • 구현 변경과 테스트가 어려운 문제를 해결하기 위해서는?

    • DIP (의존 역전 원칙)
      • 저수준 모듈이 고수준 모듈에 의존하도록 변경
        - 추상화한 인터페이스 사용
        - 행위만 작성하고 실제 구현은 인터페이스를 상속한 구현체에 적용한다.
        - 그러면 다른 계층은 행위 자체만 알고 실제 구현에 대해서는 모른다. → 의존하지 않는다.

    • 이전에는 저수준 모듈의 구현체가 필요했으나 인터페이스를 이용해 대역 객체를 사용해서 테스트가 가능하다.
  • DIP 주의사항

    • 저수준 모듈에서 인터페이스를 추출하지 않도록 주의

    • 도메인 관점이 아니라 룰 엔진이라는 저수준 모듈 관점에서 도출된 경우

    • 주문 시 통지 방식에 SMS를 추가해야 한다는 요구사항이 들어왔을 때 응용 영역의 OrderService는 변경할 필요가 없다.

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

  • 엔티티와 밸류 타입
    요소설명
    엔티티 ENTITY고유의 식별자를 갖는 객체로 자신의 라이프 사이클을 갖는다.
    밸류 VALUE고유의 식별자를 갖지 않는 객체로 주로 개념적으로 하나인 값을 표현할 때 사용된다. 엔티티의 속성으로 사용할 뿐만 아니라 다른 밸류 타입의 속성으로도 사용할 수 있다.
    애그리거트 AGGREGATE애그리거트는 연관된 엔티티와 밸류 객체를 개념적으로 하나로 묶은 것이다. 예를 들어, 주문과 관련된 Order 엔티티, OrderLine 밸류, Orderer 밸류 객체를 ‘주문’ 애그리거트로 묶을 수 있다.
    리포지터리 REPOSITORY도메인 모델의 영속성을 처리한다.
    도메인 서비스 DOMAIN SERVICE특정 엔티티에 속하지 않은 도메인 로직을 제공한다. ‘할인 금액 계산’은 상품, 쿠폰, 회원 등급, 구매 금액 등 다양한 조건을 이용해서 구현하게 되는데, 이렇게 도메인 로직이 여러 엔티티와 밸류를 필요로 하면 도메인 서비스에서 로직을 구현한다.
    • 도메인 모델의 엔티티는 단순히 데이터를 담고 있는 데이터 구조라기보다는 데이터와 함께 기능을 제공하는 객체
    • 도메인 모델의 엔티티는 두 개 이상의 데이터가 개념적으로 하나인 경우 밸류 타입을 이용해서 표현할 수 있다.
    • 밸류는 불변으로 구현할 것을 권장하며, 이는 엔티티의 밸류 타입 데이터를 변경할 때는 객체 자체를 완전히 교체한다는 것을 의미
  • 애그리거트
    • 도메인 모델이 복잡해지면 개발자가 전체 구조가 아닌 한 개 엔티티와 밸류에만 집중하는 상황이 발생
      • 상위 수준에서 모델을 관리하지 않고 개별 요소에만 초점을 맞추다 보면, 큰 수준에서 모델을 이해하지 못해 큰 틀에서 모델을 관리할 수 없는 상황에 빠질 수 있다.
    • 도메인 모델에서 전체 구조를 이해하는 데 도움이 되는 것이 애그리거트
      • 주문 애그리거트 → 주문, 배송지 정보, 주문자, 주문 목록, 총 결제 금액 등 하위 모델로 구성
    • 군집에 속한 객체를 관리하는 루트 엔티티를 갖는다.
      • 애그리거트에 속해 있는 엔티티와 밸류 객체를 이용해서 애그리거트가 구현해야 할 기능 제공
      • 애그리거트 루트를 통해 간접적으로 애그리거트 내의 다른 엔티티나 밸류 객체에 접근
        • 애그리거트 단위로 캡슐화
          • 주문에서 배송지를 변경할 경우 Order를 통해서 ShippingInfo를 변경한다.
  • 리포지터리
    • RDBMS, NoSQL, 로컬 파일과 같은 물리적인 저장소에 도메인 객체를 보관
    • 도메인 모델을 사용해야 하는 코드는 리포지터리를 통해서 도메인 객체를 구한 뒤에 도메인 객체의 기능을 실행

2.5 요청 처리 흐름

  • 표현 영역은 사용자가 전송한 데이터 형식이 올바른지 검사하고 문제가 없다면 데이터를 이용해서 응용 서비스에 기능 실행을 위임
  • 응용 서비스는 도메인 모델을 이용해서 기능을 구현

2.6 인프라스트럭처 개요

  • 표현 영역, 응용 영역, 도메인 영역을 지원
  • 무조건 인프라스트럭처에 대한 의존을 없앨 필요는 없다.
    • 예를 들어 스프링을 사용할 경우 응용 서비스는 트랜잭션 처리를 위해 스프링이 제공하는 ©Transactional을 사용하는 것이 편리

2.7 모듈 구성

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

  • 도메인이 크면 하위 도메인 별로 모듈을 나눈다.
  • 애그리거트, 모델, 리포지터리는 같은 패키지에 위치시킨다.
  • 도메인이 복잡하면 도메인 모델과 도메인 서비스를 별도 패키지에 위치시킬 수도 있다.
    • com.myshop.order.domain.order : 애그리거트 위치
    • com.myshop.order.domain.service:도메인 서비스 위치
  • 모듈 구조를 세분화하는데 정해진 규칙은 없다. 한 패키지에 너무 많은 타입이 몰려서 코드를 찾을 때 불편한 정도만 아니면 된다. 책의 필자는 한 패키지에 가능하면 10~15개 미만으로 타입 개수를 유지하려고 노력한다.
profile
시도하고 More Do하는 백엔드 개발자입니다.

0개의 댓글