[DDD] 기초 (의존성, DIP)

남순식·2026년 3월 17일

1. DDD (Domain Driven Design) & Bounded Context

DDD는 소프트웨어의 핵심 로직(도메인)을 중심에 두는 설계 방식이다.
여기서 가장 중요한 도구 중 하나가 Bounded Context다.

거대한 시스템을 한꺼번에 설계하면 용어가 꼬이고 복잡해진다.
그래서 특정 용어가 동일한 의미를 갖는 "경계(Boundary)"를 설정하는 것.

예시: 회사 내에서 'User'라는 단어는 문맥에 따라 다르다.

  • 주문 Context: 음식을 시키는 '주문자'
  • 배달 Context: 음식을 배달하는 '라이더'
  • 정산 Context: 수수료를 받는 '정산 대상'

이렇게 경계를 나누면 각 서비스(Microservice)가 자기 역할에만 집중할 수 있다.


2. Aggregate (애그리거트)

Bounded Context 내부에서 데이터 변경의 단위를 정의한 것

관련된 객체들을 하나의 묶음으로 취급하는 것.
이 묶음에는 Aggregate Root(엔티티 중 대장)가 존재하며, 모든 외부 통신은 이 루트를 통해서만 이루어진다.

예시: '장바구니(Cart)' 시스템

Cart (Root)와 CartItem (자식)이 있다고 가정

외부에서 CartItem의 수량을 직접 수정하는 게 아니라, Cart에게 "아이템 수량을 변경해줘"라고 요청. 이렇게 하면 장바구니 전체 금액 계산이나 유효성 검사 로직이 깨지지 않고 유지될 수 있음.


3. DIP (Dependency Inversion Principle, 의존성 역전 원칙)

이 모든 구조를 유연하게 만드는 마법 같은 원칙.
"고수준 모듈은 저수준 모듈에 의존해서는 안 된다"는 원칙.

  • 문제 상황: 도메인(고수준)이 JPA Repository(저수준/인프라)를 직접 의존하면, DB를 Redis로 바꾸거나 테스트를 할 때 도메인 코드까지 고쳐야 함.

  • 해결 (DIP): 도메인 계층에 CartRepository라는 인터페이스를 둠.
    실제 구현체(JPA, Redis 등)는 인프라 계층에서 구현(CartJpaRepository, CartRedisRepository, CartQueryDslRepository ... ).

  • 결과: 데이터를 저장할 인터페이스만 있으면 실제 구현이 JPA인지 Redis인지는 상관없다.


모든 개념을 합친 예시: '장바구니 담기'

  • Bounded Context: '주문/장바구니' 문맥에서 작업이 일어남.
  • Layered & Application: 사용자가 버튼을 누르면 CartController를 거쳐 CartApplication 서비스가 호출.
  • Aggregate: CartApplication은 DB에서 Cart Aggregate Root를 가져옴.
  • DIP: 이때 CartApplication은 CartRepository 인터페이스를 호출.
    실제로는 Spring이 관리하는 JpaCartRepository나 RedisCartRepository가 동작.
  • Logic: Cart 객체 내부에서 상품 정보를 검증하고 CartItem을 추가하는 핵심 로직이 실행.
profile
응집력있는 시간을 보내기 위한 블로그

0개의 댓글