[SE100 #018] 이벤트 스토밍으로 도메인 발견하기
소프트웨어 공학 100 주제 시리즈의 18번째 글이다. (카테고리: 요구사항 공학)
한 줄 요약
이벤트 스토밍은 도메인 전문가와 개발자가 긴 벽 앞에서 “무슨 일이 일어났나” 를 과거형 주황 스티커로 시간순으로 붙여 가며 업무 전체를 함께 그리는 워크숍이다. 요구사항을 한 사람씩 인터뷰해서는 보이지 않는 부서 간 경계, 용어 충돌, 아무도 책임지지 않는 구간을 몇 시간 만에 드러낸다.
왜 필요한가
요구 도출의 기본기는 인터뷰다. 그런데 업무가 여러 부서를 거치면 인터뷰는 구조적으로 실패한다.
- 주문팀은 “주문 완료” 가 결제 승인이라고 말하고, 물류팀은 출고 확정이라고 말한다. 각자의 인터뷰 기록은 모두 맞다. 합쳐 보면 모순이다.
- 업무의 진짜 문제는 부서 사이에 있다. 한 부서는 “넘겼다” 고 하고 다음 부서는 “받은 적 없다” 고 한다. 어느 인터뷰에도 그 틈은 나오지 않는다.
- 분석가가 인터뷰를 모아 문서를 만드는 동안 몇 주가 가고, 그 문서를 검토하는 사람은 자기 부분만 읽는다.
도메인 주도 설계의 보편 언어와 바운디드 컨텍스트는 이 문제를 겨냥한 개념이지만, “어떻게 찾느냐” 는 별개 문제다. 이벤트 스토밍은 그 발견 방법이다.
핵심 개념
원전과 기본 규칙
Alberto Brandolini 는 2013년 블로그 글 Introducing Event Storming에서 기본 단계를 이렇게 적었다.
- 맞는 사람을 초대한다. 넓은 회의실에 6~8명, 질문할 줄 아는 사람(그리고 답을 궁금해하는 사람)과 답을 아는 사람을 섞는다.
- 모델링 공간을 무제한으로 준다. 복잡한 문제가 제대로 분석되지 못하는 이유는 문제를 볼 공간이 부족해서다. 문제는 화이트보드보다 크다. 그는 이케아 종이 롤을 즐겨 쓴다고 했다.
- 도메인 이벤트부터 탐색한다. 도메인 이벤트는 도메인에서 일어난 의미 있는 일이다. 소프트웨어로 쉽게 옮길 수 있지만, 진짜 가치는 비기술자도 금방 이해한다는 점이다. 관례상 주황 스티커에 쓰고 시간순으로 붙인다.
- 이벤트의 원인을 찾는다. 사용자 행동의 결과라면 명령(파란 스티커), 외부 시스템이나 시간의 흐름 때문이라면 그것을 표시한다.
이후 기법이 다듬어져 지금은 eventstorming.com과 Brandolini 의 Leanpub 책 Introducing EventStorming이 공식 자료다.
왜 “이벤트” 부터인가
명사부터 시작: "주문, 고객, 상품, 쿠폰…" → 데이터 모델 논쟁, 속성 목록
동사부터 시작: "주문하다, 결제하다…" → 누가 하느냐 논쟁
이벤트부터 시작: "주문이 접수됨, 결제가 승인됨, 음료가 준비됨…"
→ 일어난 사실이라 반박하기 어렵고, 시간순으로 줄을 세울 수 있다
과거형 사실은 각 부서가 자기 언어로 쓰더라도 시간축 위에서 충돌한다. “주문 완료됨” 스티커 두 장이 서로 다른 위치에 붙는 순간, 그 단어가 두 가지 뜻이라는 것이 모두에게 보인다. 이것이 인터뷰로는 안 되던 일이다.
스티커 문법
DDD 커뮤니티가 정리한 EventStorming Glossary & Cheat sheet의 색 규칙이다.
| 색 | 개념 | 설명 |
|---|---|---|
| 주황 | 도메인 이벤트 | 도메인 전문가에게 의미 있는 사건. 과거형 동사 |
| 형광 분홍(기울여 붙임) | 핫스팟 | 충돌·마찰·질문·이견·나중에 팔 문제 |
| 초록 | 기회(opportunity) | 핫스팟의 긍정 버전. 타임라인 정리 후 사용 |
| 작은 노랑 | 행위자 | 사람, 팀, 부서 |
| 넓은 분홍 | 시스템 | 배포 가능한 IT 시스템. 엑셀일 수도 있다 |
| 파랑 | 명령/행동 | 결정·행동·의도 |
| 라일락 | 정책 | “X 가 일어나면 Y 한다” 는 반응 |
| 초록 | 조회 모델 | 행위자가 결정에 필요한 정보 |
| 큰 노랑 | 제약 | 명령 수행 시 지켜야 할 규칙. 예전엔 애그리거트라 불렀다 |
색 자체는 중요하지 않다. 범례를 벽에 붙여 두고 모두가 같은 문법을 쓰는 것이 중요하다.
세 가지 수준
| 수준 | 목표 | 참여자 | 결과 |
|---|---|---|---|
| 빅 픽처 | 사업 전체의 건강 진단, 새 사업 모델 탐색 | 10~30명 이상, 여러 부서 | 전체 타임라인, 핫스팟, 떠오르는 바운디드 컨텍스트 |
| 프로세스 모델링 | 한 흐름을 명령·정책·조회 모델까지 상세화 | 해당 흐름 관계자 | 프로세스 규칙, 정책 |
| 소프트웨어 설계 | 이벤트·명령·제약으로 설계 단위 도출 | 개발자 + 도메인 전문가 | 제약(애그리거트) 경계, 이벤트 계약 |
빅 픽처 결과는 콘웨이 법칙에 맞춰 팀과 소프트웨어를 업무 흐름 중심으로 정렬하는 입력으로도 쓸 수 있다고 cheat sheet 는 설명한다.
빅 픽처 진행 순서
1. 혼돈의 탐색 각자 아는 이벤트를 조용히 쓴다. 서로 영향을 주지 않도록 토론 금지
│
2. 타임라인 강제 중복 제거, 순서 정리. 시끄러워지는 게 정상
│ "같은 말, 다른 뜻" 이 여기서 드러난다
3. 핫스팟 충돌·질문은 그 자리에서 해결하지 말고 분홍 스티커로 표시
│
4. 개념 추가 행위자, 시스템, 가치, 기회 … 필요할 때만 범례에 추가
│
5. 핵심 이벤트·경계 흐름을 바꾸는 중요한 이벤트(pivotal event)로 구간을 나눈다
→ 떠오르는 바운디드 컨텍스트 후보
진행자는 중립을 지키며, 긴 논쟁을 끊고 핫스팟으로 시각화한다. 완성도를 목표로 하지 않는다. Brandolini 는 모델이 거대해지므로 완성은 별 가치가 없고, 불완전함을 받아들여야 워크숍이 생산적이라고 썼다.
예제
커피 주문 앱 빅 픽처의 한 구간
시간 ─────────────────────────────────────────────────────────────▶
[고객] [고객] [결제 대행사] [바리스타] [바리스타] [고객]
주문이 결제가 결제가 제조가 음료가 음료를
접수됨 ──▶ 요청됨 ──▶ 승인됨 ──▶ 시작됨 ──▶ 준비됨 ──▶ 수령함
│ │
⚠ 승인 알림이 두 번 ⚠ 고객이 10분째 안 옴.
오면? (핫스팟) 폐기? 보관? 누가 결정? (핫스팟)
│
◇ 정책: 결제가 승인되면
제조를 시작한다
이 그림에서 요구사항 두 개가 나왔다. “승인 알림 중복 시 한 번만 반영한다”, “미수령 음료 처리 규칙을 정한다”. 둘 다 인터뷰에서는 아무도 말하지 않았던 것이다.
설계 수준으로 내려가기
소프트웨어 설계 단계에서 스티커는 코드 구조로 거의 그대로 옮겨진다. 과거형 이벤트는 불변 객체로, 큰 노랑(제약)은 규칙을 지키는 객체로, 라일락(정책)은 이벤트에 반응하는 함수로.
from dataclasses import dataclass
@dataclass(frozen=True) # 주황: 과거형 이름의 불변 이벤트
class 결제가_승인됨:
주문번호: str
금액: int
@dataclass(frozen=True)
class 제조가_시작됨:
주문번호: str
class 주문: # 큰 노랑: 규칙을 지키며 명령을 받아 이벤트를 낸다
def __init__(self, 번호):
self.번호, self.결제됨, self.이벤트 = 번호, False, []
def 결제_승인_반영(self, 금액): # 파랑: 명령
if self.결제됨: # 핫스팟에서 나온 규칙: 중복 승인 무시
return
self.결제됨 = True
self.이벤트.append(결제가_승인됨(self.번호, 금액))
def 결제되면_제조를_시작한다(e): # 라일락: "X 가 일어나면 Y 한다"
if isinstance(e, 결제가_승인됨):
return 제조가_시작됨(e.주문번호)
o = 주문("A-17")
o.결제_승인_반영(4500)
o.결제_승인_반영(4500) # 결제 대행사가 승인 알림을 두 번 보낸 경우
for e in o.이벤트:
print(e, "→", 결제되면_제조를_시작한다(e))
결제가_승인됨(주문번호='A-17', 금액=4500) → 제조가_시작됨(주문번호='A-17')
워크숍 언어와 코드 언어가 같다. 이것이 Martin Fowler 가 UbiquitousLanguage에서 설명하는, 개발자와 사용자가 공유하는 엄밀한 언어를 만드는 실제 경로다. 코드에서 이벤트를 다루는 패턴은 Fowler 의 Domain Event 를 참고한다.
준비 체크리스트
- 목표를 한 문장으로 초대장에 쓴다(“주문 취소가 왜 이렇게 오래 걸리는지 찾는다”).
- 지식을 가진 사람과 그 지식이 필요한 사람을 모두 부른다. 결정권자 한 명은 꼭.
- 6~8m 이상의 벽, 종이 롤, 색별 스티커, 사람 수만큼의 마커. 의자는 치운다.
- 범례를 눈에 띄게 붙인다.
- 원격이라면 온라인 화이트보드에 같은 범례를 미리 깐다.
흔한 오해와 함정
- 처음부터 설계 수준으로 간다. 빅 픽처 없이 애그리거트부터 찾으면 개발자끼리의 모델링 회의가 된다. 도메인 전문가가 빠진 이벤트 스토밍은 이름만 같다.
- 현재형·명령형 이벤트. “주문하기”, “결제 처리” 는 이벤트가 아니다. “주문이 접수됨” 처럼 과거형 사실로 쓰게 유도한다. 과거형이어야 시간순 배치와 반박이 가능하다.
- 핫스팟을 그 자리에서 해결한다. 한 쟁점에 30분을 쓰면 나머지 흐름을 못 본다. 표시하고 넘어간 뒤 따로 다룬다.
- 스티커 사진이 산출물이다. 결과는 결정과 질문 목록이다. 핫스팟마다 담당자와 후속 조치를 정하지 않으면 워크숍은 즐거운 행사로 끝난다.
- 바운디드 컨텍스트가 워크숍에서 확정된다. 빅 픽처가 주는 것은 “떠오르는” 경계 후보다. 설계 수준 탐색과 실제 코드로 검증해야 한다.
확인 문제
- Brandolini 가 “무제한 모델링 공간” 을 강조한 이유는?
- 이벤트를 과거형으로 쓰면 무엇이 좋은가?
- 핫스팟과 기회 스티커의 차이는?
- 빅 픽처와 소프트웨어 설계 수준 이벤트 스토밍의 참여자와 산출물은 어떻게 다른가?
- 예제의 “승인 알림이 두 번 오면?” 핫스팟이 어떤 요구사항과 코드 규칙으로 이어졌는가?
풀이
- 복잡한 문제를 제대로 분석하지 못하는 이유가 문제를 한눈에 볼 공간이 부족해서이기 때문이다. 문제는 화이트보드보다 크다.
- 일어난 사실이라 반박하거나 확인하기 쉽고, 시간순으로 배치할 수 있어 부서 간 용어 충돌과 순서 모순이 시간축 위에서 드러난다.
- 핫스팟은 충돌·질문·문제(부정적)를, 기회는 개선 가능성(긍정적)을 표시한다. 기회는 타임라인을 정리한 뒤 쓴다.
- 빅 픽처는 여러 부서 10~30명 이상이 사업 흐름 전체를 그려 핫스팟과 경계 후보를 얻는다. 설계 수준은 개발자와 도메인 전문가가 명령·이벤트·제약을 찾아 설계 단위를 정한다.
- “같은 주문의 결제 승인은 한 번만 반영한다” 는 요구가 됐고, 코드에서는
주문객체가 이미 결제됐으면 승인 명령을 무시하는 규칙으로 구현됐다.
더 읽을거리 (References)
- Alberto Brandolini, Introducing Event Storming, 2013
- Alberto Brandolini, Introducing EventStorming, Leanpub / eventstorming.com
- DDD Crew, EventStorming Glossary & Cheat sheet
- Martin Fowler, Domain Event, UbiquitousLanguage, BoundedContext
- Eric Evans, Domain-Driven Design Reference
- CS300: 도메인 주도 설계