피드로 돌아가기
강남언니 공식 블로그Backend
원문 읽기
트랜잭션은 도메인 모델이 아니다
강남언니가 도메인 모델에 트랜잭션·버전 정보를 노출하지 않으면서 IoC 패턴으로 동시성 제어를 구현한 성과형 광고 시스템 아키텍처
AI 요약
Context
성과형 광고 시스템은 실시간으로 많은 노출·클릭과 그에 따른 과금이 발생하므로 동시성 상황 관리가 필수적이다. 도메인 모델에 영속성 지식(데이터베이스 트랜잭션, 버전 정보)을 노출해야 한다는 욕구가 발생했으나, 이는 DDD의 핵심 원칙인 도메인 모델의 순수성을 훼손한다.
Technical Solution
- Campaign 애그리거트를 Rich Domain Model로 설계: 불변 필드(식별자, 병원ID)와 가변 필드(이름, 예산, 상태)를 명확히 분리하고 상태 변경 명령을 캡슐화
- SwitchOnCampaignCommandExecutor 도메인 서비스 구현: 리파지토리에서 애그리거트를 읽어와 명령을 실행하고 변경된 상태를 저장하는 일관된 패턴
- 도메인 이벤트(CampaignSwitchedOn, BudgetExhausted) 발행: 애그리거트 내 이벤트 컬렉션에 저장 후 리파지토리가 메시지 브로커로 전달
- BudgetExhaustedEventHandler 이벤트 처리기 구현: 메시지 리스너에서 정제된 도메인 이벤트를 수신해 Campaign.handle() 호출
- 리파지토리에 상태 변경 제어권 이동: 함수형 인자(modifier)를 받아 데이터 모델 조회→캠페인 변환→수정→저장 일련의 과정을 트랜잭션 내에서 수행하고, 비관적/낙관적 잠금을 구현체 레벨에서만 관리
Key Takeaway
DDD에서 도메인 모델의 순수성을 유지하려면 영속성 관심사(트랜잭션, 잠금, 버전)의 제어권을 리파지토리 구현체로 역전시켜야 하며, 이는 도메인 서비스와 이벤트 처리기가 도메인 모델을 통해 비즈니스 논리를 표현하되 동시성 제어는 인프라에 위임하는 설계 원칙을 따른다.
실천 포인트
DDD를 실제로 적용하면서 트랜잭션이나 버전 관리 같은 영속성 지식을 도메인 모델에 섞고 싶은 유혹을 받을 때, 리파지토리 메서드에 함수형 인자(예: Consumer<Campaign>)를 사용해 도메인 객체의 상태 변경을 리파지토리 내 트랜잭션 경계에서 처리하면 도메인 모델을 깨끗하게 유지하면서도 낙관적 잠금(버전 정보)이나 비관적 잠금을 구현할 수 있다.