도메인 이벤트와 애플리케이션 이벤트의 차이점에 대해 알아보자.
주의) 이벤트의 정의는 발행자가 결정하는 것이고, 아래 설명은 모두 "발행자" 기준으로 된 설명이다.
도메인 이벤트
도메인 이벤트(Domain Event)란 비즈니스 관점의 이벤트를 의미한다.
도메인 모델 내에서 “무엇이 실제로 발생했는지”를 표현하는데 집중하며, 도메인 언어를 사용하여 표현한다.
주로 “주문이 생성되었다”, “새로운 손님이 입장했다”와 같은 방식으로, 비즈니스적 상황의 변화를 알리는데 집중한다.
목적
- 도메인 모델 간 결합도를 최소화하는데 사용한다.
- Event Sourcing 구현 시 상태를 복원할 수 있는 근거를 제공하는데 사용한다.
- 비즈니스 규칙 변경에 따른 확장성 확보가 가능하다.
애플리케이션 이벤트
애플리케이션 이벤트(Application Event)란 애플리케이션 레이어 하단에서 발생하는 이벤트를 의미한다.
애플리케이션 프레임워크 또는 운영 흐름 상에서 발생하는 기술적 이벤트(트랜잭션 끊기, 비동기 처리)를 표현하는데 집중하며, 기술 스펙/구현을 중심으로 정의된다.
예시
- Spring의 ContextRefreshedEvent
- RequestHandledEvent
목적
- 컴포넌트 간 통신(이벤트 리스너/퍼블리셔)을 위해 사용한다.
- 로깅, 모니터링, 트랜잭션 관리 등 인프라 기능 분리하는데 사용한다.
- 애플리케이션의 라이프사이클 트리거(생성/초기화/삭제 트리거)를 제공한다.
주요 차이점(표)
구분 | 도메인 이벤트 | 애플리케이션 이벤트 |
---|---|---|
관점 | 비즈니스(도메인) 관점 | 기술(인프라/프레임워크) 관점 |
언어 | 도메인 용어 사용 (Ubiquitous Language) | 기술/프레임워크 용어 사용 |
불변성 | 생성 시점 이후 상태 변경 불가 (immutable) | 일반적으로 mutable 가능하나, 구현에 따라 다름 |
발행 주체 | Aggregate Root 혹은 도메인 서비스 | 애플리케이션 컨텍스트, 프레임워크 컴포넌트 |
소비자(Listener) | 도메인 서비스, 도메인 이벤트 핸들러 | 애플리케이션 레벨의 리스너(로깅, 트랜잭션, 모니터링 등) |
용도 | 비즈니스 로직 분기, 연관 도메인 모델 변경, 이벤트 소싱 | 애플리케이션 라이프사이클 관리, 인프라 기능 분리, 모니터링 |
영속화 | 이벤트 소싱 시 저장소에 보관 가능 | 대체로 영속화하지 않으며, 필요 시 로그 목적(ex. Audit)으로 처리 |
분산 처리/통합 | 내부 도메인 통신에 초점, 필요 시 메시징 큐로 확장 가능 | 시스템 간 통합(Integration Event)으로 확장하는 형태도 있으나, 기본은 프레임워크 내부 |
트랜잭션 범위 | 도메인 트랜잭션 경계 내 | 애플리케이션 트랜잭션 경계 및 비즈니스 트랜잭션과 무관 |
그렇다면, 이벤트는 어떻게 설계하는 것이 좋을까?
도메인 객체 전체 전달?
이벤트의 전달은 사실상 매개변수 의존성 관점으로 봐야 한다.
만약 도메인 객체를 전부 전달하게 될 경우, 구독자가 도메인 객체 전체에 의존하게 되는 문제가 발생한다.
클래스 이름에 이벤트 정보가 담겨있는데, 그냥 빈 이벤트 전달?
그렇다고 빈 이벤트(state가 없는 이벤트)가 되어선 안된다. 만약 아무 정보도 받지 못한다면, 구독자는 해당 도메인을 다시 리포지토리에서 다시 꺼내와야 하는 문제가 발생한다. 그러면 “구독 시점의 최신 정보”를 알게 되고, “변경 시점의 변경 정보”를 알 수 없게 되버린다..
그럼 뭘, 어떻게 담아야 하는가?
이벤트 이름과의 관계성을 관점으로 넣어주자.
해당 이벤트와 관련된 정보만 최소한으로 담도록 하여, 꼭 필요한 정보만 담도록 하자.
도메인 이벤트 퍼블리셔(인터페이스)는 도메인 로직이 아닌데, 도메인 레이어에 있어도 될까?
도메인 이벤트 퍼블리셔는 ‘핵심 비즈니스 로직’ 자체는 아니지만, 도메인 모델의 행위(Behavior) 를 외부로 노출하기 위한 도메인 서비스역할을 수행하게 된다. 따라서, 도메인 이벤트 퍼블리셔라는 "계약(Contract)"이 도메인 레이어에 있어도 된다는 근거가 된다.
객체지향은 일종의 “우리 팀을 위한 배려”다.
변경의 영향력 최소화
- 우리가 작성하는 코드는 혼자 쓰는 코드가 아니다.
- 다른 누구라도 코드의 수정에 두려움이 없어지도록 → “이 코드 내가 건드려도 되나? 무서워…” 라는 느낌이 안들도록 만들어주어야 한다.
- “뭐 이거 고치면 되겠네~” 라는 안심이 들도록 코드를 작성해야 한다.
- 최고의 코드 → 처음보는 사람도 “내가 쓴 코드같다"라는 느낌을 받는 코드라고 생각한다.
- 간단하게 정하자면, 상급자의 코드 스타일을 따라가는 것이 가장 적합하겠지만,
- 세상 일은 어떻게될지 모르니, 변화에 대처하는 자세가 필요하다.
그럼 애그리거트간 관계도 직접 맺지 말고, 전부 식별자를 통해 서로를 알게 해야하나?
- JPA 관점에선, fetch join 같은 기능을 사용하지 못하므로, 성능/개발 생산성적으로 아쉬워진다.
- JDBC와 비슷한 수준으로 개발 생산성이 내려간다.
- JDBC는 원래 생산성이 JPA에 비해 느리니, 해당사항이 없다.
- 확실한 “개념적 격벽”이 있는 관계끼리만 id만으로 서로를 알게 하면 성능적으로도, 설계적으로도 적합한 구조를 띄게 된다.
'Article > 도메인 주도 설계 이해하기' 카테고리의 다른 글
DDD - JDBC에서 Child Entity를 생성/수정/삭제하는 방법 (0) | 2025.04.27 |
---|---|
도메인 이벤트와 State Machine 시스템 설계 - 강아지 키우기 (0) | 2025.04.05 |
도메인 서비스 - DDD의 적용, JPA 엔티티와의 비교 (0) | 2025.04.03 |
DDD 트릴레마 - 도메인 모델 완전성 vs 도메인 모델 순수성 (0) | 2025.04.01 |
객체지향 기초 - SOLID 원칙 (0) | 2025.03.07 |