MSA 기술과 적용 연구 14
오랜만에 일민형을 만난 날 우리는 모델링에 관한 이야기를 했다. 사실 <도메인 모델, Ongoing 설계 그리고 정원관리>편은 그와 만나기 전에 나눈 이야기와 만나서 나눈 이야기를 섞어 쓴 글이다.
특히나 아래 문장의 그에게 처음으로 한 말이기도 하다.
모델의 가치는 추상화인데, 코드와 일대일대응을 시도하면 그 장점을 모두 훼손한다.
대화 중에 그가 이벤트 스토밍을 언급했다. 이벤트 스토밍 위키피디아 페이지를 찾아보았다. 이벤트 스토밍은 워크숍 형태로 도메인 지식을 빠르게 정리하는 방법이다. 그 결과물은 주로 포스트잇으로 벽에 정리하는데, 이때 다음 7가지 구성 요소로 구분할 수 있다고 한다.
이벤트 스토밍이란 방법은 DDD의 맥락에서 개발된 소통 방법이라고 한다.
It was invented by Alberto Brandolini in the context of domain-driven design (DDD).
하지만 DDD 커뮤니티가 말하는 도메인 이벤트라는 표현의 쓰임에 있어서는 차이가 있다고 봐야 한다.
일단 위키피디아에 나온 예제를 보자. 최소한의 배경 지식만 있다면 쉽게 이해할 수 있게 예를 쓰려고 노력했을 것이다. 계정을 만들고(AccountCreated) 주문을 생성하는(OrderCreated) 일을 도메인 이벤트의 예로 들고, 그에 상응하는 명령(Commands)을 CreateAccount, CreateOrder 등으로 예로 들었다.
반면에 Domain event를 키워드로 구글링하면 제일 먼저 뜨는 페이지 저자의 견해는 사뭇 다르다.
페이지 마지막에 단락 제목이 <Not breaking out of the CRUD mindset>인 구절을 보자.
One of the most common mistakes when starting with Domain Events and with DDD in general is to not go the whole way and figure our what is actually going on in the domain. It is easy to fall into the trap of naming all events SomethingCreated, SomethingUpdated and SomethingDeleted. While not a problem in itself it does not make use of the powerful thing we get by adding the context and meaning to the actual change that the Domain Event represent. You lose the intent of the event and reading the event log later will not provide that much value.
위키피디아의 예시는 MS의 개발 도구가 제공하던 UI 이벤트와 명령어를 쌍으로 만들어 쓰던 전통적 습관을 연상시킨다. 마치 DDD를 쓰고 싶어서 Domain Event를 차용했으나 CRUD 맥락을 벗어나지 못하고 있는 개발자의 작명 사례라고 할 수도 있다. 물론, 위키피디아 페이지 저자가 그렇다는 것이 아니라 설계와 구현에 DDD를 적용한다고 하면 해당 표현을 그렇게 해석할 수 있다고 말하는 것이다.
근본적인 문제는 도메인 이벤트라는 말 자체가 갖는 범용성이다. 일단 위키피디아에는 domain event라는 페이지가 없다. 반면 앞서 살펴본 이벤트 스토밍에서의 정의는 단순하다. 비즈니스 수행 과정에서 벌어지는 모든 일을 도메인 이벤트로 정의할 수 있다. 제약 사항은 도리어 영문법적인 표기밖에 없다.
An event that occurs in the business process. Written in past tense.
이는 마틴 파울러의 2005년 클래스도와 유사하다.
마틴 파울러의 domain event 정의는 이렇다. 과거에 벌어졌던 일이기 때문에 과거형으로 쓰는 일을 설명해준다.
Captures the memory of something interesting which affects the domain
정작 DDD의 저자인 Eric Evans의 책에는 도메인 이벤트가 없다. 내 기억에는 초창기 DDD 커뮤니티에서 PDF 로 일부가 추가되었다. 하지만, 커뮤니티가 저자가 다루지 않은 많은 내용을 추가했고, 구글링을 조금만 해봐도 다양한 자료를 접할 수 있다.
그 중에 MSA 대가인 Chris Richardson의 정의를 인용해보자. 그는 Domain Event 개념을 정의한 것이 아니라 DDD 구현할 때 패턴(검증된 설계 방법)으로 정의했다.
Organize the business logic of a service as a collection of DDD aggregates that emit domain events when they created or updated. The service publishes these domain events so that they can be consumed by other services.
서비스를 구성하는 비즈니스 로직을 DDD Aggregates 모음으로 조직화 하면, Aggregates의 생성과 수정을 도메인 이벤트의 발생으로 취급할 수 있다. 서비스는 이렇게 정의한 도메인 이벤트를 발행(publish)하면, 다른 서비스가 필요에 따라 소비할 수 있다. 복잡한 데이터 조작과 일관성을 맞추는 일을 도메인 개념으로 다룰 수 있게 하는 일이다.
스파게티 코드를 고차원의 함수로 조직화 시키는 일이다.
인터넷에서 찾은 그림 하나로 개념을 시각화 할 수도 있다.
쓰고 보니 <MSA를 대하는 개발자의 필수 마음자세>편에서 소개한 분산 트랜젝션이라는 낡은 방법에 대한 우아한 대책일 수 있다. 아래 그림도 구글링으로 찾은 것인데, <MSA를 대하는 개발자의 필수 마음자세>편에서 설명한 Bounded Context와 앞서 다룬 패턴 설명을 한번에 할 수 있는 그림이다.
사용자 등록(User Registration)이라는 이벤트를 처리하기 위해 수정해야 할 데이터와 유관 데이터의 일관성을 맞추는 일을 생각해보자. 이 글을 보고 분산 트랜젝션을 떠올리는 분은 건강의 위해 글을 그만 읽고 브라우저를 닫으시길 권한다. 그런 분이 아니고 MSA 적용에 관심이 있는 분에게라면 앞서 설명한 Chris Richardson의 도메인 이벤트 패턴의 예시로 이걸 들 수 있다. Wallet, User가 수정해야 할 두 개의 Aggregates이다. 이때, Rental 이 별도의 맥락(BoundedContext)이고, Accounting도 별도의 맥락이라고 가정하자. 별도의 맥락이면, MSA 구현과 딱이다. 그렇게 되면 관계도로 그린 initialze wallet 과 create user 라는 선이 동일한 이벤트(User Registration)에 대해서 각각의 맥락(MSA라면 마이크로 서비스)에서 Aggregates에 반영할 일이 된다. 명쾌하지 않은가? 왜 이런 방법을 두고 2PC 같은 구식을 쓰겠는가?