[도서 정리] 도메인 주도 개발 시작하기 - 최범균

  • 최범균님의 도메인 주도 설계 관련 도서를 읽고 내용을 정리했다.

    • 도메인 주도 DDD Start! 도메인 주도 설계 구현과 핵심 개념 익히기 (2016년)

    • 도메인 주도 개발 시작하기 (2022년)

      • DDD Start를 보완하여 출판한 도서이기 때문에 도메인 주도 개발 시작하기를 보면 된다

         

    • 새롭게 알게 된 개념

      • 애그리거트

        • 같은 생명주기를 공유하는 도메인들을 의미하며, 팩토리 메서드 등으로 루트엔티티에서 로직의 일관성을 지키며 관리하도록 한다

      • 도메인 서비스

        • 기존에도 서비스를 분리하거나 필요한 유틸들을 생성하여 사용했었지만 도메인 로직을 서비스에서 관리한다는 개념 자체는 단순하지만 생각하지 못했던 부분이었던 것 같다.

        • 도메인 모델 로직을 한없이 늘리거나 응용 계층에서 일반 로직과 섞어서 복잡하게 짜지말고 도메인 서비스를 사용하는 것이 좋을 것 같다

      • 인프라스트럭처

        • 계층 아키텍처 기준으로 repository는 영속성 계층이었지만 도메인 주도 설계에서는 repository는 도메인 계층이며 실제 repository의 기능을 구현한 구현체는 인프라스트럭처 계층으로 나뉘었다

        • 도메인 주도 설계에서는 고수준 모듈과 저수준 모듈을 구분하고 고수준은 interface 로직을 호출할 뿐 저수준 구현체와는 아무런 관계를 하지 않는다

 


 

도메인 주도 설계란, 도메인을 중심으로 설계하는 것이다

  • 도메인이란 소프트웨어로 해결하고자 하는 문제 영역이다

    • 쉽게 말해서 쇼핑몰 서비스라 하면 상품, 주문, 배송 등이 해당 서비스에서 해결하고자하는 문제 영역이라 할 수 있다

     

  • 도메인과 엔티티는 다르다

    • 도메인 모델 엔티티는 테이블만이 기준이 아니라 같은 단위의 속성도 묶는다

    • 엔티티의 특징은 식별자를 갖는다는 것이다

    • Value의 특징은 값들의 묶음이라는 것이다

      • 테이블이 있다하더라도 모두 엔티티는 아니다

      • 한 엔티티에 포함되지만 DB 정규화에서 나눠진 테이블들이 있다

      • 객체로 속성을 관리하게 되면 가독성이 높아지고 상태 관리의 일관성을 높일 수 있다

     

  • 애그리거트

    1. 운명공동체인 객체의 묶음이다

    2. 루트 엔티티에서 기능을 제공한다

      • 다른 객체에서 변경할 수 있도록 하면 일관성이 깨지고 중복 로직이 발생한다

      • 루트 엔티티가 변경 주체이지만 실제 변경은 대상 객체에게 위임할 수 있다

    3. 트랜잭션 범위는 작을수록 좋으며, 한 트랜잭션에서 두 개 이상의 애그리거트를 건들지 않도록 한다

      • 서비스에서 서로 다른 애그리거트를 호출하여 변경하도록 한다

      • JPA의 지연로딩의 개념과 같다. 즉시로딩은 객체 간의 결합도가 높아진다

      • N+1이 발생한다면 한 번에 호출하는 join 쿼리를 생성하여 조회하도록 한다

      • N:M 관계에서는 중간 테이블을 두어 다루는 것이 좋다

    4. 논리적인 하나의 도메인은 나열식으로 생성하기보다 하나의 애그리거트에서 팩토리 메서드로 함께 생성하는 것이 좋다

       

 

  • 도메인 주도 설계에서의 계층

    • 표현 계층, 응용 계층, 도메인 계층, 인프라 스트럭처 계층

       

    • 고수준 모듈응용 계층 도메인 계층이며, 저수준 모듈은 인프라스트럭처 계층이다

      • interface가 호출되는 곳은 고수준 모듈이어야한다

    • 표현 계층, 응용 계층에 도메인 로직은 넣지 않도록 한다

      • 응용 계층에서 중복 로직이 발생한다면 메서드로 분리할 필요가 있으며, 서비스 로직이 커진다면 서비스 클래스 수준에서 분리가 필요하다

      • 응용 계층은 트랜잭션을 관리한다

    • 응용 계층(서비스 계층)은 표현 계층에 필요한 데이터만 전달한다

      • 계층 간 필요한 정보만 교환하고 서로 의존성을 줄인다

      • 보통 표현 계층에서는 값을 검증하고, 응용 계층에서는 논리적 검증/존재 검증을 한다

    • 리포지토리는 domain 계층이며, 리포지토리를 구현한 클래스는 infrastructure 계층이다

      • infrastructure 계층 : 영속성을 구현하거나 외부와 통신하는 기능을 제공하는 레이어

    • 도메인 계층에는 도메인 모델과 도메인 서비스가 있다

    • 저수준을 추상화하는 것을 경계해야한다!

      • 저수준을 추상화하면 도메인이 구현체에 의존하게 된다

 

  • 핵심 서비스 로직에서 -> 도메인 모델 로직과 부가 서비스 로직을 호출한다

    • 주문과 할인 도메인 로직이 있을 때 주문에 할인된 금액 정보가 필요하다면 해당 로직을 주문 애그리거트에 할당하지 않아야한다

    • 도메인 서비스를 생성하여 기능을 구현하는 것이 맞다 => 주문 도메인 서비스에서 할인금액을 계산하도록 한다

    • 할인 로직이 달라지는 경우, 로직을 추가하기보다 interface로 구현체를 조립할 수 있다

 

  • Bounded Context; 모델은 컨텍스트(문맥)에서 결정된다

    • 상품 모델은 카탈로그 상품, 주문 상품, 배송 상품 등 다양한 상품이 있다

    • 각 컨텍스트에서의 상품이 각각의 모델이 된다

 

  • 이벤트

    • 이벤트가 발생할 때 후처리 관련한 트리거를 발생시키거나 데이터 동기화 작업을 한다

    • 예를 들어 결제는 외부 서비스를 이용하는 경우가 많은데 외부 서비스에 문제가 생겼을 때 롤백을 할 것인지, 추후에 재시도할 것인지를 결정해야한다

    • 이러한 경우 트랜잭션이나 여러 경우를 고려하여 로직을 짜게 되면 복잡한 로직으로 이어지게 되기 때문에 이벤트를 발생시켜 처리하도록 한다

      • spring에서 ApplicationEventPublisher와 @EventListener를 사용할 수 있다

    • 비동기 처리는 다음과 같은 방식이 있다

      • 코드 수준에서 @Async를 사용

      • 메세지 큐 사용

      • 이벤트 저장소 DB 및 별도 프로그램 구축

    • 재처리 정책이나 멱등성 등을 고려하여 설계하도록 한다

 

  • CQRS

    • Command and Query Responsibility Segregation

    • 명령과 조회의 책임 분리

    • DB에 대한 Write와 Read가 분리되는 것이다

    • 데이터 변경이 있을 시 -> 메세지 이벤트 발생 -> 연관 데이터 변경

  

 

댓글을 작성해보세요.