LostCatBox

(책읽기)도매인 주도 설계 시작하기

Word count: 644Reading time: 4 min
2026/01/05 Share

왜?

  • DDD 개발 예시를 알기위해서
  • DDD의 정확한 예시를 알기위해

도메인 모델 시작하기

  • 도메인 = 문제의 영역
  • 도메인 모델 -> 엔티티와 밸류로 나눔
    • 엔티티 - 식별값이 존재
      • setter를 제공하지않고, changeXXX, close() 등의 다양한 목적를 나타내는 행위를 정의한 메서드로 제공하자.
      • 예시 - Order, Delivery
    • 밸류 - 식별값이 없음
      • 밸류는 불변 객체를 원칙으로 설계하고, 매번 새로운 객체를 반환하도록 한다.
      • 예시 - Money, Address, OrderItem

아키텍처 개요

계층 구조 아키텍처

  • 표현 : 클라이언트의 요청에 따라 알맞는 응용 서비스 호출 및 응답 반환
  • 응용 : 비즈니스 로직을 갖지 않으며, 도메인 계층에게 비즈니스 로직 처리 요청함.
    • 응용 서비스
  • 도메인 :
    • 도메인 모델
    • 도메인 서비스
  • 인프라스트럭처

애그리거트

  • 애그리거트는 하나의 Transaction 단위를 가지는 집합이다.

  • 하위 도메인 모델들의 기능들의 상태변화 및 비즈니스 로직을 구현하고있다.

  • 루트 에그리거트(엔티티) + 밸류 + 엔티티 등로 구성되어 하나의 애그리거트가 된다.

  • 루트 애그리거트를 통해서만 하위 도메인 모델(하위 밸류, 하위 엔티티) 의 상태변화를 일으키도록 해야한다.

  • 다른 애그리거트의 값이 필요할 경우, ID값을 이용하여 다른 애그리거트를 참조하는것을 추천한다

    • 특징 : lazy로딩과 유사함. 실제로 필요할때 정보를 가져오도록 쿼리하는 형태로 로직 구현
    • 문제점 : N+1 문제가 동일하게 발생할 수 있음
    • 해결방법 : 데이터 조회를 위한 DAO를 만들어서 한번에 쿼리
  • 예시

    주문(루트)

    • 주문리스트(밸류)

    • 발송상태(밸류)

리포지터리와 모델 구현

  • JPA를 활용한 리포지터리 구현

  • 다양한 JPA 활용법 포함

    • AttributeConverter
    • Collection
    • 밸류를 이용한 ID 매핑
    • 별도 테이블에 저장하는 밸류 매핑
    • ID 참조와 조인 테이블 이용한 단방향 M-N 매핑
  • 기타 특이사항

    • 도메인 엔티티와 JPA 엔티티를 같은 객체로 구현하였다.(개발 비용 절감)
    • 도메인 엔티티에 @Entity, @Column와 같은 에너테이션 존재 -> 인프라 계층에 의존성 생김 -> JPA 기술을 바꿀일이 거의없고, 단위테스트 가능한 구조기때문에 단점이지만, 장점인 개발 비용절감 효과큼

스프링 데이터 JPA를 이용한 조회기능 (CQRS 관련에서 조회)

  • 스펙 구현(Spec)

  • 정렬 구현(Sort)

  • 페이징 활용법(Pageable, PageRequest)

  • 동적 인스턴스 생성(new Object())

  • 하이버네이트 @Subselect 활용

응용 서비스와 표현 영역

  • 응용 서비스 구현

    • 응용 서비스의 매개변수는 비즈니스로직+ 입력 검증 필요
    • 에그리거트 찾음 -> 에그리거트.도메인로직 -> 결과리턴
    • 도메인 서비스 특징
      • 도메인 서비스는 도메인 데이터 값 활용 + 변경을 한다.
      • 만약, 도메인 로직이 응용 서비스에 있다면, 모든 응용 서비스들에 중복 검증 코드가 생기므로 바람직하지않다.
    • 응용 서비스 특징
      • 한 책임을 여러개 가져가는거 보다, 클래스를 분리하여, 각자의 책임을 가져가는 것이 좋다.
        • Controller -> ChangePasswordService-> password 도메인 모델의 검증 호출
        • Controller -> OrderCreateService-> order 도메인 모델 생성 팩토리 호출
  • 표현 영역의 역할

    • 알맞는 응용 서비스를 호출하고 그에 맞는 DTO로 전환 필수 (사이드 이펙트 방지를 위해 표현과 응용 계층 완벽한 분리하는것 추천)
    • 입력에 대한 검증 책임 위치에 대한 2가지 유형
      • 2개 계층에 분산하여 각각 검증
        • 표현 영역 : 필수 값, 값의 형식, 범위 등을 검증한다.
        • 응용 서비스: 데이터의 존재 유무와 같은 논리적 오류를 검증한다.
      • 응용 서비스에서 필수값, 논리적인 검증 모두 한다.
        • 응용 서비스: 필수 값, 값의 형식, 범위 + 데이터의 존재 유무와 같은 논리적 오류를 검증한다.
  • 조회 전용 기능과 응용 서비스

    • 표현에서 단순 쿼리, 검색 쿼리 등이 필요할 경우, 간단한 응용 서비스를 통해 구현된 DAO를 활용하는 것 추천 (경우에 따라 응용 서비스 계층도 생략)

도메인 서비스

  • domain에 속함
  • 도메인 서비스는 다음과같을 때 활용한다.
    • 도메인 서비스는 하나의 에그리거트에서 처리하기 어려운 도메인 로직
    • 도메인 모델 하나에 담기 어려운 경우
    • 외부 서비스(포트) 이용해야할 경우
  • 도메인 서비스를 에그리거트에 포함시키지말자 -> 응용 서비스에서 주입받아서 사용.
    • 에그리거트의 책임은 다른 에그리거트에 대한 책임을 포함하지 않는것이 바람직하다.

애그리거트 트랜잭션 관리

  • 배타락, 낙관적락 설명

도메인 모델과 바운디드 컨텍스트

  • 문맥이 달라지는 곳이 바운디드 컨텍스트이며, 바운디드 컨텍스트에 도메인 모델은 하나다.
  • 바운디드 컨텍스트 간의 통신할때, 동기(API), 비동기(messageQ) 를 알맞게 사용하고, 상류-하류를 구분하여, 상류 코드를 변경하는 것에 각별히 주의하자.

이벤트

  • 바운디드 컨텍스트 간의 강결합을 없앨때, 효과적이다.
  • 이벤트는 과거에 벌어진 어떤 것이다.
  • 이벤트 처리는 퍼블리셔-브로커-리스너으로 구성되어있다.
  • 구현방법
    • 동기 처리
      • @EventLister 사용
        • 동일한 트랜잭션 범위에서 실행된다.
    • 비동기 처리 (기본적으로 트랜잭션 범위 분리됨)
      • 로컬 핸들러로 비동기 실행
        • @Async 로 별도 쓰레드를 이용해 비동기 처리
      • 메시지 큐 사용
        • 카프카, 래빗 사용
      • 이벤트 저장소와 이벤트 포워더 사용
      • 이벤트 저장소와 이벤트 제공 API 사용
  • 주의할점
    • 이벤트 발급이 포함된 트랜잭션은 막상 실패하고 이벤트는 발급됨과 같은 실패 케이스 등도 고민해봐야한다.
      • @TransactionEventListener 사용해보기

CQRS

  • 조회노드, 명령 노드를 나누면, 조회성능이 매우 올라간다.
  • JPA 모델과 DAO 모델을 나눠서, 쓰기와 읽기에 알맞게 활용가능하다.
CATALOG
  1. 1. 왜?
  2. 2. 도메인 모델 시작하기
  3. 3. 아키텍처 개요
    1. 3.1. 계층 구조 아키텍처
  4. 4. 애그리거트
  5. 5. 리포지터리와 모델 구현
  6. 6. 스프링 데이터 JPA를 이용한 조회기능 (CQRS 관련에서 조회)
  7. 7. 응용 서비스와 표현 영역
  8. 8. 도메인 서비스
  9. 9. 애그리거트 트랜잭션 관리
  10. 10. 도메인 모델과 바운디드 컨텍스트
  11. 11. 이벤트
  12. 12. CQRS