티스토리 뷰

IT/SW Design

DDD 완전 정복 - MSA 서비스 분리의 핵심, 도메인 모델링은 어떻게 하는가?

Stv 2025. 5. 20. 19:39

목차


    MSA 아키텍처 설계를 고민하다 보면 반드시 마주치는 개념이 있다.
    바로 DDD, Domain-Driven Design (도메인 주도 설계)이다.

    DDD는 단순한 설계 기법이 아니다.
    비즈니스와 개발이 완전히 같은 언어를 공유하면서 시스템을 설계하는 철학이다.

    이번 포스팅에서는 DDD가 무엇인지, 왜 필요한지, 실제로 도메인을 어떻게 모델링하고 서비스로 분리할 수 있는지까지 A to Z로 전부 정리해보겠다.

    1️⃣ DDD란 무엇인가?

    DDD(Domain-Driven Design)는 복잡한 비즈니스 로직을 효과적으로 다루기 위한 설계 방법론이다.

     

    📌 키워드만 간단히 정리하면

    • Domain (도메인) : 비즈니스 영역 (ex. 주문, 결제, 정산 등)
    • Model (모델) : 도메인을 코드로 옮긴 표현
    • Ubiquitous Language (통합 언어) : 개발자와 비즈니스가 동일한 용어로 대화
    • Bounded Context (경계 컨텍스트) : 도메인을 의미 단위로 나눈 경계

    예시

    "주문이 결제되면 배송을 준비한다"
    -> 이 한 문장에서 "주문", "결제", "배송"이 각각 도메인이자 서비스 분리의 후보가 된다.

    2️⃣ DDD가 왜 중요한가?

    🧩 서비스 분리의 기준이 되기 때문

     

    • MSA를 구현하려면 서비스를 나눌 기준이 필요하다.
    • DDD는 이 기준을 비즈니스 중심으로 만들어준다.
    • 기존의 기술 중심 분할 (컨트롤러/서비스/DAO)가 아니라
    • 비즈니스 역할과 책임을 중심으로 코드를 분리할 수 있게 해준다.

    3️⃣ DDD의 핵심 개념 정리

     

    ① Entity

    • 고유한 식별자를 가진 객체 (예: 주문, 사용자)
    • 상태가 시간이 지나도 유지됨
    class Order {
      private Long id;
      private List<OrderItem> items;
    }

    ② Value Object

    • 식별자 없이 값 자체가 중요 (예: 주소, 전화번호)
    • 불변 객체로 설계
    class Address {
      private String city;
      private String street;
    }

    ③ Aggregate

    • Entity + 관련 Value Object의 집합
    • 변경은 항상 루트(Aggregate Root)를 통해서만 가능
    예: 주문(Order) 안에 여러 개의 주문 항목(OrderItem)이 있지만, 항상 Order 단위로 조작

    ④ Repository

    • Aggregate를 조회/저장하는 인터페이스 (DB 접근)
    interface OrderRepository {
      Order findById(Long id);
      void save(Order order);
    }

    ⑤ Service

    • 도메인 객체들이 할 수 없는 복잡한 비즈니스 로직을 담당
    • 내부 로직은 최대한 도메인 객체에 위임하는 것이 좋다

    ⑥ Bounded Context

    • 도메인의 의미가 유요한 의미적 경계
    • 이 경계를 기준으로 서비스를 나누고 DB를 나눈다.
      • 예시 : 결제라는 단어는 "주문 도메인"에서는 결제여부를 의미하고, "정산 도메인"에서는 정산금액을 의미할 수 있다.         이 경우 이 둘은 분명히 다른 Bounded Context다.

    4️⃣ 도메인 모델링 어떻게 할까? (실무 방식)

    ✅ 1. 비즈니스 이해 먼저

    • 기획자, PO, 현업과 협업하면서 용어와 흐름 정리
    • 시나리오 기반으로 "주요 개체"와 "주요 흐름" 도출

    ✅ 2. 유비쿼터스 언어 정리

    • 모든 팀원이 공통된 용어로 이야기하도록 용어집 작성
    • '주문 등록', '배송 요청', '정산 승인' 등 이벤트 중심 용어 사용

    ✅ 3. 컨텍스트 맵(Context Map) 작성

    • 각각의 도메인 경계를 시각화
    • 도메인 간 관계 (Upstream/Downstream, ACL, Shared Kernel 등) 도식화

    ✅ 4. 도메인 -> 서비스로 나누기

    • Bounded Context 기준으로 하나의 컨텍스트를 하나의 마이크로서비스로 전환
    • 각 서비스는 자체 데이터, 자체 API만 사용

    5️⃣ DDD 기반 설계 예시

    예를 들어, 물류 시스템이라면 아래와 같은 도메인이 있을 수 있다.

    도메인 주요 Entity 주요 이벤트
    주문 Order, OrderItem 주문 생성, 주문 변경
    결제 Payment 결제 완료, 결제 실패
    배송 Delivery, Tracking 배송 시작, 배송 완료
    정산 Settlement 정산 승인, 정산 완료
    • 이런 각각의 도메인이 곧 Bounded Context가 됨
      • 각각 하나의 마이크로서비스로 분리 가능해짐

     

    6️⃣ DDD 적용 시 주의할 점

    • 너무 이론에 빠져 실무 적용 못하면 의미 없음
    • 항상 복잡한 도메인에만 적용 (CRUD 중심 단순 시스템엔 과함)
    • 유비쿼터스 언어는 실제 사용하는 말과 최대한 맞춰야 함
    • 서비스 분리 후엔 통신/데이터 일관성 문제가 생기므로 Event-driven 구조 고려 필요

    ✅ 마무리

    DDD는 단순히 설계 기법이 아니라, 비즈니스 언어와 개발 언어를 일치시키고, 도메인 경계를 중심으로 시스템을 설계하는 사고 방식이다.

    실무에서는 무조건 이론대로 할 수는 없지만, 서비스를 비즈니스 중심으로 나누기 위한 기준으로 DDD만큼 강력한 도구는 아직 없다.