Перейти к содержимому
Программа DDDDDD.2 Стратегическое проектирование

Event Storming: моделируем через события

Как Альберто Брандолини предлагает моделировать предметную область вместе с экспертами: доменные события на «бесконечной стене», три формата сессии, нотация стикеров, проведение офлайн и онлайн и ошибки фасилитатора. Разбираем сессию «записаться на поток и оплатить», закрываем открытые вопросы глоссария и переходим от стены к контекстам и агрегатам.

УРОКddd/ddd-2-strategic/03-event-storming.mdx2 ч 10 минУрок 3 из 3
После урока вы сможете
  • Объяснить, что такое Event Storming, чем различаются форматы Big Picture, Process Level и Design Level и когда какой выбрать
  • Читать и писать стену в нотации стикеров — событие, команда, актор, политика, внешняя система, модель чтения, агрегат, горячая точка
  • Подготовить и провести сессию с экспертами офлайн или онлайн и избежать типичных ошибок фасилитатора
  • Переходить от стены событий к границам контекстов и кандидатам в агрегаты на примере процесса «записаться на поток и оплатить»

Команда онлайн-школы два месяца писала требования к записи и оплате. Получилось тридцать страниц, эксперты их прочитали и согласовали. После запуска первый же звонок в поддержку: студент оплатил счёт через пять минут после того, как его запись автоматически отменилась. Деньги списаны, места нет, что делать — не знает никто. Вопрос не задали ни на одной из тридцати страниц, потому что текст читают по разделам, а такие случаи живут на стыке двух разделов — «оплата» и «отмена».

Такие стыки хорошо видны, если выложить процесс по времени: вот событие, вот следующее, а что, если между ними случится третье? На этом и построен метод Event StormingEvent Storming («штурм событий»)EN EventStormingМетод совместного моделирования Альберто Брандолини: эксперты и разработчики выкладывают доменные события на длинной ленте вдоль времени, а потом добавляют команды, акторов, политики, системы и горячие точки. Форматы: Big Picture, Process Level, Design Level. («штурм событий»), который придумал Альберто Брандолини. Эксперты и разработчики стоят у длинной бумажной ленты и выкладывают на неё факты предметной области, а пробелы и противоречия всплывают сами. В уроке DDD.1.2 в глоссарии школы остались три открытых вопроса — в этом уроке мы закроем их на стене. А в уроке DDD.1.3 было обещано, что события на стене сами соберутся в группы, — посмотрим, как это происходит и как из стикеров вырастают контексты и агрегаты.

Event Storming — метод совместного моделирования. Его основа простая: «бесконечная» стена (рулон бумаги на несколько метров), время идёт слева направо, а на стену клеят оранжевые стикеры — доменные событиядоменное событиеEN domain eventЗначимый для экспертов факт, который уже произошёл, в прошедшем времени: «Студент записан», «Платёж получен». В Event Storming — оранжевый стикер, в коде — неизменяемый объект (урок DDD.3.3).. Шпаргалка DDD Crew определяет событие так: факт, значимый для экспертов предметной области в исследуемой области, глагол в прошедшем времени. Параллельные потоки событий располагают друг под другом.

Почему именно события, а не, скажем, сущности или экраны?

  • Их понимают все. Бизнес рассказывает истории фактами: «студент записался, через двое суток не оплатил, место отдали следующему». Для этого не нужно знать UML или базы данных.
  • Прошедшее время дисциплинирует. «Платёж получен» — это либо случилось, либо нет. Расплывчатая «оплата» на оранжевый стикер не помещается: её приходится уточнять — счёт выставлен? платёж получен? деньги возвращены?
  • Порядок вскрывает пробелы. Когда события стоят в ряд, видно, где между ними пусто, где два отдела рассказывают одну историю по-разному и где никто не знает, что происходит дальше.

Сам Брандолини, как пересказывает шпаргалка DDD Crew, сравнивает Event Storming с пиццей: рулон бумаги и события — это тесто, а остальные ингредиенты кладут по вкусу и по задаче. Ингредиенты — это стикеры других цветов и форматы сессии.

Big PictureProcess LevelDesign Level
Цельувидеть бизнес целиком: здоровье направления, проблемы, возможности, границы контекстовразобрать один процесс: узкие места, правила, кто что решаетспроектировать код внутри одного контекста
Кто в комнатемного людей из разных отделов: 10–30 и большеэксперты процесса и разработчикиразработчики и эксперты одного контекста
Масштабвесь бизнес, от «курс опубликован» до «сертификат выдан»один процесс: «записаться на поток и оплатить»один агрегат или несколько
Стикерысобытия, горячие точки, акторы, системы, возможности, ценностьвся «грамматика»: команды, политики, модели чтенияплюс агрегаты и их правила
Результатобщая картина, главная проблема, кандидаты в контекстысогласованный процесс, закрытые вопросыкандидаты в агрегаты, их команды, события и инварианты

В шпаргалке DDD Crew второй и третий форматы называются Process Modelling и Software Design; в русских и английских текстах встречаются и названия Process Level и Design Level. Форматы не обязательно проводить все и подряд: часто достаточно одного Big Picture на старте проекта и нескольких Process Level по самым болезненным процессам.

Цвета ниже — «официальные» по шпаргалке DDD Crew. Команды нередко заменяют их тем, что есть под рукой; важно не это, а легенда на виду: лист с образцом каждого стикера висит на стене всю сессию.

СтикерЦветЧто означаетПример в онлайн-школе
Доменное событиеоранжевыйфакт в прошедшем времени«Студент записан», «Платёж получен»
Горячая точкаярко-розовый, повёрнут ромбомвопрос, конфликт, противоречие в языке, боль, «обсудим позже»«Платёж пришёл после отмены — что делаем?»
Актормаленький жёлтыйчеловек, роль или отдел, который действует«Студент», «Менеджер набора»
Системаширокий розовыйвнешняя или своя система, участвующая в процессе«Платёжная система», «Сервис рассылок»
Командасинийнамерение, решение, действие«Записаться на поток», «Выставить счёт»
Политикасиреневыйреакция «когда X — делаем Y»«Когда платёж получен — подтвердить запись»
Модель чтениязелёныйинформация, которая нужна для решения«Свободные места на потоках»
Агрегат (ограничение)большой жёлтыйто, что принимает решение и защищает правила«Поток»
Возможностьзелёныйидея улучшения (в Big Picture, в пару к горячим точкам)«Предлагать место из листа ожидания автоматически»

Пояснения к самым важным стикерам:

  • Горячая точкагорячая точкаEN hotspotСтикер Event Storming (ярко-розовый, повёрнутый ромбом) для вопросов, конфликтов, противоречий в языке, болевых мест и всего, что решили обсудить позже. Фасилитатор ставит его вместо затянувшегося спора. — главный инструмент фасилитатора. Шпаргалка DDD Crew перечисляет, что она ловит: противоречия в языке, трения, вопросы, несогласие, возражения, проблемы и всё, что решили обсудить позже. Её ставят на месте спора и идут дальше.
  • Командакоманда (в Event Storming)EN commandНамерение или решение что-то сделать: «Записаться на поток». Синий стикер. Её отдаёт актор или политика, итог — событие или отказ. — то, что кто-то решил сделать. В разговоре с бизнесом DDD Crew советует говорить «действие»: это слово понятнее. Итог команды — событие или отказ.
  • Политикаполитика (в Event Storming)EN policyРеакция «когда случилось X — делаем Y» между событием и командой: «Когда платёж получен — подтвердить запись». Сиреневый стикер. Бывает автоматической и ручной. — правило-реакция между событием и следующей командой. Бывает автоматической («через 48 часов без платежа отменить запись») и ручной («когда пришла жалоба, менеджер связывается со студентом»). Шпаргалка замечает, что за политикой всегда скрывается больше, чем кажется вначале.
  • Модель чтениямодель чтенияEN read model, query modelДанные, которые нужны человеку или программе, чтобы принять решение: «свободные места на потоках». В Event Storming — зелёный стикер; в CQRS — отдельная модель для чтения (урок DDD.4.1). — данные, на которые смотрит актор, прежде чем отдать команду: студент смотрит на свободные места, прежде чем записаться.
  • Большой жёлтый стикер раньше называли агрегатом. Шпаргалка DDD Crew теперь называет его «ограничением» (constraint) — правилом, которое нужно соблюсти, чтобы выполнить команду, — а слово «агрегат» считает устаревшим для Event Storming: с бизнесом его лучше не произносить. Разработчики при этом по-прежнему видят в нём кандидата в агрегатагрегатEN aggregateКластер сущностей и объектов-значений, который меняется только целиком через корень и после каждой операции соблюдает свои инварианты. Граница агрегата — граница транзакции: одна транзакция меняет один агрегат. В онлайн-школе — поток с записями и листом ожидания. — подробно о них в уроке DDD.3.2.

Стикеры складываются в «грамматику», которую часто называют картинкой, объясняющей (почти) всё:

flowchart LR
R[/"модель чтения"/] --> A(["актор"])
A --> C["команда"]
C --> G[["агрегат или<br/>ограничение"]]
C --> S[("внешняя<br/>система")]
G --> E("событие")
S --> E
E --> P{{"политика"}}
P --> C2["следующая<br/>команда"]
Грамматика Process Level: актор смотрит на модель чтения и отдаёт команду; решает агрегат или внешняя система; получается событие; политика реагирует следующей командой

Представим первую сессию в школе. В комнате менеджер набора, методист, бухгалтер, маркетолог, старший сотрудник поддержки, руководитель школы и четверо разработчиков. Шпаргалка DDD Crew описывает ход сессии так.

  1. Хаотичное исследование. Каждый молча пишет события, которые знает, и клеит их туда, где, как ему кажется, они происходят. Молчание важно: участники не должны влиять друг на друга. Фасилитатор не торопит и не отвечает на вопросы — это самая важная часть сессии.
  2. Выстраиваем хронологию. Теперь можно говорить. Участники упорядочивают события, обсуждают и убирают дубликаты. Осторожно с дубликатами: два одинаковых стикера могут оказаться одним словом для разных понятий. Так на стене школы рядом оказались «Оплата прошла» маркетолога и «Счёт оплачен» бухгалтера — и выяснилось, что маркетолог имел в виду момент, когда студент нажал кнопку, а деньги приходят позже. Структуру — дорожки, вертикальные линии — добавляют аккуратно: слишком ранний порядок прячет ценные находки.
  3. Горячие точки. Конфликты при выстраивании хронологии — это хорошо: из них растёт понимание. Фасилитатор отмечает их розовыми стикерами, не давая спорам затянуться.
  4. Новые понятия — по мере надобности. Когда участникам понадобятся акторы, системы или возможности, их добавляют в легенду и объясняют.

Дальше обычно ищут ключевые событияключевое событиеEN pivotal eventОдно из немногих самых важных событий процесса, после которого многое меняется и которое интересно многим участникам. Ключевые события делят стену Event Storming на части и подсказывают границы контекстов. — немногие самые важные факты, после которых многое меняется и которыми интересуются многие участники. Для интернет-магазина шпаргалка приводит пример: «товар добавлен в каталог», «заказ оформлен», «заказ отправлен», «платёж получен», «заказ доставлен». Удобный приём проверки — рассказ вдоль стены: один участник ведёт историю слева направо, остальные останавливают его на каждом пробеле. Полезно пройти стену и в обратную сторону, от последнего события к первому, задавая вопрос «что должно было случиться перед этим?». Завершается Big Picture выбором главной проблемы: участники голосуют за горячие точки, и следующая сессия посвящается победителю.

У школы стена после выстраивания хронологии выглядит примерно так:

flowchart LR
subgraph K["Каталог"]
  e1("Курс опубликован") --> e2("Поток открыт<br/>для записи")
end
subgraph N["Набор"]
  e3("Студент записан") --> e6("Запись подтверждена")
  e3 --> e11("Запись отменена") --> e12("Место освободилось")
end
subgraph P["Оплата"]
  e4("Счёт выставлен") --> e5("Платёж получен")
end
subgraph L["Обучение"]
  e7("Поток стартовал") --> e8("Задание сдано") --> e9("Курс пройден")
end
subgraph C["Сертификация"]
  e10("Сертификат выдан")
end
e2 ==> e3
e3 --> e4
e5 --> e6
e6 ==> e7
e9 ==> e10
Big Picture онлайн-школы: события сгруппированы по возникающим контекстам; толстые стрелки — переходы через ключевые события

Посмотрите, как на стене проявились контексты. Ключевые события — «Поток открыт для записи», «Запись подтверждена», «Поток стартовал», «Курс пройден», «Сертификат выдан» — делят ленту на участки. Возле каждого участка стоят свои люди: у записи — менеджер набора, у счетов — бухгалтер, у заданий — методист. Меняется язык: слева говорят «поток» и «место», в середине — «счёт» и «платёж», справа — «задание» и «прогресс». Шпаргалка DDD Crew называет такие группы возникающими ограниченными контекстами (emerging bounded contexts): это первые подсказки, где проектировать границы. Для школы они подтвердили шесть контекстов из урока DDD.2.1 — а Уведомления нашлись по-другому: их событие «Письмо отправлено» висело почти под каждым участком, и его вынесли в отдельную дорожку.

Голосование на Big Picture выбрало главную боль — «запись и оплата». На вторую сессию пришли менеджер набора, бухгалтер, сотрудник поддержки, двое разработчиков и фасилитатор. Задача — разобрать процесс полной грамматикой и закрыть вопросы.

Сессия идёт по тем же правилам, но теперь к каждому событию спрашивают: что его вызвало? (команда — от кого? или внешняя система?) и что происходит после? (какая политика срабатывает?). Вот что получилось на основной ветке и двух болезненных ответвлениях:

flowchart TB
A1(["Студент"]) --> C1["Записаться на поток"]
R1[/"Свободные места на потоках"/] --> A1
C1 --> G1[["Поток"]] --> E1("Студент записан")
E1 --> P1{{"Когда студент записан —<br/>выставить счёт"}} --> C2["Выставить счёт"] --> G2[["Счёт"]] --> E2("Счёт выставлен")
E2 --> A2(["Студент"]) --> C3["Оплатить счёт"] --> S1[("Платёжная система")] --> E3("Платёж получен")
E3 --> P2{{"Когда платёж получен —<br/>подтвердить запись"}} --> C4["Подтвердить запись"] --> G3[["Поток"]] --> E4("Запись подтверждена")
E1 --> T1{{"Через 48 часов без платежа —<br/>отменить запись"}} --> C5["Отменить неоплаченную запись"] --> G4[["Поток"]] --> E5("Запись отменена<br/>Место освободилось")
E3 --> P3{{"Когда платёж получен,<br/>а запись отменена — вернуть платёж"}} --> C6["Вернуть платёж"] --> G5[["Счёт"]] --> E6("Платёж возвращён")
H1>"Горячая точка: платёж пришёл<br/>после отмены — что делаем?"] -.-> P3
Process Level «записаться на поток и оплатить». Формы: капсула — актор, параллелограмм — модель чтения, прямоугольник — команда, двойная рамка — агрегат, цилиндр — внешняя система, скруглённый — событие, шестиугольник — политика, флажок — горячая точка

Самое ценное в сессии — горячие точки. Три из них — открытые вопросы глоссария из урока DDD.1.2; эксперты школы закрыли их прямо у стены. Решения ниже — условия учебного примера, как и числа 48 часов, 7 суток и 24 часа.

Горячая точкаРешение экспертовЧто появилось на стене и в глоссарии
Можно ли снова записаться на поток после отмены?Да, если запись на поток ещё открыта и есть свободное место. Правило «не дважды» касается действующих записей — «ожидает оплаты» и «подтверждена». Отменённая запись остаётся в истории, повторная запись — новая записьуточнённое правило 2 Набора: у студента не может быть двух действующих записей на один поток
Платёж пришёл после автоматической отмены — что делать?Вернуть платёж полностью. Запись не восстанавливается: место могло уже уйти первому в листе ожидания. Если места есть, студент может записаться снова по общим правиламполитика «Когда платёж получен, а запись отменена — вернуть платёж»; новое событие ПлатёжВозвращён (PaymentRefunded)
Что подтверждает студент из листа ожидания за 24 часа?Согласие занять предложенное место. Пока идут 24 часа, место закреплено за ним. После подтверждения появляется обычная запись «ожидает оплаты» с теми же 48 часами на оплату. Нет ответа за 24 часа — предложение истекает, место предлагается следующемукоманда «Принять предложение»; новые события МестоПредложено (SeatOffered) и ПредложениеИстекло (SeatOfferExpired)

Заодно решился вопрос из того же урока, нужны ли события для действий «предложить место» и «вернуть деньги». Нужны: на «Место предложено» реагируют Уведомления (письмо студенту) и таймер на 24 часа, на «Платёж возвращён» — Уведомления и поддержка. Ещё одно новое событие — «Счёт выставлен» (InvoiceIssued): его ждёт письмо со ссылкой на оплату.

Не всё закрывается сразу. Две горячие точки остались открытыми и ушли в канву Набора: «Поток перенесли на другую дату — что с записями и правилом 7 суток?» и «Возможен ли частичный возврат?». Это нормальный итог: горячая точка без ответа — не провал сессии, а честно записанное незнание.

У стены разгорелся спор: «Студент отменил запись» и «Неоплаченная запись отменена по таймеру» — одно событие или два? Менеджер набора сказала, что для места разницы нет: оно освобождается в обоих случаях. Бухгалтер возразила: в первом случае может быть положен возврат по правилу 7 суток, во втором денег не было вовсе. Решили оставить одно событие ЗаписьОтменена, но с причиной отмены — студент или истёк срок оплаты, — а правило возврата применять только к первой причине. Такие споры о словах — та самая работа над единым языком из урока DDD.1.2, только у стены она идёт в разы быстрее.

На Design Level команда приближает один участок — всё, что крутится вокруг большого жёлтого стикера «Поток». На нём записывают правила, которые он защищает, а вокруг собирают его команды и события. Получается почти готовый эскиз агрегата:

Стикер на стенеКандидат в коде (Набор)Событие
команда «Записаться на поток»cohort.enroll(student_id, now)СтудентЗаписан (StudentEnrolled)
политика «Когда платёж получен — подтвердить запись» → командаcohort.confirm(enrollment_id, now)ЗаписьПодтверждена (EnrollmentConfirmed)
команда «Отменить запись» (студент или таймер 48 часов)cohort.cancel(enrollment_id, now, reason)ЗаписьОтменена (EnrollmentCancelled), МестоОсвободилось (SeatReleased)
политика «Когда место освободилось — предложить место» → командаcohort.offer(now)МестоПредложено (SeatOffered)
команда «Принять предложение»cohort.accept_offer(student_id, now)СтудентЗаписан (StudentEnrolled)
правила на жёлтом стикереинварианты агрегатаместа, «не дважды», закрытие при старте, 48 и 24 часа

Имена в среднем столбце — черновик, а не окончательный дизайн: как сделать агрегат, который нельзя привести в неверное состояние, разберём в уроке DDD.3.2. Но направление уже видно: слова стены становятся именами в коде, события — классами событий, правила — проверками, которые тесты будут ловить по одному. Остальные стикеры тоже находят своё место:

СтикерВо что превращаетсяГде в программе
событиекласс доменного событияурок DDD.3.3
командаметод агрегата или сервиса приложенияуроки DDD.3.2 и DDD.3.3
агрегат (ограничение)агрегат с инвариантамиурок DDD.3.2
политикаобработчик события, менеджер процессаурок DDD.4.2
модель чтениязапрос или проекцияурок DDD.4.1
внешняя системаадаптер и предохранительный слойурок DDD.2.2
горячая точкаоткрытый вопрос в глоссарии и канве; позже — тест на принятое решениеуроки DDD.1.2 и DDD.2.1
  • Кого звать. По шпаргалке DDD Crew — всех, кто приносит знания, и всех, кому эти знания нужны: экспертов и инженеров. Процесс DDD Crew добавляет людей продукта, тех, кто понимает нужды клиентов, и по возможности настоящих пользователей. Без экспертов получится Event Storming базы данных, а не бизнеса.
  • Приглашение. Напишите цель встречи и в двух фразах — что такое Event Storming. Автор шпаргалки рассылает участникам заранее доклад Брандолини «50,000 Orange Stickies Later».
  • Материалы. Рулон бумаги, много оранжевых стикеров и понемногу остальных цветов, одинаковые толстые маркеры (тонкую ручку не прочитать с двух метров), скотч. Материалов должно хватить с запасом: ничто так не сбивает сессию, как кончившиеся стикеры.
  • Комната. Поверхность для моделирования около 6–8 метров, стол для материалов, легенда на виду и никаких стульев у стены: люди, которые стоят, двигаются и спорят, а сидящие смотрят в телефоны. Открывающиеся окна и немного еды — не мелочь, а условие трёхчасовой работы.
  • Фасилитатор. Отдельный человек, нейтральный: он не продвигает своё решение, а помогает группе. Приходит первым и уходит последним.

Шпаргалка советует начинать с check-in: каждый коротко говорит, как он и чего ждёт от встречи, — не о работе. Затем договорённости, записанные на флипчарте. Автор шпаргалки берёт три из практики Deep Democracy: каждый прав, ни у кого нет монополии на истину; мы начинаем разговор, чтобы углубить отношения; мы готовы учиться вместе. Потом — короткое введение: что такое доменное событие, легенда, пример. Заканчивают check-out: участники по кругу говорят, что вынесли из встречи. Сразу после сессии стену фотографируют по участкам, а в течение пары дней переносят в цифровой вид — иначе через неделю от неё останется рулон, который никто не развернёт.

Event Storming хорошо переносится на виртуальные доски — Miro и аналоги; есть и открытый инструмент DDD Toolbox с готовым шаблоном. Онлайн свои правила (это практические советы, а не догма):

  • Подготовьте доску заранее: длинная горизонтальная область, палитра стикеров нужных цветов, легенда, отдельная «парковка» для горячих точек. Каждый участник должен до встречи один раз зайти на доску и создать стикер.
  • Короче и чаще. Три часа у экрана тяжелее трёх часов у стены. Лучше две-три сессии по полтора-два часа с перерывами.
  • Хаотичное исследование — по таймеру и молча, с включёнными камерами. Онлайн легче отвлечься, и фасилитатору труднее заметить, кто выпал.
  • Помощник фасилитатора следит за доской: выравнивает стикеры, ловит дубликаты, отвечает на вопросы по инструменту.
  • Плюс онлайна — стена уже цифровая, её не нужно переносить. Минус — меньше энергии и спонтанных разговоров у стены; их приходится провоцировать вопросами.
ОшибкаЧто получаетсяКак правильно
позволить спору идти сорок минутполовина участников выключается, стена стоитпоставить горячую точку и двигаться дальше
начать Big Picture с команд и агрегатовэксперты теряются в чужих терминах, а разработчики рисуют схему базысначала только события; остальные стикеры — когда понадобятся
позволить говорить во время хаотичного исследованияпервый уверенный голос задаёт всю картину15–20 минут тишины, каждый пишет сам
самому писать стикеры или занимать сторону в спорегруппа ждёт решения от фасилитаторафасилитатор нейтрален, стикеры пишут участники
звать только разработчиковстена о таблицах и экранах, а не о бизнесебез экспертов сессию не проводить
пропускать стикеры «Оплата», «Сохранить в БД»на стене команды, существительные и техника вместо событийвежливо просить переписать: что случилось, в прошедшем времени, словами бизнеса
рано наводить порядокдубликаты убраны без обсуждения, хотя за одним словом были разные понятиясначала обсудить каждый дубликат, структуру добавлять постепенно
хотеть всё за одну встречусессия на восемь часов, к вечеру никто ничего не решаетBig Picture отдельно, процессы — отдельными сессиями
забыть про итогичерез неделю никто не помнит решенийсфотографировать, оцифровать, внести решения в глоссарий и канву

После сессии стену оцифровывают. Удобно хранить процесс как строки «грамматики» — так его можно и прочитать, и проверить программой. Скрипт ниже делает три вещи, которые полезно делать после каждой сессии: проверяет черновые стикеры, собирает команды вокруг тех, кто принимает решение, — кандидатов в агрегаты, — и ищет дыры: политики без события и события, на которые никто не реагирует.

# Стена Process Level «записаться на поток и оплатить», перенесённая в код после сессии.
# Строка = кто запускает (актор, таймер или политика «Когда …») → команда → кто решает → события.
FLOW = [
("Студент", "Записаться на поток", "Поток", ["Студент записан"]),
("Когда студент записан", "Выставить счёт", "Счёт", ["Счёт выставлен"]),
("Студент", "Оплатить счёт", "Платёжная система", ["Платёж получен"]),
("Когда платёж получен", "Подтвердить запись", "Поток", ["Запись подтверждена"]),
("Когда запись подтверждена", "Открыть доступ к занятиям", "Обучение", ["Доступ к занятиям открыт"]),
("Через 48 часов без платежа", "Отменить неоплаченную запись", "Поток", ["Запись отменена", "Место освободилось"]),
("Когда место освободилось", "Предложить место", "Поток", ["Место предложено"]),
("Студент из листа ожидания", "Принять предложение", "Поток", ["Студент записан"]),
("Через 24 часа без ответа", "Отозвать предложение", "Поток", ["Предложение истекло", "Место освободилось"]),
("Когда платёж получен, а запись отменена", "Вернуть платёж", "Счёт", ["Платёж возвращён"]),
]
OWNER = {"Поток": "Набор", "Счёт": "Оплата", "Платёжная система": "внешняя система", "Обучение": "другой контекст"}
# Черновые стикеры из хаотичного исследования — до чистки
DRAFT = ["Студент записан", "Оплата", "Запись сохранена в таблицу orders", "Отменить запись", "Место освободилось"]
PAST_ENDINGS = ("ан", "ен", "ён", "на", "но", "ло", "лось", "лся", "лась", "ыт") # грубая эвристика
TECH_WORDS = ("таблиц", "orders", "бд", "кнопк", "api")
def check_sticker(text):
"""Что не так с оранжевым стикером: событие — факт предметной области в прошедшем времени."""
if any(word in text.lower() for word in TECH_WORDS):
return "технический факт, а не событие предметной области"
if not text.split()[-1].endswith(PAST_ENDINGS):
return "не прошедшее время: это команда, процесс или существительное"
return None
print("Черновые стикеры:")
for text in DRAFT:
print(f" {text:35} {check_sticker(text) or 'ок'}")
print("\nПроцесс по строкам грамматики:")
for who, command, decider, produced in FLOW:
print(f" {who:41} → {command:30} → {decider:17} → {', '.join(produced)}")
print("\nКандидаты в агрегаты и их контексты:")
for decider in dict.fromkeys(d for _, _, d, _ in FLOW):
commands = [c for _, c, d, _ in FLOW if d == decider]
print(f" {decider} ({OWNER[decider]}): {'; '.join(commands)}")
events = {e for *_, produced in FLOW for e in produced}
triggers = {who.removeprefix("Когда ").split(",")[0].capitalize() for who, *_ in FLOW if who.startswith("Когда ")}
print("\nПолитика ждёт события, которого нет на стене:", sorted(triggers - events) or "нет")
print("На событие никто не реагирует:", ", ".join(sorted(events - triggers)))
Черновые стикеры:
Студент записан ок
Оплата не прошедшее время: это команда, процесс или существительное
Запись сохранена в таблицу orders технический факт, а не событие предметной области
Отменить запись не прошедшее время: это команда, процесс или существительное
Место освободилось ок
Процесс по строкам грамматики:
Студент → Записаться на поток → Поток → Студент записан
Когда студент записан → Выставить счёт → Счёт → Счёт выставлен
Студент → Оплатить счёт → Платёжная система → Платёж получен
Когда платёж получен → Подтвердить запись → Поток → Запись подтверждена
Когда запись подтверждена → Открыть доступ к занятиям → Обучение → Доступ к занятиям открыт
Через 48 часов без платежа → Отменить неоплаченную запись → Поток → Запись отменена, Место освободилось
Когда место освободилось → Предложить место → Поток → Место предложено
Студент из листа ожидания → Принять предложение → Поток → Студент записан
Через 24 часа без ответа → Отозвать предложение → Поток → Предложение истекло, Место освободилось
Когда платёж получен, а запись отменена → Вернуть платёж → Счёт → Платёж возвращён
Кандидаты в агрегаты и их контексты:
Поток (Набор): Записаться на поток; Подтвердить запись; Отменить неоплаченную запись; Предложить место; Принять предложение; Отозвать предложение
Счёт (Оплата): Выставить счёт; Вернуть платёж
Платёжная система (внешняя система): Оплатить счёт
Обучение (другой контекст): Открыть доступ к занятиям
Политика ждёт события, которого нет на стене: нет
На событие никто не реагирует: Доступ к занятиям открыт, Запись отменена, Место предложено, Платёж возвращён, Предложение истекло, Счёт выставлен

Как читать результат:

  • Черновые стикеры. «Оплата» — то самое двусмысленное слово, которого нет в глоссарии; у стены его превращают в «Счёт выставлен» или «Платёж получен». «Запись сохранена в таблицу orders» — факт о базе данных, а не о бизнесе. «Отменить запись» — команда, ей место на синем стикере. Проверка окончаний — грубая эвристика, а не разбор русского языка: она ловит частые ошибки, но последнее слово всегда за людьми.
  • Кандидаты в агрегаты. Вокруг «Потока» собрались шесть команд и все правила Набора — это кандидат в главный агрегат школы. «Счёт» — агрегат Оплаты. Платёжная система — внешняя, с ней работают через предохранительный слой из прошлого урока.
  • События без реакции. Три из шести — законные концы веток: «Доступ к занятиям открыт», «Платёж возвращён», «Предложение истекло» (место после него освобождается отдельным событием). А вот «Счёт выставлен» и «Место предложено» — сигналы: студенту никто не сообщает ни о счёте, ни о предложенном месте. На стене не хватает Уведомлений — нужны политики «Когда счёт выставлен — отправить ссылку на оплату» и «Когда место предложено — написать студенту». «Запись отменена» тоже требует вопроса: если отменил студент за 7 суток и более, кто запускает возврат? Это готовые вопросы к следующей сессии.

Попробуйте дописать в FLOW строки для Уведомлений и возврата при отмене студентом и запустите скрипт снова — список событий без реакции должен сократиться до законных концов.

Упражнение: мини-сессия «отмена записи студентом» (30–40 минут)

Заголовок раздела «Упражнение: мини-сессия «отмена записи студентом» (30–40 минут)»

Проведите Event Storming уровня Process Level для процесса «студент отменяет запись» — с коллегой или в одиночку, проговаривая вслух. Если есть возможность, позовите человека, который работал в поддержке любого сервиса: он знает, как на самом деле отменяют.

  1. Выложите события, начиная с «Запись отменена», и все её последствия. Только оранжевые стикеры, 10 минут.
  2. Добавьте команды, акторов, политики и внешние системы.
  3. Отметьте горячие точки. Подсказка: правило возврата зависит от времени до старта; запись может быть в разных статусах; освободившееся место кому-то предлагают.
  4. Сверьтесь с разбором.
Возможный разбор

События: «Запись отменена» (причина — студент), «Место освободилось», «Возврат назначен» или сразу команда «Вернуть платёж» в Оплату, «Платёж возвращён», «Место предложено». Политики: «Когда запись отменена студентом за 7 суток и более до старта — вернуть платёж»; «Когда место освободилось — предложить первому в листе ожидания»; «Когда платёж возвращён — написать студенту». Внешние системы: платёжная система, сервис рассылок.

Горячие точки, которые обычно всплывают: отмена записи в статусе «ожидает оплаты» — возвращать нечего, но место освобождается; отмена ровно за 7 суток — решено в уроке DDD.1.2: полный возврат (сравнение «больше или равно»); что, если возврат в платёжной системе не прошёл; можно ли отменить запись после старта потока. Последний вопрос — новый открытый вопрос для экспертов: запишите его в канву Набора.

Проверь себя6 вопросов
1 Какой из стикеров — правильно названное доменное событие?
2 Школа впервые проектирует систему целиком и хочет понять, на какие контексты её делить и где главная боль. Какой формат выбрать?
3 Стикер «Когда платёж получен — подтвердить запись». Что это?
4 Какие действия фасилитатора — ошибки? Выберите все верные варианты.Можно выбрать несколько ответов
5 Что эксперты учебной школы решили делать с платежом, который пришёл после автоматической отмены записи?
6 Какого цвета по шпаргалке DDD Crew стикер доменного события? (одно слово)
  • Event Storming Альберто Брандолини — совместное моделирование на «бесконечной стене»: доменные события в прошедшем времени слева направо, а вокруг них команды, акторы, политики, системы, модели чтения, агрегаты и горячие точки. Порядок по времени вскрывает пробелы, которые прячутся в тексте требований.
  • Три формата: Big Picture — весь бизнес и возникающие контексты; Process Level — один процесс полной грамматикой; Design Level — агрегаты, их правила и события внутри контекста.
  • Сессию готовят: нужные люди (эксперты обязательно), материалы, длинная стена без стульев, нейтральный фасилитатор, договорённости. Онлайн — подготовленная доска, короткие сессии и помощник. Главная ошибка фасилитатора — давать спорам съедать время вместо горячих точек.
  • На сессии «записаться на поток и оплатить» закрыты три открытых вопроса глоссария: повторная запись после отмены возможна; платёж после автоматической отмены возвращается; студент из листа ожидания подтверждает согласие занять место и получает запись «ожидает оплаты». Появились события «Счёт выставлен», «Место предложено», «Предложение истекло», «Платёж возвращён».
  • Стена переходит в архитектуру: ключевые события, дорожки и смена языка дают границы контекстов, а команды и правила вокруг жёлтого стикера «Поток» — кандидата в агрегат, с которого начнётся тактическое проектирование.

Дальше: урок DDD.3.1 — сущности и объекты-значения. Начинаем модуль тактического проектирования: превратим Money и Period из стикеров и глоссария в неизменяемые объекты с правилами и узнаем, чем запись на поток отличается от суммы в копейках.