https://product.kyobobook.co.kr/detail/S000061352142, Ch 7
lead-id | name | status | phone-number | -on |
---|---|---|---|---|
1 | CONVERTED | |||
2 | CLOSED | |||
6 | NEW_LEAD | |||
9 | FOLLOWUP_SET | |||
15 | PAYMENT_FAILED | |||
18 | PENDING_PAYMENT |
애그리리게이트의 현재 상태를 반영하는 스키마 대신 이벤트 소싱 기반 시스템은 애그리게이트의 수명주기의 모든 변경사항을 문서화하는 이벤트를 유지한다.
public class LeadSearchModelProjection
{
...
public void Apply(LeadInitialized @event)
{
...
Version = 0;
}
public void Apply(ContactDetailsChanged @event)
{
...
Version += 1;
}
public void Apply(Contacted @event)
{
Version += 1;
}
public void Apply(FollowupSet @event)
{
Version += 1;
}
public void Apply(OrderSubmitted @event)
{
Version += 1;
}
public void Apply(PaymentConfirmed @event)
{
Version += 1;
}
}
애그리게이트의 이벤트를 반복해서 순서대로 적절히 재정의한 Apply 매서드에 넣의면 표 7-1의 테이블에 모델링된 상태 표현이 정확하게 만들어진다.
각 이벤트를 적용한 후 증가하는 버전 필드에 주목하자. 해당 값은 비즈니스 엔티티에 가해진 모든 변경의 회수를 나타낸다. 또한 이벤트의 일부만 적용한다고 가정한다. 이 경우 '시간 여행'을 할 수 있다.
이벤트 스토어는 추가만 가능한 저장소이므로 이벤트를 수정하거나 삭제할 수 없다.
본질적으로 이벤트 소싱 패턴은 새로운 것이 아니다. 금융 산업에서는 이벤트를 사용하여 원장의 변경사항을 나타낸다. 원장은 트랜잭션을 문서화하는 추가 전용 로그다. 계정 잔액과 같은 현재 상태는 원장의 기록을 프로젝션해서 언제든지 추론할 수 있다.
이벤트 소싱 애그리게이트에 대한 각 작업은 다음 단게를 따른다.
애플리케이션 서비스는 앞에서 설명한 과정을 따른다. 관련 티켓의 이벤트를 로드하고, 애그리게이트 인스턴스를 리하이드레이션하고, 관련 명령을 호출하고, 변경사항을 데이터베이스에 다시 저정한다.
왜 '이벤트 소싱 도메인 모델'일까?
이벤트를 사용하여 상태 전화(이벤트 소싱 패턴)을 나타내는 것은 도메인 모델의 구성요소가 있든 없든 가능하다. 따라서 필자는 도메인 모델 애그리게이트의 수명주기 변경을 나타내기 위해 이벤트 소싱을 사용하고 있음을 명시적으로 보여주는 방법을 선택했다.
당면한 작업에 이 패턴을 적용할 당위성이 없으며, 대신 더 단순한 설계로 해결할 수 있는 경우라면 앞에 제시한 모든 문제는 훨씬 더 심각해진다.
모든 애그리게이트 관련 작업은 단일 애그리게이트 컨텍스트에서 수행되므로 이벤트 스토어는 애그리게이트 ID로 분할할 수 있다. 애그리게이트의 인스턴스에 속하는 모든 이벤트는 단일 샤드(shard)에 있어야 한다.