Event storming без воркшопов: как работать с тикетами и логами
Узнайте, как проводить event storming без воркшопов — вытягивая доменные события из тикетов и логов и группируя их в модули за один час.

Почему команды избегают воркшопов
Большинство команд не ненавидят картирование событий само по себе. Они ненавидят классический формат воркшопа.
Положите шестерых человек в комнату со стеной стикеров — и работа часто уходит в сторону от продукта. Кто‑то спорит о точном названии события. Кто‑то уходит в архитектуру. Через двадцать минут никто толком не договорился, что же произошло с реальным пользователем.
Такое ускользание происходит потому, что воркшопы чаще вознаграждают быстрые рассуждения, а не ясные доказательства. Человек с самой сильной позицией может потянуть всю стену в одном направлении, даже если он знает только часть процесса. Руководитель поддержки может знать реальный путь возврата по десяткам тикетов, но более громкий инженер или основатель всё равно может доминировать в сессии.
Команды также застревают на словах слишком рано. Они спорят, называть ли событие «запрошен возврат», «создан запрос на возврат» или «открыт возврат», ещё не выложив порядок действий. Это кажется мелочью, но тратит время и создаёт фальшивые разногласия. Обычно люди спорят о ярлыках, потому что они ещё не видят поток.
Есть и другая причина избегать воркшопов. Чистая версия процесса редко совпадает с реальной работой. Стикеры склонны показывать «счастливый» путь. Тикеты и логи показывают более грязную правду: дублирующиеся действия, повторы, отсутствующие данные, ручные правки и моменты, когда пользователи запутались настолько, что написали в поддержку.
Простой пример делает проблему очевидной. На воркшопе команда может сказать: «Клиент запросил возврат, система оформила возврат, клиент получил подтверждение». В тикетах и логах та же история часто выглядит иначе: платежный провайдер завис, поддержка открывает дело заново, клиент отправляет запрос дважды, бухгалтерия проверяет один заказ вручную.
Именно поэтому более лёгкий подход лучше для скептичных команд. Начинайте с того, что уже произошло, а не с чьей‑то памяти, статуса или самого громкого выступающего. Когда исходный материал берут из тикетов и логов, разговор становится короче, острее и гораздо сложнее захватиться кем‑то одним.
Что собрать перед началом
Начните с доказательств, а не с мнений. Если вы хотите полезную карту за один час, вытягивайте следы работы, которые уже пошли не так, застряли или повторялись.
Недавние тикеты — первое место для поиска. Ищите повторяющиеся случаи, а не редкие уникальные инциденты. Пять тикетов про возврат, который завис, расскажут вам больше, чем один странный сбой. Сохраняйте оригинальную формулировку пользователей и поддержки. Эти фразы часто указывают на моменты, которые должны быть на карте: «запрошен возврат», «платёж захвачен», «возврат одобрен», «возврат не выполнен», «клиент уведомлён».
Логи помогают, когда тикеты слишком расплывчаты. Вытяните небольшой временной интервал вокруг неудачных или медленных действий — обычно несколько минут до и после проблемы. Вы ещё не пытаетесь отладить каждую ошибку. Вы пытаетесь увидеть порядок и время: что произошло первым, что изменилось потом и где поток остановился.
Если продукт ведёт аудит‑трейл, возьмите и его. История статусов часто удобнее, чем application logs, потому что показывает бизнес‑изменения простым языком. Строка вроде «заказ сдвинулся из paid в refund_pending» легче ложится на карту, чем стектрейс. То же самое относится к заметкам админов, истории вебхуков и временным меткам изменений состояния.
Держите подготовку небольшой. Короткого пакета достаточно: 10–20 недавних тикетов по одному потоку, фрагменты логов вокруг ошибок или задержек, записи об изменении статусов или аудите для тех же случаев и три‑пять ключевых действий пользователя.
Эти действия пользователя удерживают сессию в рамках. Запишите их простыми глаголами: разместить заказ, отменить заказ, запросить возврат, загрузить документ, одобрить выплату. Пока пропускайте всё остальное. Если команда попытается картировать весь продукт, час улетит быстро.
Узкая область работает лучше. Выберите один поток, один тип проблемы и один недавний период. Для стартап‑команды это может быть только вопросы с возвратами за последние 30 дней. Этого достаточно, чтобы заметить реальные доменные события и затем превратить их в более чистые модули.
Приходите на сессию с одной страницей доказательств, а не с папкой сырых данных.
Что считается доменным событием
Доменное событие — это факт бизнеса, который уже случился. Это не клик, не имя экрана и не задача для команды. Если в тикете написано «Клиент попросил возврат», это ещё запрос. Событие наступает позже, когда что‑то в бизнесе реально изменилось: «Возврат одобрен», «Возврат отклонён» или «Возврат выполнен».
Пишите события в прошедшем времени, потому что они описывают факты, а не намерения. Прошедшее время также сохраняет честность карты. «Платёж захвачен» работает. «Захватить платёж» — нет. Одно — результат, другое — попытка чего‑то.
Это разделение важнее, чем кажется. Команды часто заполняют стену элементами вроде «Пользователь нажал refund», «Агент открыл дело» или «Нажата кнопка отправки». Это шаги интерфейса. Они могут помочь в работе с UI, но не объясняют поведение бизнеса. Если вы хотите доменные события из тикетов или логов, ищите момент, когда изменилось состояние.
Простое правило помогает: назовите то, что изменилось, а затем само изменение. «Заказ отправлен», «Счёт выставлен», «Подписка продлена», «Доступ отозван» — такие формулировки хорошо переносятся между инструментами, командами и кодом. Названия кнопок этого не делают. «Подтвердить модал возврата» быстро устареет, как только продуктовая команда переименует экран.
Акторы важны только если они меняют правило. «Возврат одобрен» часто достаточно. Но если в вашем бизнесе одобрение бухгалтерии отличается от автоматического одобрения, актор должен быть в названии события или заметке. «Возврат одобрен бухгалтерией» и «Возврат автоодобрен» — разные факты, потому что у них разные правила и разные дальнейшие шаги.
Если строка из тикета кажется расплывчатой, уточняйте её, пока факт не станет явным. «Клиент связался с поддержкой» обычно шум для картирования событий. «Аккаунт восстановлен» — полезно. Это говорит, что изменилось, а это и есть сырьё для последующей группировки поведения в модули.
Проведение часовой сессии
Поместите в комнату от двух до пяти человек. Один ведёт доску и следит за временем. Остальные приносят доказательства: недавние тикеты, фрагменты логов, заметки поддержки и, возможно, один‑два скриншота, если они объясняют бизнес‑изменение.
Это работает для команд, которые не любят воркшопы, потому что похоже на разбор реальной работы, а не на мозговой штурм. Вы не просите людей выдумать идеальную модель. Вы просите их указать на то, что уже произошло.
Практичный 60‑минутный поток выглядит так. Потратьте первые 10 минут на запись сырых фактов из тикетов и логов короткими заметками в прошедшем времени. Следующие 10 минут используйте, чтобы объединить заметки, описывающие одно и то же бизнес‑изменение. Потом 15 минут расставьте события в хронологическом порядке. Ещё 15 минут отметьте, что запустило каждый поток, и обведите правила, ожидания и передачи. Последние 10 минут оставьте для точек остановки, повторяющихся паттернов и открытых вопросов для отложенного рассмотрения.
В первые минуты держите заметки ясными и фактологичными. Пишите «клиент запросил возврат», «возврат одобрен» или «платёж не прошёл после повтора». Пропускайте догадки вроде «система дала сбой» или широкие ярлыки вроде «процесс возврата».
Затем почистите стопку. Разные команды часто описывают одно и то же событие разными словами, особенно когда одна запись от поддержки, а другая — из логов. Если две заметки означают одно и то же бизнес‑изменение, оставьте одну метку и двигайтесь дальше.
Когда сортируете по времени, не тратьте десять минут на споры про граничные случаи. Сначала поставьте очевидные события в порядок. Если одна часть ветвится, покажите разветвление и продолжайте.
Теперь отметьте действие, которое запустило каждый поток. Это может быть действие клиента, сотрудника, периодическая задача или сообщение от другой системы. Это важно, потому что неясные старты создают грязные модули позже.
Выделите три вещи по ходу: правила, ожидания и передачи. Правило — это место, где бизнес принимает решение, например «возвраты свыше $500 требуют проверки». Ожидание — мёртвое время, например «ожидание ответа банка». Передача — когда работа переходит между людьми или системами.
В одну итерацию не нужно полного охвата. Остановитесь, когда новые тикеты лишь повторяют тот же путь с незначительными изменениями формулировок. Если последние элементы не добавляют ни нового события, ни нового правила, ни новой передачи — карта достаточна, чтобы превращать её в модули.
Перед уходом оставьте небольшую зону для споров и недостающих данных. Не позволяйте им съесть весь час.
Простой пример: поток возврата заказа
Этот метод быстро становится конкретным. Тикет поддержки говорит, что клиент попросил возврат после того, как увидел два списания по одному заказу. Лог подтверждает. Тот же платёж был захвачен дважды в течение минуты с одинаковым ID заказа и суммой.
Это даёт команде лучшее, чем догадки. У них есть реальная проблема, жалоба клиента и чёткая последовательность, которую можно проследить.
От тикета и логов к событиям
Вместо разговоров о экранах, эндпойнтах или таблицах базы данных запишите, что произошло, в бизнес‑терминах. Чистая начальная версия может выглядеть так:
- платёж захвачен
- платёж захвачен повторно
- запрошен возврат
- возврат одобрен
- возврат отправлен
Сначала оставьте дублирующий захват в карте. Он ясно рассказывает историю. Позже можно решить, блокировать ли такое повторение, объединять его или помечать для проверки.
Как только эти события расположены в порядке, поток становится легче читать. Часть, связанная с платежом, касается взимания средств и предотвращения повторного выполнения одной и той же операции. Часть с возвратом начинается после того, как кто‑то заметил проблему, будь то агент поддержки, автоматическая проверка или сам клиент.
Что становятся модули
Здесь дизайн модулей становится практичным. Платежи и возвраты могут касаться одного заказа, но они решают разные задачи. Модуль платежей отвечает за попытки захвата, ссылки транзакций, повторы и защиту от дубликатов. Модуль возвратов отвечает за запросы, одобрения, статус выплат и учёт того, что вернули клиенту.
Карта также быстро отвечает на один запутанный вопрос: где должна быть идемпотентность? Она должна быть в платежах. Этот модуль должен остановить второй захват для того же заказа. Модуль возвратов исправляет результат после ошибки, но не должен нести правило предотвращения самой ошибки.
Небольшой пример часто меняет взгляд команды на систему. Один тикет и одна трасса логов могут превратиться в короткую карту событий, два понятных модуля и одно следующее действие, с которым трудно поспорить: сделать невозможным дублирование захвата платежа.
Превращение карты событий в модули
Глядя на законченную карту событий, не режьте её по экрану, команде или таблице базы данных. Режьте её по бизнес‑результату. Если несколько событий нужны, чтобы выполнить одну задачу, они обычно принадлежат одному модулю.
Поток возврата показывает это хорошо. «Запрошен возврат», «Возврат одобрен», «Возврат отправлен», «Возврат закрыт» — все они ведут к одному результату: деньги возвращены и дело закрыто. Такой набор часто становится модулем Refunds. Название говорит, что делает модуль, а не где хранятся данные.
Разные правила обычно означают разные модули. Если в одной области требуется одобрение менеджера, временные лимиты или проверки на мошенничество — держите её отдельно от области, которая только хранит статусы. Разделение важно там, где принимаются решения. Правила меняются чаще, чем поля.
Внешние системы оставляйте на краю карты. Платёжный шлюз, почтовый сервис, ERP или вебхук — соседи, а не центр. Ваш модуль должен говорить на языке бизнес‑событий, например «возврат отправлен» или «клиент уведомлён». Тонкий слой интеграции решит работу с внешним API.
Избегайте расплывчатых имён вроде «Core», «Shared» или «Processing». Они скрывают задачу. Имена вроде Refunds, Inventory Reservation, Billing и Customer Notifications лучше, потому что новый разработчик за секунды додумает, для чего они нужны.
Быстрая проверка помогает. Группируйте события, которые приводят к одному бизнес‑результату. Разделяйте группы там, где меняются правила или нужны одобрения. Переносите внешние вызовы на край. Выберите простое имя, соответствующее задаче. Затем протестируйте группу на одном реальном тикете.
Эта последняя проверка быстро ловит плохие разрезы. Возьмите один реальный тикет или баг‑репорт и проведите его через модуль. Если простой тикет прыгает через три модуля, прежде чем произойдёт что‑то полезное, ваш разрез, вероятно, неверен. Если один модуль пытается покрыть два несвязанных тикета, он слишком широк.
Хороший модуль может объяснить одну реальную работу от начала до конца, не притягивая половину продукта в обсуждение.
Ошибки, которые портят карту
Метод быстро путается, если команда записывает то, что система должна делать, вместо того, что уже произошло. Эта одна ошибка портит всю карту. Команда «выдать возврат» — это запрос. Событие — факт, например «возврат одобрен» или «возврат выплачен».
Формулировки важнее, чем кажется. Когда команды вытаскивают элементы из тикетов и логов, они часто копируют названия кнопок, имена джобов или API‑действия. Это полезные подсказки, но не временная шкала. Шкала должна показывать факты в порядке, в котором их могли наблюдать люди или системы.
Расплывчатые названия вызывают следующую проблему. «Статус обновлён» почти ничего не говорит. С чего и на что он обновлён и почему? Лучше, если имя события несёт смысл. «Возврат отклонён потому что платёж уже проведён» длиннее, но никто не должен домысливать. Если двое читают карту и представляют разные истории, имя события слишком размыто.
Ещё одна распространённая ошибка — смешивание нескольких путей в одной линии. Поток возврата, поток chargeback и поток жалобы поддержки могут касаться одного заказа, но это не одна и та же история. Если поместить их на одну временную шкалу, вы получите фальшивые связи, дублирующиеся события и карту, которой никто не доверяет. Сначала разделите их. Позже соедините там, где они действительно пересекаются.
Команды также позволяют таблицам базы данных решать границы модулей. Это кажется аккуратным, но обычно даёт тонкие модули с именами вроде Orders, Payments и Statuses, которые перепускают логику друг другу. Модули должны следовать за бизнес‑изменением, а не за хранением. Если один кластер событий отвечает на один бизнес‑вопрос, держите его вместе, даже если данные лежат в нескольких таблицах.
Редкие пограничные случаи могут подождать. Команды тратят половину часа на один странный тикет с прошлого года и никогда не заканчивают основной путь. Начинайте с общего потока, который случается каждую неделю. Исключения добавляйте только после того, как нормальная история станет ясной.
Простой тест помогает. Каждая заметка должна описывать факт, который случился. Каждое имя события должно быть понятно без дополнительного объяснения. Одна временная шкала должна покрывать одно путешествие. Линии модулей должны следовать за кластерами событий, а не за именами таблиц. Странные случаи держите в стороне от основного пути до конца.
Когда карта мутнеет, обычно помогает простая правка: переименовать факты, разделить путешествия и ненадолго забыть про базу данных.
Быстрые проверки перед сохранением результата
Грубая карта может показаться завершённой слишком рано. Дайте ей последний обзор перед тем, как превращать в имена модулей, тикеты или код. Если карта проваливает эти проверки сейчас, она обычно создаст грязные модули позже.
Начните с простейшей проверки: дайте поток тому, кто не был на сессии. Новый коллега должен уметь прочитать её слева направо и пересказать историю простыми бизнес‑словами. Если ему нужно объяснять, переименуйте заметку или разделите шаг.
Каждое событие должно отмечать реальное изменение в бизнесе, а не действие экрана или техническую деталь. «Запрошен возврат», «возврат одобрен» и «возврат отправлен» — это события. «Пользователь нажал отправить» и «API вернул 200» — нет. Эта проверка не даёт логам превратить карту в шум интерфейса.
Карта также должна быть трассируемой. Каждая заметка должна исходить из того, на что вы можете показать: тикет поддержки, лог аудита, заметку инцидента, разговор с ops или реальную запись в системе. Если никто не отвечает на вопрос «откуда это событие?» — относите его к догадкам, пока не верифицируете.
Прочитайте вслух имена модулей. Они должны звучать как бизнес, а не как фреймворк. «Refunds», «Payments», «Orders» — ясно. «RefundHandlerService» и «TransactionOrchestrator» — это имена кода, а не домена.
Сделайте один проход очистки перед сохранением. Уберите заметки, описывающие страницы, кнопки, формы или HTTP‑вызовы. Объедините дубликаты с разными словами. Обведите пробелы, где история прыгает и никто не знает, что происходит. Пометьте догадки, чтобы они случайно не превратились в факты.
Небольшой поток возврата показывает разницу. Если карта говорит «клиент открыл страницу возврата», «клиент нажал кнопку» и «POST /refund выполнен», вы картируете интерфейс. Если она говорит «запрошен возврат», «возврат рассмотрен» и «возврат выполнен», у вас есть то, что можно превратить в модули.
Сохраняйте карту только тогда, когда она читается как бизнес сам по себе. Такая версия переживёт смену UI и даст границы модулей, которые потом можно отстаивать.
Что делать дальше
Не пытайтесь очистить всю карту сразу. Выберите один модуль, где команда уже испытывает боль, например возвраты, неудачные регистрации или изменения в счётах. На одной странице напишите события, команды, которые их запускали, и правила, решающие, что может произойти дальше. Если двое по‑разному описывают одно и то же правило, остановитесь и согласуйте формулировку.
Эта страница — рабочий черновик, а не формальная спецификация. Она даёт команде общий взгляд, который можно протестировать. Обычно это первый реальный победный момент: меньше домыслов, меньше лишних споров и более ясная отправная точка для разработки.
Повторяющиеся точки отказа должны сразу уйти в инженерную работу. Если карта показывает одно и то же падение снова и снова, превратите это в тест и алерт. Возврат, который запрашивают дважды, заказ, который остаётся в «pending», или вебхук, который приходит с опозданием, не должны жить только на белой доске. Поместите такие случаи туда, где команда увидит их в процессе разработки и в продакшне.
Карта также помогает выбирать границы. События, которые разделяют одинаковые правила, обычно принадлежат одному пакету кода или сервису. Разделяйте их только при явной причине: разное владение, разный темп релизов или очень разные требования к масштабированию. Если вы разделите слишком рано, создадите лишнюю координацию до получения реальной выгоды.
Некоторые команды застревают на этом шаге. У них есть грубая карта, но они не уверены, подходят ли модули или не пропустили правило. Короткий обзор от опытного fractional CTO может помочь. Oleg Sotnikov at oleg.is работает со стартапами и маленькими командами на этом шаге: превращает грубые карты событий в практичные модули, тесты и планы поставки без добавления лишнего процесса.
Держите следующий шаг маленьким и конкретным. Возьмите один модуль, выпишите его события и правила на одной странице, добавьте два теста для известных случаев отказа и позвольте этому сформировать следующий спринт.