기존 도메인 모델링의 한계
기존의 소프트웨어 도메인 모델링은 주로 구성 요소 간의 구조와 관계를 그래프 형태로 이해하는 방식에 의존합니다. 이는 시스템의 정적인 측면을 설명하는 데는 효과적이지만, 비즈니스 워크플로우와 같은 동적인 ‘행동’을 명시적으로 표현하는 데는 부족함이 있습니다. 워크플로우는 종종 웹 컨트롤러, 백그라운드 작업 등 다양한 실행 컨텍스트에 암묵적으로 결합되어 있어 이해하고 관리하기 어렵습니다.
이벤트 소싱(Event Sourcing)의 도입
이벤트 소싱은 시스템의 상태 변화를 불변의 이벤트(Event) 형태로 기록하고, 이 이벤트들의 순차적인 적용을 통해 현재 상태를 재구성하는 방식입니다. 이는 은행 계좌의 거래 내역을 통해 잔액을 파악하는 것과 유사합니다. 핵심 구성 요소는 다음과 같습니다. * 명령(Command): 시스템 상태 변경에 대한 사용자의 의도. 유효성 검사를 거칩니다. * 이벤트(Event): 시스템에서 실제로 발생한 불변의 사실(Fact). 저장소에 영구적으로 기록됩니다. * 스트림(Stream): 특정 엔티티(예: 주문)에 대한 이벤트들을 그룹화하는 식별자. 스트림 내 이벤트는 순차적으로 처리됩니다.
CQRS(Command Query Responsibility Segregation)와 읽기 모델
이벤트 소싱은 상태 업데이트(쓰기)에 최적화되어 있지만, 복잡한 쿼리(읽기)에는 비효율적입니다. 이를 해결하기 위해 CQRS 패턴이 사용됩니다. CQRS는 데이터 모델을 두 가지로 분리합니다. * 명령 모델(Command Model): 이벤트 소싱을 사용하여 시스템 상태를 업데이트합니다. * 쿼리 모델(Query Model): UI나 클라이언트에 최적화된 읽기 전용 데이터 모델입니다. 이벤트 저장소에서 발생하는 이벤트를 수신하여 ElasticSearch, Redis, PostgreSQL 등 다양한 형태로 데이터를 재구성(프로젝션)하여 저장합니다. 쿼리 모델은 언제든지 이벤트 히스토리로부터 재구축 가능하여 유연성이 높습니다.
Ruby 구현 상세
발표자는 sourced
라는 자체 라이브러리를 활용하여 Ruby로 이벤트 소싱을 구현하는 방법을 소개합니다.
* OrderState: 주문의 현재 상태를 나타내는 단순한 인메모리 Struct
또는 해시.
* 명령/이벤트(Command/Event): AddItemCommand
, ItemAddedEvent
와 같이 기능의 한 조각을 정의하는 데이터 구조체.
* 액터(Actor): 특정 스트림(예: 주문)에 발생할 수 있는 모든 것을 캡슐화하는 클래스. OrderActor
는 command_handler
에서 명령을 검증하고 이벤트를 생성하며, event_handler
에서 이벤트를 통해 상태를 업데이트합니다.
동시성 및 워크플로우
이벤트 소싱은 스트림 단위의 동시성을 제공합니다. reaction_handler
를 통해 특정 이벤트에 반응하여 새로운 스트림(예: 결제 스트림)을 시작하거나 다른 액터에 명령을 보낼 수 있습니다. 이는 비즈니스 로직 내에서 동시성을 명시적으로 모델링하는 것을 가능하게 합니다. 이벤트 간의 인과 관계(causation)와 상관 관계(correlation)를 추적하여 복잡한 동시성 워크플로우를 감사하고 디버깅할 수 있습니다.
자동화 및 실시간 UI
- 자동화: 특정 조건(예: 주문이 결제되고 준비 완료됨)이 충족될 때,
reaction_handler
를 통해 자동으로 다음 명령(예: 주문 배달)을 실행하여 인간의 수동 작업을 대체할 수 있습니다. - 실시간 UI: 서버 센트 이벤트(SSE)를 활용하여 백엔드에서 발생하는 관련 이벤트를 브라우저에 실시간으로 전송하고, 브라우저는 수신된 HTML 조각을 DOM에 병합하여 페이지 새로고침 없이 UI를 업데이트합니다. Sinatra 애플리케이션에서
sourced
라이브러리를 통해 명령을 비동기적으로 처리하고, 프로젝터가 UI 관련 이벤트를 발생시켜 실시간 업데이트를 구현합니다.
향후 계획
발표자는 이 실험적인 작업의 향후 계획으로 버그 수정, 중첩된 상태 머신(State Machine) 및 내구성 있는 실행(Durable Execution) 개념 도입, SQLite 지원 추가, 그리고 명령/이벤트 정의와 액터 DSL을 기반으로 한 자동 다이어그램 및 문서 생성 기능을 언급합니다.