ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 도메인 주도 개발 시작하기 CH.1 ~ CH.3
    DESIGN PATTERN & ARCHITECTURE 2024. 6. 10. 23:13

     

     

     

     

    쿠버네티스 스터디를 끝내고 새로운 스터디를 들어가게 되어, 책을 공부하면서 정리를 해보려고 한다!

    책은 최범균 저자의 <도메인 주도 개발 시작하기> 이다. 

    https://www.yes24.com/Product/Goods/108431347

     

    도메인 주도 개발 시작하기 - 예스24

    가장 쉽게 배우는 도메인 주도 설계 입문서!이 책은 도메인 주도 설계(DDD)를 처음 배우는 개발자를 위한 책이다. 실제 업무에 DDD를 적용할 수 있도록 기본적인 DDD의 핵심 개념을 익히고 구현을

    www.yes24.com

     

     

    Ch. 1 : 도메인 모델 시작하기 

     

    1.1

    도메인

    • 소프트웨어로 해결하고자 하는 문제영역 
    • 한 도메인은 다시 하위 도메인으로 나눌 수 있음 
      • 고정된 하위 도메인이 존재하는 것은 아님 
      • 상황에 따라서 하위 도메인 구성 여부가 달라짐 
    • 특정 도메인을 위한 소프트웨어라고 해서 도메인이 제공해야 할 모든 기능을 직접 구현하는 것은 아님 

     

    1.2 

    도메인 전문가와 개발자 간 지식 공유 

    • 도메인 전문가는 해당 도메인에 대한 지식과 경험을 바탕으로 본인들이 원하는 기능 개발을 요구 
    • 개발자는 이러한 요구사항을 분석 및 설계하여 코드를 작성, 테스트, 배포 
      • => 코딩에 앞서 요구사항을 올바르게 이해하는 것이 중요
      • 개발자와 전문가가 직접 대화 
    • 이해관계자와 개발자도 도메인 지식을 갖춰야 함 

     

    1.3

    도메인 모델

    • 특정 도메인을 개념적으로 표현한 것 
      • 도메인 자체를 이해하기 위한 개념 모델 
    • 여러 관계자들이 동일한 모습으로 도메인을 이해하고 지식을 공유하는데 도움 
    • 구현 기술에 맞는 구현 모델이 따로 필요 

     

    1.4 

    도메인 모델 패턴 

    • 아키텍처  
      • 사용자 인터페이스 또는 표현 
        • 사용자의 요청을 처리하고 사용자에게 정보를 보여줌 
      • 응용 
        • 사용자가 요청한 기능을 실행 
        • 도메인 계층을 조합해서 기능을 실행
      • 도메인 
        • 시스템이 제공할 도메인 규칙을 구현 
          • 도메인의 핵심 규칙을 구현 
            • 도메인 모델 패턴 : 도메인 규칙을 객체 지향 기법으로 구현하는 패턴으로 핵심 규칙을 구현한 코드가 도메인 모델에만 위치하기 때문에 규칙이 바뀌거나 규칙을 확장해야 할 때 다른 코드에 영향을 줄일 수 있음 
      • 인프라스트럭처 
        • 외부 시스템과의 연동을 처리

     

    1.5

    도메인 모델 도출 

    • 도메인에 대한 이해 없이 코딩을 시작할 수 없음 
    • 모델을 구성하는 핵심 구성 요소, 규칙 기능을 찾아야 함 
      • 특정 조건이나 상태에 따라 제약이나 규칙이 달리 적용되는 경우가 많음 
    • 문서화 
      • 지식을 공유하는 목적 
      • 전체 구조를 이해하고 더 깊게 이해할 필요가 있는 부분을 코드로 분석해 나가면 됨 

     

    1.6

    엔티티와 밸류 

    • 엔티티 
      • 고유한 식별자를 가짐 
        • 식별자가 같으면 두 엔티티는 같다고 판단 가능
        • 중복되지 않도록 주의 
      • 생성 방식 
        • 특정 규칙에 따라 생성 
          • ex) 주문번호, 운송장 번호, 카드번호, 현재 시간과 다른 값을 조합 등 
        • UUID나 Nano ID와 같은 고유 식별자 생성기 사용 
        • 값을 직접 입력 
        • 일련번호 사용
          • 시퀀스나 DB의 자동 증가 칼럼 사용
    • 밸류 
      • 개념적으로 완전한 하나를 표현할 때 사용 
      • 코드의 가독성 향상 
      • 안전한 코드 작성을 위해 데이터 변경 기능을 제공하지 않는 불변 타입으로 구현을 권장
    • 식별자의 경우 도메인에서 특별한 의미를 지니는 경우가 많아 식별자를 위한 밸류 타입을 사용해서 의미가 잘 드러날 수 있도록 할 수 있음 
    • 도메인 객체가 불완전한 상태로 사용되는 방지하기 위해 생성자를 통해 생성 시점에 필요한 것을 전달받을 수 있도록 해야함 
    • 도메인 모델에 get/set 메서드를 무조건적으로 추가하는 것을 지양 
      • set 메서드의 경우 private으로 내부에서 데이터를 변경할 목적으로 사용
      • 불변 밸류 타입을 사용하여 불변 타입의 장점을 살리도록 구현 
    • DTO의 get / set 
      • 프레젠테이션 계층과 도메인 계층이 데이터를 주고받을 때 사용 
      • set 메서드 대신 프레임워크를 이용한 private 필드 직접 값 할당 방법을 사용해보자 

     

    1.7

    도메인 용어와 유비쿼터스 언어 

    • 최대한 도메인 용어를 사용해서 도메인 규칙을 코드로 작성하여 언어 차이에서 오는 버그를 줄이자 
    • 유비쿼터스 언어 
      • 전문가, 관계자, 개발자가 도메인과 관련해서 사용하는 공통의 언어 

     

     

     

    Ch.2 : 아키텍처 개요 

     

    2.1

    네 개의 영역 

    • 표현 영역 
      • 사용자의 요청을 받아 응용 영역에 전달하고 응용 영역의 처리 결과를 다시 사용자에게 보여주는 역할 
    • 응용 영역 
      • 시스템이 사용자에게 제공해야 할 기능을 구현 
      • 기능 구현을 위해 도메인 영역의 도메인 모델을 사용 
        • 로직을 직접 수행하기 보다 도메인 모델에 로직 수행을 위임 
    • 도메인 영역 
      • 도메인 모델을 구현 
        • 도메인의 핵심 로직을 구현 
    • 인프라스트럭처 영역 
      • 구현 기술을 다룸 
      • 논리적인 개념을 표현하기 보다 실제 구현을 다룸 
      • 도메인, 응용, 표현 영역은 인프라스트럭처에서 제공하는 기능을 사용해서 필요한 기능을 개발

     

    2.2 

    계층 구조 아키텍처 

    • 표현 영역과 응용 영역은 도메인 영역을 사용 
    • 도메인 영역은 인프라스트럭처 영역을 사용 
      • => 상위 계층에서 하위 계층으로의 의존만 존재하고 하위 계층은 상위 계층에 의존하지 않음 
      • 계층 구조를 유연하게 적용하기도 함 
    • 표현, 응용, 도메인 계층이 인프라스트럭처에 의존하면 테스트가 어렵고, 기능 확장이 어려워짐 

     

     

    2.3 

    DIP

    • 고수준 모듈의 기능을 구현하려면 여러 하위 기능이 필요 
      • 고수준 모듈 : 응용, 도메인 영역 
    • 저수준 모듈 : 하위 기능을 실제로 구현한 것 
      • 저수준 모듈 : 인프라스트럭처 영역 
    • DIP 
      • 의존 역전 원칙 
      • 추상화 인터페이스를 이용해서 고수준 모듈이 저수준 모듈에 의존하지 않고, 저수준 모듈이 고수준 모듈에 의존하도록 변경 
      • 이를 통해 구현 기술을 변경하더라도 수정이 필요하지 않고, 테스트가 용이해짐 
      • DIP를 적용할 때 하위 기능을 추상화한 인터페이스는 고수준 모듈 관점에서 도출
      • 단, DIP를 항상 적용할 필요는 없음 
        • @Entity와 같이 특정 구현 기술에 의존적인 코드를 도메인에 포함하는 것이 효과적일 때도 있음 

     

    2.4 

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

    • 엔티티
      • 고유의 식별자를 갖는 객체 
      • 자신의 라이프 사이클을 갖는다 
      • 도메인의 고유한 개념을 표현 
      • 도메인 모델의 데이터를 포함하며 해당 데이터와 관련된 기능을 함께 제공 
      • 도메인 모델의 에닡티 != DB관계현 모델의 엔티티
      • 기능 구현을 캡슐화해서 데이터가 임의로 변경되는 것을 막음 
      • 두개 이상의 데이터가 개념적으로 하나인 경우 밸류 타입을 이용해서 표현 가능 
    • 밸류
      • 식별자를 갖지 않는 객체 
      • 개념적으로 하나의 값을 표현 
      • 다른 밸류 타입의 속성이나 엔티티 속성으로 사용 
      • 불변으로 구현할 것을 권장 
        • 밸류 타입의 데이터를 변경할 떄는 객체 자체를 완전히 교체 하는 것을 의미 
    • 애그리거트
      • 관련 객체를 하나로 묶은 군집
        • 연관된 엔티티와 밸류 객체를 개념적으로 하나로 묶은 것 
      • 상위 수준에서 모델을 볼 수 있어야 전체 모델의 관계와 개별 모델을 이해하는데 도움이 됨 
      • 객체를 관리하는 루트 엔티티를 가짐 
        • 애그리거트에 속해 있는 엔티티와 밸류 객체를 이용해서 애그리거트가 구현해야 할 기능을 제공 
    • 레포지터리 
      • 도메인 모델의 영속성 처리 
        • 물리적인 저장소에 도메인 객체를 보관 
      • 구현을 위한 도메인 모델 
      • 애그리거트 단위로 도메인 객체를 저장하고 조회하는 기능을 정의 
      • 응용 서비스는 의존 주입과 같은 방식을 사용해서 실제 레포지터리 구현 객체에 접근 
        • 응용 서비스가 필요로 하는 메서드를 제공 
    • 도메인 서비스 
      • 특정 엔티티에 속하지 않은 도메인 로직을 제공 

     

     

    2.5 

    요청 처리 흐름 

    • 1. 표현 영역 
      • 사용자가 전송한 데이터 형식이 올바른지 검사
      • 응용 서비스에 기능 실행을 위임 
      • 사용자가 전송한 데이터를 응용 서비스가 요구하는 형식으로 변환해서 전달 
    • 2. 응용 서비스 
      • 도메인 모델을 이용해서 기능 구현 
      • 두개 이상의 도메인 객체를 사용해서 구현하기도 함 
      • 도메인의 상태를 변경하므로 변경 상태가 물리 저장소에 올바르게 반영 되도록 트랜잭션을 관리해야함 
    • 앱 서비스가 변경의 경우 도메인 객체를 이용해서 도메인 로직을 실행하고 단순 조회의 경우 레포지토리를 바로 조회하기도 함 

     

     

    2.6 

    인프라스트럭처 개요 

    • 표현, 응용, 도메인 영역을 지원 
    • 구현의 편리함이 DIP가 주는 다른 장점만큼 중요하기 때문에 응용 영역과 도메인 영역에서 상황에 따라 구현 기술에 대한 의존성을 가져갈 수도 있음 

     

    2.7 

    모듈 구성 

    • 도메인이 크면 하위 도메인 별로 모듈을 나눔 
    • 애그리거트, 모델, 레포지터리는 같은 패키지에 위치 
    • 도메인이 복잡하면 도메인 모델과 도메인 서비스를 별도의 패키지에 위치시킬 수 있음 
      • ex) 
        • 애그리거트 : com.shop.order.domain.order
        • 도메인 서비스 : com.shop.order.domain.service
    • 응용 서비스도 도메인 별로 패키리를 구분할 수 있음 
      • com.shop.order.application.order
      • com.shop.order.application.product

     

     

    Ch.3 : 애그리거트 

    3.1 

    애그리거트 

    • 상위 수준에서 모델 구성을 파악하여 요구 사항 구현에 용이하도록 함
    • 관련된 모델을 하나로 모았기 때문에 한 애그리거트에 속한 객체는 유사하거나 동일한 라이프 사이클을 가짐 
      • 애그리거트에 속한 구성요소는 대부분 함께 생성하고 함께 제거 
    • 경계를 가짐
      • 애그리거트에 속한 객체는 다른 애그리거트에 속하지 않음  
      • 독립된 객체군으로 자기자신을 관리할 뿐 다른 애그리거트르 관리하지 않음 
      • 경계 설정 
        • 도메인 규칙과 요구사항 
        • 도메인 규칙에 따라 함께 생성되는 구성요소이거나 함께 변경되는 빈도가 높은 객체  한 애그리거트에 속할 가능성이 높음 
        • A가 B를 갖는다는 조건이 한 애그리거트에 속하는 것을 의미하는 것은 아님 
          • ex) product 와 review

     

    3.2 

    애그리거트 루트 

    • 도메인 규칙을 지키려면 애그리거트에 속한 모든 객체가 정상 상태를 가져야 함 
    • 애그리거트 루트 
      • 애그리거트에 속한 모든 객체를 일관된 상태로 관리 
      • 애그리거트가 제공해야 할 도메인 기능을 구현 
      • 도메인 규칙에 따라 애그리거트에 속한 객체의 일관성이 깨지지 않도록 메서드 구현 
      • 애그리거트 내부의 다른 객체를 조합해서 기능을 완성 
      • 구성 요소의 상태를 참조하고 기능 실행을 위임 
      • 전체적인 성능을 위해 트랜잭션 범위는 작은 것이 좋음 
        • => 처리량과 충돌을 방지하기 위해 한 트랜잭션 안에서는 한개의 애그리거트만 수정해야함 
        • = 즉, 한 애그리거트에서 다른 애그리거트를 변경하면 안됨 
        • 결합도 증진 
    • 애그리거트 외부에서 애그리거트에 속한 객체를 직접 변경해서는 안됨 
      • 논리적인 데이터 일관성이 깨지게 됨 
      • 밸류 타입의 내부 상태를 변경하려면 애그리거트 루트를 통해서만 가능해야 함 
    • 둘이상의 변경이 필요하다면 응용 서비스에서 수정 
      • ex) 도메인 이벤트 활용 
      • 상황에 따라서는 한 트랜잭션에서 두개 이상의 애그리거트를 변경하는 것을 고려 

     

    3.3 

    리포지터리와 애그리거트 

    • 애그리거트가 개념상 완전한 한 개의 도메인 모델을 표현하므로 영속성을 처리하는 리포지터리는 애그리거트 단위로 존재 
    • 애그리거트는 개념적으로 하나이므로 레포지터리는 애그리거트 전체를 저장소에 영속화 해야함 
      • = 동일하게, 애그리거트를 구하는 레포지토리 메서드는 완전한 애그리거트를 제공해야 함 
      • 제공하지 않으면 필드나 값이 올바르지 않아 애그리거트의 기능 실행중 nullPointerException과 같은 문제가 발생할 수 있음 
    • 애그리거트 상태가 변경되면 모든 변경을 원자적으로 저장소에 반영해야 함 
      • ex) 트랜잭션 이용 

     

    3.4

    ID를 이용한 애그리거트 참조 

    • 다른 애그리거트를 직접 참조시 문제 
      • 다른 애그리거트의 상태를 변경할 수 있음 
        • 애그리거트간의 의존 결합도를 높임 
      • 지연, 즉시 로딩 등 성능과 관련된 고민 필요 
      • 기술의 확정에 어려움 
    • => ID를 활용해서 다른 애그리거트를 참조하도록 하여 모델의 복잡도를 낮추고 응집도를 높인다 
      •  => 애그리거트 수준에서 지연 로딩과 동일한 결과를 만들어냄 
    • 단, 조회 성능을 위해 조인을 사용하는 것을 고려 해야함 
      • 애그리거트 마다 다른 저장소를 사용하면 조회 성능 증진을 위해 캐시나 조회 전용 저장소를 따로 구성하는 것을 고려 

     

    3.5 

    애그리거트 간 집합 연관 

    • 1-N의 관계
      • 컬렉션을 이용해서 표현 가능 
      • 개념적으로는 애그리거트 간에 1-N 연관이 있더라도 성능 문제 때문에 애그리거트 간의 1-N 연관을 실제 구현에 반영하지 않음 
    • M-N의 관계
      • 개념적으로 양쪽 애그리거트에 컬렉션으로 연관을 만듬
      • 실제 요구사항을 고려해서 구현에 포함할지를 결정해야 함 
    • 목록이나 상세 화면과 같은 조회 기능은 조회 전용 모델을 이용해서 구현하는 것이 좋음 

     

    3.6 

    애그리거트를 팩토리로 사용 

    • 애그리거트를 생성하는 팩토리 역할 
    • 응용 서비스에서 애그리거트의 상태를 확인하지 않아도 됨 
    • 애그리거트가 갖고 있는 데이터를 이용해서 다른 애그리거트를 생성해야 한다면, 애그리거트에 팩토리 메서드를 구현하는 것을 고려해야함 
    • 도메인 로직을 한곳에 위치시키는 것이 목적 

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

Designed by Tistory.