Event Modeling Webinar - From idea to production code with Event Sourcing and Code Generation
Event Modeling / Event Sourcing applied · 2025-02-16 · 1ч 54м · 1 310 просмотров · YouTube ↗
Топики: durable-execution
🎧 Аудио
📝 Summary
model=deepseek-v4-flash · prompt=summary-v7 · 21 652→3 264 tokens · 2026-07-20 15:15:53
🎯 Главная суть
Event Modeling — это метод структурированной коммуникации между разработчиками и бизнесом, основанный на четырёх шаблонах: event (изменение состояния), command (инструкция системе), read model (способ получения данных) и automation/translation (фоновые процессы и интеграции). На вебинаре Мартин из компании Nebulit на примере системы таймшитов за 90 минут проходит полный цикл: от нечётких требований через мозговой штурм до запущенного event-sourced приложения на Spring Boot + Axon и генерирует продакшн-код прямо из модели.
Зачем нужно Event Modeling
Главная проблема проектов — плохая коммуникация. Разработчики и заказчики используют разный язык, из-за чего требования интерпретируются по-разному, а ошибки обнаруживаются слишком поздно. Event Modeling даёт единый визуальный язык: общий набор терминов (event, command, read model) понятен обеим сторонам. Модель обсуждается в начале проекта, когда изменения дешёвы. Позднее исправление обходится в разы дороже.
Волновая структура любого софта
Все программные системы можно свести к повторяющемуся шаблону: триггер → изменение состояния → реакция. Триггер (клик пользователя или фоновый процесс) вызывает command, который порождает event (запись о том, что состояние изменилось). Другие части системы реагируют на этот event. Эта «волна» проходит сквозь систему. Event Modeling моделирует каждый такой шаг как отдельный строительный блок — slice (срез). Система собирается из slices как из Lego-кирпичиков.
Четыре строительных паттерна Event Modeling
Для моделирования любой системы достаточно четырёх шаблонов:
- State change — информация входит в систему: command → event.
- State view — информация выходит из системы: event → read model (проекция).
- Automation — фоновый процесс, реагирующий на события без участия пользователя (изображается шестерёнкой).
- Translation — взаимодействие с внешними системами; внешние события обозначаются жёлтым цветом.
Мозговой штурм и старт с помощью AI
Сначала команда (в идеале до 30 человек: UX, разработчики, бизнес, безопасность) собирает все возможные events, не обсуждая детали. Чтобы снять начальную заминку, можно использовать AI-интеграцию в инструменте Event Modeling (плагин для Miro). Мартин вводит короткое описание: «хочу добавлять, удалять таймшиты и строки, затем отправлять таймшит». AI генерирует начальную временную линию событий: TimesheetAdded, TimesheetRemoved, TimesheetEntryAdded, TimesheetEntryRemoved, TimesheetSubmitted — вместе с примерными атрибутами. Это становится отправной точкой для обсуждения.
Построение и проверка первого среза (Add Timesheet)
Модель должна читаться слева направо как история. К первому событию TimesheetAdded добавляется экран. Мартин рисует примитивный wireframe с полями Name, Email, Period и кнопкой Create Timesheet. Затем определяется command AddTimesheet. К событию прикрепляются поля (name, email, period). Для ID генерируется UUID.
Информационная полнота — ключевая механика: если какое-то поле события не обеспечено ни одним из подключенных элементов (command, UI, read model), стрелка становится красной и блокирует прогресс. Например, без решения, откуда берётся ID, стрелка остаётся красной. Это заставляет обсудить, генерируется ли ID на сервере или имеет бизнес-смысл.
Когда все поля совпадают, стрелка становится чёрной, slice готов к реализации.
Срез отображения таймшитов (Read Model)
После создания таймшита пользователь должен видеть их список. Для этого добавляется read model TimesheetsAsList, которая берёт данные из события TimesheetAdded. В read model достаточно поля period и ID. Связь между событием и read model — это проекция. Для этого среза задаётся given-then тест (без command): «Если было событие TimesheetAdded с периодом 2025-01, то read model должен содержать строку с периодом 2025-01». Такой тест описывает поведение read model в чистом виде.
Прототипирование прямо в браузере
Инструмент Event Modeling (коммерческая часть) позволяет нажать кнопку и развернуть работающий прототип на основе модели. Прототип использует in-browser event sourcing engine. Можно кликать по кнопкам, вводить данные, и события сохраняются в локальном event store. Например, при добавлении таймшита (ID=1, Name=Martin, Email=martin@nebulit.de, Period=2025-01) в event store появляется первая запись. Затем, после описания read model проекции (простой фильтр: показывать все неотправленные таймшиты), список таймшитов обновляется автоматически — всё работает без бэкенда.
Бизнес-правила через Given-When-Then
Любое бизнес-правило описывается тремя элементами: given — текущее состояние системы (набор уже произошедших событий), when — новое действие (command), then — ожидаемый результат (новое событие или ошибка).
Для среза AddTimesheetEntry ключевое правило: «строки таймшита не должны пересекаться во времени». Пример:
- Given: TimesheetAdded, TimesheetEntryAdded (task=4711, date=2025-01-01, start=10:00, end=12:00).
- When: попытка добавить TimesheetEntry с task=4711, date=2025-01-01, start=11:00, end=13:00 (пересечение).
- Then: ожидается ошибка (красная заметка на модели).
Такой тест можно напрямую транслировать в код (unit-тест).
Срез отправки таймшита (Submit Timesheet)
Для отправки таймшита нужен command SubmitTimesheet и событие TimesheetSubmitted. Единственное обязательное поле — ID таймшита.
Когда таймшит отправлен, он должен исчезнуть из списка активных. Для этого Мартин добавляет обратную стрелку от события TimesheetSubmitted к read model TimesheetsAsList (единственный тип обратной ссылки, который он допускает). В проекции read model пишется логика: при TimesheetSubmitted — удалять элемент из списка. В прототипе это отрабатывает: после нажатия Submit таймшит пропадает.
Валидация модели
Перед кодогенерацией нужно проверить модель на корректность. Встроенный валидатор находит ошибки: например, у события TimesheetAdded не указан атрибут ID. Мартин исправляет это вручную (AI-автоисправление в планах). После исправления всех таких ошибок модель готова.
Генерация документации (EventCatalog)
Из модели можно сгенерировать документированную систему на базе EventCatalog (open-source). Для этого используется JSON-метамодель, описывающая все события, команды и их связи. Команда gen в терминале запускает кодогенератор, который создаёт готовый каталог событий — с веб-интерфейсом, где видны events, services, domains и их отношения (на примере демо-системы e-commerce из книги «Understanding Event Sourcing»). Документация всегда актуальна, так как генерируется из модели.
Генерация продакшн-кода (Axon + Spring Boot + Spring Modulith)
Для генерации приложения нужно определить swim lanes — какие события принадлежат одному агрегату. Для простого таймшита достаточно одной swim lane с агрегатом Timesheet. Кодогенератор создаёт:
- скелет Spring Boot-приложения (полностью настроенный, стартует сразу)
- класс агрегата с command handler’ами
- для каждого slice — отдельный пакет, изолированный Spring Modulith'ом (пакеты видят друг друга только через события)
- REST-контроллеры, command’ы и event’ы (на Kotlin, но легко адаптируется под Java)
- unit-тесты, прямо отражающие given-when-then из модели
Пример: срез AddTimesheet → пакет addtimesheet, класс AddTimesheetCommand с полями name, email, period, ID (UUID). Command handler в агрегате создаёт событие TimesheetAdded. Тест запускает command и проверяет, что событие сохранено.
После генерации приложение компилируется, стартует (использует Postgres) и предоставляет Swagger UI для вызова REST-эндпоинтов (добавить таймшит, добавить запись, отправить таймшит). Мартин исправляет мелкую ошибку (не указан @CreationPolicy в агрегате) — находит её через упавший тест.
Этапы моделирования и роли участников
Мартин делит процесс на 7 фаз (от мозгового штурма до детализации).
- Фазы 1–3 (события, таймлайн, экраны) — участвует максимум людей, включая бизнес.
- Фазы 4–6 (команды, read model, swim lanes) — только те, кто отвечает за конкретный chapter (например, продукт или процессинг). Обычно 5–6 человек: 2 разработчика, 2 продакта, 1-2 эксперта.
- Фаза 7 (детали атрибутов и given-when-then) — чисто техническая встреча перед реализацией.
Бизнес-правила (given-when-then) обязательно требуют участия бизнес-аналитика — он знает точные ограничения. Это исключает догадки.
Ответы на вопросы (из Q&A)
- Несколько событий от одной команды — возможно, но не рекомендуется, так как усложняет рассуждения о системе. Лучше стремиться к 1:1.
- Обработка ошибок — если ошибка не порождает follow-up процесс (просто блокировка), она обозначается красной заметкой. Если ошибка требует дальнейших действий — она становится новым событием (например,
TimesheetEntryFailed), на которое подписываются автоматы. - Внешние данные (например, тарифный план пользователя) — моделируются либо как read model с известными данными, либо как внешнее событие (
PremiumUserAuthenticated). Read model не обязательно связан с событием; можно указать таблицу. - Разногласия в стиле (с Мартином и Адамом Дыметчуком) — нормально. Важно, чтобы команда внутри договорилась о едином способе моделирования.
- Альтернативы Axon — в .NET используют EventStoreDB (теперь Curity) или CosmosDB. Без фреймворка не рекомендуется: команда потратит всё время на написание собственного фреймворка.
- Генерация кода и работа двух разработчиков — event принадлежит slice, который его создаёт. Это «владелец». Другие slices используют event как контракт. Ветки не конфликтуют, так как событие одинаково у всех.
📜 Transcript
en · 16 589 слов · 211 сегментов · clean
Показать текст транскрипта
Hi, this is Martin. I'm the CEO of a company called Nebulit. I operate in southern Germany and the webinar you are about to see will guide you through a typical software development process with a tool called event modeling. Event modeling allows to improve the communication between development teams and the business stakeholders in a very structured way. And in this webinar you will see exactly how this process works. We will start with a set of loose requirements. We will model some parts of the system and discuss the functionality. We will then create a few prototypes just to verify the model. We will validate the model on the fly using an information completeness check. You will see in the webinar what that actually means but it saves you time and money and in the end we will generate some production code directly from the model all within about 90 minutes. Where to go from here? There is this book called understanding event sourcing that describes this whole process in about 600 pages This book is really a very good starting point and explains all the steps necessary to introduce event modeling And if you want to work with me if you want to be a little bit faster feel free to contact me I offer consulting and training for teams that want to adopt event modeling as a daily practice Just head over to my company page nebulit.de and send me a quick email. Let's talk And now enjoy the webinar. Yeah, many thumbs up. That's good. Only experts here. Amazing. Not too long ago I gave a workshop with Adam Dymetschuk which was labeled a beginner's workshop and it turned out to be that there were only experienced event sources in this workshop. They had much more experience than me so we had about 100 years of experience in this workshop. Let's see if this is the same today. Only experienced people here. Amazing. So before we start, let me give you a quick warning. If you are here and you expect a polished slide deck or something, you're clearly in the wrong webinar. There will be no slides. You will not see any polished slide deck. If you work in a real world project, the only time you see polished slide decks is when you work, if you talk to consultants. So for me, you will not see any polished slide decks. We will go right to the trenches today. All right. That's what I'm here for. Yeah, nice. Nice. Me too. Okay, let's wait half a minute and then we jump right to the board. I will share my screen in a second and then we directly start. Maybe I can already start with the introduction. Some of you might know me, some might not. I'm Morten. I'm the CEO of a company called Nebulut, operating in southern Germany, Bavaria. It's an invent modeling company. So what I do is I really help other companies adopt event modeling, adopt event sourcing, adopt event driven architectures and basically just supporting wherever I can. Also helping to build the community around event modeling. There was a webinar I gave back in 2024, January 2024. This was basically the first webinar I gave about event modeling. And there I said event modeling will change the IT industry within two years. So we are almost one year in and I guess we are on track. So still almost a year to go but I think we are about to see something amazing happen. I will tell you in a little bit what event modeling is so if you don't know what I'm talking about don't worry you will learn everything you need to know about it in just a few minutes. All right. I think most people are here with 34 people. That's already amazing. So I will share my screen. Again, I will share the MyRobot link. If you haven't seen it, here is the MyRobot. You should be able to access it. And then I will share my screen. And let's talk a little bit about event modeling. Let's quickly talk about the agenda of today. So as I said, there are no slides. I'm here to work with you. So in the beginning, I will give you a brief introduction about event modeling. What is it all about? Why are we talking about event modeling? That's all you need to know. You will see the whole process in action. So the goal of today is to start with a set of loose requirements. Build a complete application. Let's see how far we can get. The last time we did this, we implemented a few slices because there were so many questions, depending on how many questions you have today. Maybe we will finish, maybe we will not. It doesn't really matter. At least we will have a lot of fun today. That's my goal. So we will build a small prototype along the way. You will see how I do prototyping. We will generate a little bit of documentation and we will generate some production code. So you will really see the whole process. In the end, we will at least have some kind of running event-sourced application using Spring, Spring Boot, Spring Modulith and Axon just from the event model. So you will see the whole process and in the end, you will have the possibility to ask questions and hopefully get some answers. At least I will try. During the whole webinar, you will... absolutely allowed to ask questions at any point in time. So, don't wait or something. Don't wait for the Q&A. This can be a great discussion. If you have questions during the webinar, just throw them out so everybody will learn something. All right, let's talk a little bit about event modeling. Why are we doing event modeling? Maybe some of you know what event modeling is. If you never heard of it, maybe you heard of something else which is called event storming. they are pretty similar at least in the early phases. What is event modeling all about? It's about communication. If you ask me, one of the biggest problems we have in all projects is very very bad communication. We as an industry, we never manage to define some kind of a clear language how we discuss requirements, how we discuss what a system should actually do. We are really bad at it and I'm no exception. So what we need to find is we need to find a way how can our developers, our architects discuss requirements with our stakeholders, with the business people. How can we manage that they understand each other? They need some kind of clear common language and event modeling is exactly that. With event modeling you have the possibility to define the language of your project and of your system basically in discussions. And modeling a system really helps to understand and build this common understanding what the system should actually do right in the beginning of the project, not in the end. So we will uncover all the question marks, all the problems in a project right in the beginning, in the early phases where everything is cheap. If you find problems in your requirements right in the beginning of a project, it's very cheap to fix them. The later you find these problems, the harder it will get to fix them and the more expensive. So these discussions really save time and they save a lot of effort. If you look at software systems and if you've seen more software systems, you realize they are all the same. All these software systems are basically the same thing. And if you at some point in time, I realized all software systems basically mimic like a wave structure. If you've read my book. I wrote a book, it's called Understanding Event Sourcing. There's also quite a lengthy chapter about this whole idea of the wave structure and why software is structured in waves. So basically what you have in the system is always some kind of a trigger. Let's say you have a UI, for example, can also be a background process and this triggers something. So maybe the user clicks on a button and submits an order. So this is the cause of something. This button click triggers a change in the system, a state change. So our system changes in some point or in some way. The next thing that happens is we have other processes, other things in our system that simply react to this state change. So you always have something, a trigger, state change. The state change triggers the next thing. And so you have this wave structure that goes through our system. And all systems are built like this. You can model any system, no matter how complex, by using this simple wave structure. And you will see how that works because event modeling does exactly that. And if you look at this wave structure, in the end what we have is every system is made up of simple building blocks. We call them slices. When you read my book or when you read about event modeling, at some point you will discuss slices. Because all systems are made up of slices. And my structure, my architecture of systems is typically, I typically build slice based architecture. Maybe you've heard of it, vertical slice architecture. It's basically the same idea. It's just separating the system into small building blocks and you can put them together like Lego bricks. And with event modeling, we can plan these slices in a way that we can easily work with them. And to do this, we only need a few small building blocks. Actually, it's just four patterns we need in event modeling to model any system, no matter how complex. And we only need these three elements for it, basically. We have an event. An event is always something that changes in our system, basically a state change. Whenever something changes in our system, we have an event that showcases it. You will see in a minute how that works. The next thing is we have a command. A command is basically an instruction to our system. So basically a click on a button can trigger a command in our system which results in an event. An order was submitted. So we record this event. And the last thing is a read model. We only need these three elements. A read model is basically a way to get information out of the system, to display it in a UI or as an input to a background process, for example. Basically, with these three elements, I can describe how does information get into the system using commands and events. How do I get information out of my system using events and read models? And these are the four patterns we work with. Using these four patterns, you can describe any system. Information gets into the system. We call this state change. If a command, command results in an event. Very simple. Don't worry. You will see in a second how that works in practice. With a state view is the second pattern. Take the events already recorded in our system. and build read models, build queries from them. If you come from an event-sourced background, you know this as a projection maybe. So we get information out of the system. But not everything is a button click. Sometimes we have these background processes that do something. So for example, you have a user that submits an order and if this order was submitted, we have a background process that maybe sends an email. Background processes in event modeling are modeled as these gear symbols. So a gear symbol is simply showing okay here something is happening in the background and even a business person will understand at this point something is happening it doesn't matter how it's implemented implementation doesn't really matter in event modeling we are only discussing what the system should actually do not how it's doing it and the last thing we need some kind of translations a translation is always if our system communicates with an external system we need some kind of translation to do it Typically also just this gear symbol. In my event models, the external events are yellow. So you know exactly, just looking at the structure here, something external happens. And this is basically how you structure it. In event modeling, you have exactly this wave structure. You have these state change slices, you have the state view slices. And if you put them together, you have your system. Sometimes with a UI, sometimes with a background process. But any system can be modeled like this. And what I want to do today with you is I want to build just a little system. We will build a little time tracking system. And we have some requirements here. Typically, when you start with a new project, you have a set of requirements. Mostly they are pretty bad. They're pretty bad requirements. So something like, okay, the timesheets, we have some kind of timesheet. Timesheets must be submitted. We have some kind of timesheet entries. So it's just a few requirements. When we start with event modeling, The first thing we do typically is it's called brainstorming. Brainstorming means the first thing we do is we gather all the events in our system and we need as many people as possible to do this. This can be UX, this can be our backend developers, this can be front-end developers, this can be the CEO, this can be database people, people from security, business people, project managers, whoever is part of the project should join for the brainstorming session. So sometimes this can be 30 people. It really depends. But in the first session, we really try to define this common language and to define the terms. What is this project actually really about? It's one of the most important sessions in any event modeling project. The first sessions define the language. So what we do here is typically something like this. What you see here on the left is my event modeling tooling. This is a plugin. You can just install it in Miro. It's freely available. It just helps you a little bit in modeling and gives you a little bit of tooling around event modeling. You don't need it by any means. So event modeling is really very simple. You can do it without tooling. The tooling really just helps. If you want to install it, I will send you a link after the webinar. Don't worry. Then you can just install it. So the first thing we typically do is we find a few events. So we know we talk about timesheet management, time management. So one event we could use here is timesheet edit. Somehow maybe we need to add a timesheet. We don't know what that actually means but some business people could just put this on the board without explaining it. In the brainstorming session we really try to find as many events as possible without really discussing what that means. Sometimes in these event modeling sessions, it's a little bit hard to get started. People are a little shy. They don't know what to do. They are afraid to make errors. What I do then sometimes is I use a little bit of AI to get started, which works really well. So using this tooling here, you can just say, okay, we want to use a little bit of AI. And you can just describe what does the system actually do. Let's try this. Let's see if this works. So for example, I could say, We want to build a timesheet management system. I want to be able to add timesheets, remove timesheets, and I want to be able to add timesheet entries and remove them. In the end, I want to be able to submit the timesheet. Something like this. Just a very rough description could be our system, just to get started. What this integration will now do is it will analyze what you give it and it will try to build up a small timeline. Give you a handful of events just to get started. Just we have something to discuss. Nice. So we have something here. Timesheet added, timesheet removed, timesheet entry added, timesheet entry removed, timesheet submitted. Great. Perfect to get started. It already gives us some attributes here. We will see in a second if that really makes sense. Not yet sure, but it doesn't look too bad. So when we have our initial timeline, we will just go through it from left to right. It should make sense. So after the brainstorming, we have a huge number of events. So how does this typically look? There's an example down here. It looks something like this. This can be 100, 200, 300 events, depending on how many people are in the session. This can be huge. It's chaotic. It's really hard to read. And at the end of the brainstorming session, we try to bring this in an order. So in the end, it should look like this. You have a story of your system readable from left to right. That's the goal. Readable from left to right. It should make sense, both for developers and for the business people. Now, if we look at our short storyline here, we have a timesheet that is added. Seems to make sense. We could remove it. All right. Then we can add the timesheet entry. And this is exactly what I also do in event modeling sessions. So I read it aloud to everybody. As if I'm reading a story to everybody. Everybody stands just there, listens, and we will find out, does it make sense? Timesheet can be removed, timesheet is submitted. Okay, nice. Makes sense. So the next thing we do is, and this is where event modeling really starts to be a little bit different than event storming, we add the first screens. Screens can be either you already have pre-made screenshots by your UX team. It's great if you already have screenshots. By any means use them here because it saves a lot of time. You can also import screens from Figma for example. I also like this a lot. So wherever you have the screens bring them in. If you don't have any screens what I do typically is I build them right here. So let me show you how I typically do this. Just adding a screen here. And I do build screens by intention, very ugly. So if I'm building screens in my room, they are always ugly. Because it's not about building the perfect UX. It's not about building the most beautiful screens. It's about giving everybody in the session something visual to work with. If you see a screen, you know exactly what we are discussing. Sometimes we start directly with the screens. If I realize that people are highly visual, we start directly with the screen so everybody sees what we are discussing. And what I'm typically using is just the wireframe library here in Miro. So for example, I could just say, when we want to add a timesheet, what information do we need? What is important? Well, we could say, at least I need to enter my name. Let's say for the timesheet, I need my name. Could make sense. I'm always working with examples so I could add in Martin. Okay, Martin adds a new timesheet. Great. Maybe I also need something like a time period. So if I'm working with the timesheet, I could add something like time period could be something like this. One timesheet per month. And I would discuss with the business people. How often do you create these timesheets? Is it per month? Is it per week? Is it per day? Oh, it's per month. Okay, great. Then it's something like January 2025 or February 2025. Sounds decent. Anything else? What do we need for a timesheet? I think that could already be enough. We will have some kind of a button. Create timesheet. Or just create, maybe. Something like this. This is how my screens typically look like. Most people hate them because they are ugly. But that's fine. It's just about capturing the information flow. I already prepared some screens, so we will not build these screens because it takes a lot of time to build them. Let's use my pre-built screens. So they are here. I bring them down. Let's go through them. So what do we have here? We have a name. We have an email. Maybe we need some kind of an email address. We have the period. We have this create button. All right. That's not too bad. We have some kind of selection. We can select the timesheets later. Okay. Here's a button to submit a timesheet. That's also fine. Apparently, we can add some timesheet entries with the tasks. So we need a reference to a task. We need a day. For which day do we do this? And from and to. Obviously, this is the time. All right, then we have a listing of our timesheet entries. We can edit them. And in the end, we can submit it. Seems like this is our time tracking system. So now we have our events, we have the storyline and we have a few screens. It's visual. And now we can already start to think about how does the system actually work? What do we actually do here? So for example, we always start with the first event. Let's start with the first event, move everything else a little bit to the right. What is the information we capture here? So currently the AI integration gave me just a timesheet ID. which is a technical information. This is not even that important. Much more important is the information we capture up here. So obviously we know, okay, there's the name, there's the email and there's some kind of the time period. And what I also do to make this very, very clear to everybody, I always mark these elements in the screen in blue. So everybody knows, okay, we are discussing exactly these information fields here. This is the input for our first business action to create a new timesheet. So we can already add this information to our event here. Name, email and period. So let's do this. Using this tooling you can just define the schema. Typically you can also directly work on this sticky note. That's really up to you. So let's say we have the name, we have the email and we have the period. Let's save this. This basically defines the schema of our event. So the timesheet ID, let's name this ID. I don't like timesheet ID. It's too long. It's hard to read. Let's just name it ID. Yeah, that's better. Something like this maybe. Now the question, just looking at the first slice here, what needs to happen so that we can store this event here? What needs to happen in our system so that this information is somehow stored in our system? Just by having this event here, doesn't mean we need to build this using an event-driven architecture and it does not mean we need to build an event source system or something. Just having an event here tells you some information is stored in our system. It doesn't matter how. This can be a relational table. It doesn't really matter how it is persisted. It's just telling you at this point in time with this event information is entering our system. So obviously somebody needs to put in the information and click on this button. I would also highlight this button. So this is basically what we are discussing for this functionality in our system. And now the question, what happens if a user clicks on this button? We need a command. This is what commands are for. The user triggers an action. This triggers a command in our system. We request the system to do something. So the command is always blue. And we would say add timesheet, for example. Now you can just connect these elements. So if this command here gets executed, I want this event here to be stored. And what you see here is this arrow turns red. This is one of the very, very important things in event modeling. What you see here is the so-called information completeness check. It checks at all time if all the information required by the event is provided by the connected elements. Why is this important? This is important because it prevents us from making wrong assumptions. One of the biggest problem in all projects is you're making assumptions. You assume the email to be available. We don't know where it comes from. We take care of it later. Let's assume the email is available. Well, what if it's not available? If we go into the implementation and then we realize, oh, we don't have the email here. It's in another system. And this other system is owned by another team with its own backlog. And suddenly our whole efforts to plan our current sprint are completely meaningless because the preconditions are wrong. The assumptions are wrong. And then we need to re-plan our sprint because the other team has its own priorities and they don't have time to provide the API for the email. And suddenly everything goes wrong. And nobody knows why the project suddenly costs double. the amount of what we originally estimated just because of wrong assumptions. And using the information completeness check here prevents us from making these wrong assumptions because we can't simply, we cannot go into the implementation because the error is red. Simple as that. As long as the error is red, we cannot do anything. We are not done planning. We need to find out where this information is coming from. So in this case, it's very simple because we know the name the email the period everything is coming from the ui the user just puts it in here that's easy so in this case i can just copy the fields as soon as all the connected elements all the fields are have an equivalent in the connected element error turns red great we're good the same problem of course appears when i connect the screen same problem also turns red because we need to tell the screen what information do you provide here so it does provide name, email and period. So just add the fields to the to the screen name, email and period. Now it's still red. Why it's still red? Because we haven't decided where does the ID come from. There is no input field for the ID. So where does it come from? So it's really it's it forces you to think about information flow. Where does all this information come from? If you don't know, you have a problem. This arrow will not turn black. And if you don't use the tooling, just look at the information. You will see, okay, ID is missing. Where does it come from? And then you start discussing. You discuss with your teammates. You ask the business stakeholders, hey, where's the ID coming from? Is it just generated? Oh no, no, there's meaning in the ID. You cannot just generate it because the ID has semantics. Oh, I didn't know that. Great, we discovered something new. In this case, we can just say, okay, the ID is generated. Just to calm down the information, completeness check. ID here is generated. And this is the ID, by the way. Great. Now everything is black. I love black arrows. I really love them. I hate red arrows. The longer I work with Miro, the longer I work with event modeling, the more I hate these red arrows. So the information completeness check is really, really important. And the great thing is, this already, this small thing here, already defines our first slice. This is an operation and you could already implement this. It's an isolated building block. Here the UI, the user can click on this button and in the end the information is stored here. That is an isolated functionality. And what you can do is you can just define, okay, let's make this a slice. You can just select everything and now it's a slice and you can give it a name. If you build slice based architectures, this could be your first JIRA ticket. You can implement this. But of course, we can describe there might be business rules alongside this slide. So what are the business rules? And we would discuss what is a business rule to create a timesheet? Are there any business rules? Oh, well, we could say, how do you describe business rules in event modeling? You describe them using give and when thens. We call them give and when thens. This is how you describe your policies. So you always say, given something happened in the system, so basically describing the current state of the system, when something new happens, for example, when someone tries to add a timesheet, then I expect the system to be in this new state. So very simple example, given nothing, given no prior timesheets were added, when I try to add a timesheet, I expect a timesheet added event to be stored in the system. Very simple use case, very simple test case. Typically what you do is these test cases are direct derivatives of your policies and of your requirements. We will talk a little bit more about given when then when we come to the timesheet entries. We have a lot of rules which belong to the timesheet entries. For timesheets themselves, nobody seems to know a lot of rules. So there might not be too many rules. But this already describes, okay, this is our simplest given when then. I can add timesheets. And you can translate them directly to running tests. You will see this hopefully a little bit later in the webinar. And the great thing is we can already start to implement a little prototype for it. Since we have this slice, which is an isolated block of functionality, let's implement a small prototype. I will show you how I do prototyping. The only thing I need to do for this, I will just start a small Docker container here. My Docker daemon is not running. That's basically the only precondition you have. Yeah, seems good. Now, can we do a small prototype just for this slice here? Generator available. That is good. Oh, one thing I need to do. I need to define a model context. Because typically when you work with event modeling, these models, they can get huge. They're really big. Depending on the system, of course. So systems can have 30 slices. Systems can have 300 slices and more. So typically it makes a lot of sense to split these models. into smaller models. So you don't have to do everything in one big model. You can split them into smaller models. And I use model contexts for this. Basically just a way to give a name to a certain model. So in this case, we could define a model context and say, that's my timesheet model here. Model contexts are always pink. So that's my timesheet model. It's just a name for my model. So everybody knows, okay, this is the context we are talking about timesheets here. Great. And I can assign my timesheet, my slices to my timesheet context. And now what I can do is I can use this to generate a small prototype just to see a little get a little bit of a feeling. How does that work? Does it work what I modeled here? Let's create it and jump over to the prototype. It gets generated in the background directly in the browser. Let's see if it works. It's not too bad. So we already this is my prototype that gets generated directly from the model. So we have my default flow and we have the timesheets screen here. The timesheet screen is directly the screen we defined here. If I'm going to the screen, we see, oh, there's a command here, but it's disabled because we haven't defined, okay, how does this work? What is the enablement for this command? So I can just say, okay, for this command here, first, I want it to be named correctly because that looks a little bit ugly. Let's say this is the add timesheet command and it should be enabled by default. Switching over, so you see it updates on the fly. Now you have this add timesheet button. The amazing thing here is what you have here is an in-browser event sourcing engine. So you can play around with event sourcing directly in the browser, which is a lot of fun. So we can say add timesheet. And this is exactly the information we provided in our command here. ID name email period. So let's say the ID here is a one. Name is Martin. Martin at Nebulit. And period is one 2025. Something like this. Nothing else happens because we haven't defined any views, anything. But we see we have our event store here. This is our event store. And we already see the first event is already stored here. And we can now work with this event. We can use it, for example, to display our timesheets in the next screen. Okay, great. So, does seem to work. Not too bad. So, what's the next thing we need? Since now we added our timesheets, obviously, we need a way to select the current timesheet. So, it's... We can add timesheets. We want to be able to select them. When we get information out of the system, what we need is we need a query or a read model. Read models are always green. Let's add a read model here. So the read model here could be timesheets as a list. It's a list of timesheets I want to display. And what we see here is obviously what we need is we definitely need the period because we want to display it and we will need the ID. of this. Maybe like that. A list of timesheets, just a period. So we don't even need all the information from the timesheet. We just need the period. So this means our read model here will just provide the period. Currently, this is all we need. Okay, let's see if that works. I connect the elements and you see it's black, which is great. Means, okay, we don't make any assumptions. All the information is available. And I can connect the screen and we can just copy over the fields. That should be fine. This is our second slice. We had our first slice, our first work item. Now we have our second slice. We get information into the system, creating timesheets. Second slice, we can display the timesheets. That's an isolated block of functionality. Because it's clearly defined, we only need the timesheet added event. And we need to provide the query here. That's all we need. So let's make it a slice. And let's make them equal high. Something like this. Not too bad. So can we also define test cases for our read model? Absolutely. We can exactly define how this read model will look like when we add a new timesheet, for example. The test case for it is typically a given then. It's not a given when then. Not like here, because there's no action that happens. We just want to show if we have the system in a certain state, how does the read model react? You basically describe the read model. So how could that look like? Basically in the simplest scenario, just given the timesheet was added, then I expect my read model to be in a certain state. So for example, I could say here, working with examples, given there was a timesheet added using my email, martin at nebo.de. So this is basically the example data you can provide. And the name Martin. like this and the period to 2025. Given this information was added, how should my read model look like? I could say in this case I want my read model to have exactly this value to 2025 and that's it. That's all. And now I could go through the scenarios and describe how would it look like if I have two timesheets added. Then I would have a list here. Something like that. You could clearly describe step by step how does this read model basically get built up from the events from the state in your system. And now if we have this, can we use this in our prototype? Can we already play around with it? It's already marked green here. So this I typically would also mark this green in a screen so everybody knows in this screen we are not interested in this button. We are not interested in anything else. The only thing we are interested in is exactly this area here. So can we use this in my prototype? I think we can. For this, I typically describe what the projection looks like. So you can basically code a little bit of event sourcing directly for this prototype. So you can basically define how does this event model react to the events. This is basically the same code you would also use later in your production system. You would maybe use a different language, but the code is exactly the same. Event sourcing looks the same in all systems, no matter how you implement it. The underlying concepts are always the same. So let's see if that changes anything. Let's refresh. Oh, one thing I've forgotten. Of course, I need to assign this also to my model context. That's important. Now let's see what happens. Oh, we have this new screen here because the screen here is named timesheet entry. So there's already the new screen. That's not too bad. Let's add a timesheet again. And now since we defined how the read model should look like, I can display my information here. Here's my timesheets. And it's everything is built upon the simple event here. We have only one event in our event store. And this event is used to build a projection for these timesheets here. So I can already play around with my model and I can really see does this what I model, does the thing I model here generally work. Of course, it doesn't look beautiful. You can adjust the styling of it. But this is not what this prototype is all about. It's really just about, does it work what we modeled here? Can we make it work very quickly, within minutes? And we already have our first two slices. You can discuss them. You can create tickets for these slices. You can implement them. You can even use the event model itself as your tool of project management. So, for example, you could just say this slice is now assigned. What will happen is the slice will get a different color. So just by looking at the event model, you know exactly which slices are currently in progress, which slices are currently worked on. Or you could say, oh, this slice is done. The more slices you finish, the more progress you have. So even the project managers will see immediately we have a system comprised of 100 slices and 50 of them are done. Means we are about 50% into the project. 50% is done. Most of my customers don't do this, not only using the EVAM model. So typically what happens is you have a slice in the EVAM model and what happens, you create a JIRA ticket referencing the slice. This is what typically happens. Any questions? Maybe asking, we're about halfway into the webinar. Any questions so far? Feel free to place them. Yes, Vlad. It's not public. Oh, many people are here. So it should be public. Let me see. Why do you need access? All right. Should work now. Can you try again? Thanks for the mention. So let me paste quickly the link again. So that's the link to the board. It should be accessible because some people are already on the board. Oh, no. What happens now? All right. So if there are no more questions, I would just continue with the next slice. because we have a lot of things to do today. So what we managed to do so far is we managed to create timesheets and we managed to display timesheets. Perfect use case, perfect thing for our first sprint. We could use this to display basically working software after the first sprint. We managed to implement our first slices. Great. Just amazing. So the next thing is let's talk about timesheet entries. So the next event we would basically look at is How do we add timesheet entries? What's the information we need? Same process again. Looking at the screen, what's the information we need to provide? So we need a selected timesheet, obviously. We need a task, so we need a reference to a task. We need a day, start time and from time and end time. So let's just add the information here to our event. So let's say we need, what do we need here? All right, so we need the task. We need the day, which is of type date, for example. We need something like start, which is a time. Oops. Start with it. So day, start is a date time. And end is also a date time. And we need, what was it? The task, which is a string. Something like this. Now I added this on the screen. We need the same on the event. task date start which is a date time and end which is also a date time something like that so we have an entry entry id we have a timesheet id task date start and end so what needs to happen here so that this event gets stored in our system what is the action we need to trigger basically first first thing i would always do is mark the elements on the screen we are discussing this this is the important elements here and we want to be able to add an entry so just by looking at the screen everybody knows exactly what are we discussing what is this this slice about and the command we need for this is add timesheet entry or just add entry let's keep it simple same thing again we would connect the elements should turn red so i copy the fields over now we see that is fine Again, connecting the elements here. That is also fine because we already defined the fields here. So this is our next slice. The possibility to add a timesheet entry. Let's make this a slice. And now we can discuss a few of the policies that come along with creating a timesheet entry. So what are the policies? So let's move this slice a little bit to the left like that. And also assign it to the model context like this. So what are the policies here? So typically what I do is as soon as the user selects a timesheet here, the user will automatically come to the next screen. There's no transition in the system happening. It's just a UI thing that happens. So then I just connect directly to screens, which is fine. And this is then a dotted line. Okay, there's one thing missing here, obviously. What is it? Yeah, I made a few mistakes on the fields. Just... Removing everything again. Here we go. Now let's look at our requirements. There are a few requirements for our timesheet entries. So for example, timesheet entries must have a start and an end date. Timesheet entries must not overlap. That's an interesting one. They must not overlap. These are all things where you would use a given when then to describe these policies, which are later then translated typically to running test cases in your code. So looking at this, Let's define a given when then for our at entry slice. Timesheets must not overlap. So we would do it like this. So given. First of all, give it a name. At entry timesheets must not overlap. What is the given here? Given the timesheet was added to the system. That's the first thing that we need. So you really set the system into a certain state. You play all the events. necessary to get into the state where you can add a timesheet entry. To be able to add a timesheet entry, you need a timesheet. So the first thing that needs to happen is a timesheet added. You cannot just add a timesheet entry without adding a timesheet. Timesheet added is the first event. So given timesheet added and given timesheet entry added, when I try to add a new timesheet entry with an overlapping period, then I expect an error. Oh no, misclicked. Do it again. Add timesheet entry overlapping period. Okay, again, given timesheet added, given timesheet entry added. When I try to add a new entry, go away. Then I expect an error. Oh, interesting. There is some HTML going on. Okay, let's ignore that for now. So given the timesheet added and given the timesheet entry added, what do I need to define so that this test case basically makes sense. We need overlapping timesheet entries here. So for example, we need the timesheet entry ID. So I defined it as a UUID here. So let me quickly fetch a UUID from somewhere. So we need the entry ID here. The timesheet ID we keep as a default. So the task would be create event model, for example, task 4711. Let's make it a task number. Let's say this is a task number. So the date is defined as a string. That's wrong. We need to correct that later. Let's say the date is 1st of January 2025. Start is also 1st of January 2025 at 10. Now really, we're working with examples here. So it's really clear for everybody. what is the policy we are discussing. The example must be very clear and very readable. And here we do a second time entry from 10 to 12, something like this. That's the example. And now if I try to add a new timesheet entry with the same data, so I can just copy the fields, saving a little bit of time, using the same data but an overlapping entry, what would happen? And in this case, I would expect an error. So in this case, we say it's the same entry, but starting at 11 and going to 13 German time. Now we have an overlapping entry. That's a problem. This must, this does not work. You cannot have this. So it's clearly showing in this, in this example here, this is when you get into this error case. And this is how you describe basically these policies. You always have this given when then. And you do this for every business rule that applies to exactly this slice. So you can describe this slice in absolute detail. How does it actually work? What are the rules exactly for this slice? Does that make sense? Let me correct this naming here. Not sure how that happens. All right. Now that means we have our next slice. So we can add a timesheet entry. Does that work in our prototype? Let's see. Let's see if we now can add a timesheet entry. So we have our add entry command here. This is new. Let's give it a better name. Add entry. All right. Let's see if it works. Now we have our add entry command. So we have our timesheet here and now we can add an entry. And this is also the schema we just defined in our event model. So we have our entry ID using a UUID here. The timesheet ID is a string. Task is 4711. Date is the 1st of January. Should have defined it as a date. And we have a start time, which is now and an end time, which is at about 19. Timesheet ID must also be a UUID. And let's just use the same for the example here. Now, if I look at my event store, I have a new event here, timesheet entry added. So just by modeling, I can really play around with my prototype and really see, does it work what I modeled here? Does it make sense? You should be able to play through your whole model in this prototype. If not, something is wrong. You should be able to play through the whole model here within minutes just to get a very, very quick feedback. So that's our third slice just on the clock. So, all right, let's do one more and then do a little bit of code generation. So let's see, we should be able... Should we do timesheet entry removed or timesheet submitted? Which one is more important? You are the business owners. Which one should we do? Any suggestion? Timesheet submitted or timesheet removed? Timesheet submitted or timesheet entry removed? All right. Let's submit our timesheet. So in this case, this is the button we are interested in. So we add our entries. We would have to provide a read model to have these entries displayed here. We haven't done this yet. So this is a missing slice. But we are now focusing on submitting the timesheet. So what I would do is I would mark this timesheet, the button here, so we know we can now submit this timesheet. Amazing. Now the event that is necessary here is timesheet submitted. And we only have one thing here, which is the timesheet ID. We don't need any other information to submit a timesheet. That's all we need. Let's just rename this to ID as we did in the other ones. So now what needs to happen for this timesheet to be submitted? Well, as always, we need our command. Let's define the command. The command is named timesheet submit timesheet. We go through the system slice by slice. We discuss every slice and at the end you have described all the slices in all details and you should be able to basically implement each and every slice independent from one another because typically these slices, they are independent. You can implement them in isolation, depending on the architecture you choose. If you use a slice based architecture, you can really implement these slices in isolation because they're very, very small building blocks. If you want to know in detail how that works, it's described in my book, the whole process. And there are also many, many videos on LinkedIn where I talk about this concept. So in this case, again, we would just connect the elements, trans-read, information completeness check. And we can do it like that. That's a slice. Again, just select all the elements, make it a slice, make the slice equal high. Now we need to discuss what is the effect when a timesheet is submitted. For example, we could say as soon as a timesheet is submitted, I can no longer select it here. How would you model this? So depending on who works on the event model, sometimes you will add a new. timesheet here as a copy of this timesheet read model to showcase how that works. I often do this. But what I also do is and this is something not every event model does. I also connect this event back to this timesheet read model. So I clearly see, OK, there is a dependency between this event here and this timesheet. And this is the only type of back arrow I allow in my event models. if an event further to the right has an influence on a read model to the left. That's the only back arrow I allow in my event models. Everything else is just straightly turning to the right. So you can read it from left to right. The only thing here is if an event has an effect on an earlier read model, I allow this back arrow because sometimes it's just easier to do it like that. Now the question is, can we use this information in our prototype? So it should be able to we should be able to play around with this functionality. I can use the projection in my read model. So you just say clear here and it adds all the events that are dependencies and you can also use the AI. The AI can write the necessary code for you. So you can just say timesheet submitted removes it. That's all you need. The AI typically does the rest. Save it. And now what we should be able to do is add a timesheet, submit this timesheet and the timesheet should be removed from this list. Basically, let's see if that works. So let's refresh here just to be sure. We add a new timesheet using our this ID, Martin's timesheet. It's info at nebolit.de and my period is this. Did I forget something? Oh yes, I forgot to add it to this. Model context. Here's my button. Now I can submit this timesheet. Let's do this. I just need the ID. We just model the ID and you see it works. The timesheet is removed from this projection. The only thing I have here is I have two events in my event store. Timesheet added and timesheet submitted. The system knows how to work with these events. If you look at the projection, it's very simple. The projection of this read model, it's basically a left fold, exactly what you do in event sourcing. You have two events, timesheet added, and timesheet added adds an entry to this list. And timesheet submitted removes the entry from this list. This is what the AI wrote for us. It's just basically just as a filter on this list of timesheets displayed in our projection. Very simple. And it basically removes this submitted timesheet again. So whenever someone submits a new timesheet, you have this timesheet added event, which adds an item to this list. And whenever someone submits a timesheet, it's removed from this list. And in the end, you have always a list of active timesheets in your system. Very simple. So we have four slices defined. Of course, we could again define our given vendors for our system. Now, what we should do before we start doing a little bit of code generation, we should check is everything correct here because on the first look it looks fine but you can use the validation it just saves a lot of time validations are done on the first screen here and we see there are quite a few validation errors here i made a few mistakes modeling here so let's see what happens we have an arrow in add timesheet which is the first one what's the what's the problem here there's a problem in the event we haven't defined an id attribute that's correct all right let's fix this It's just a few hints that help you if you want to use something like code generation You need to be very specific about the data. You need to define what is what is the ID of each element? You need to be very specific and this validations they just help you a little bit so we can just say the ID attribute of our timesheet added event is the ID Let's see if we can get rid of all these validations Yeah, first one is gone Oh, there are even more. Submit timesheet has also some problems. So what's the problem here? Timesheet submitted has no ID attribute. Let's fix this one. I might also add a little bit of AI to this to resolve these problems automatically. That's already planned. But for now, you have to do this manually. But it still helps a lot. The command is maybe the same problem. Exactly. Submit timesheet. Just correcting a few of these. So screens are not important. So we have another problem here in the timesheet added event. What's the problem here? Also no ID attribute. We can jump directly to this one. And the ID attribute here is the timesheet ID. All right. Hope we have it. And there is one in the command. Command is the same problem. Also missing the timesheet ID. Yeah. All right. Great. Let's check. Yeah, there's only validation problem in the screen. Screens are not important. So for now, it doesn't look too bad. Now, what we can do now is we already have modeled our slices. We've played around a little bit with our prototype. We can generate a little bit of documentation. So what is documentation? If you work with an event-driven system, there are many ways how you can build up your documentation. But... it's very, very crucial to keep it up to date. So code generation and documentation are really a match made in heaven. And I love to do this using code generation. And one of the best tools to document an event-driven system is Event Catalog. Not sure if you know it, eventcatalog.dev is an open source project. Here is a filled catalog just as a demo. And it's freely available. I think it's eventcatalog.dev. Yeah. So it's freely available. You can just use it. And I have a code generator that can just generate basically a fully filled event catalog. Event catalog also has its own code generators. You can use it to basically generate it from open API specifications and stuff like that. So there are many, many ways to do it. But I like to do it directly from the event model. because most of the time this makes really a lot of sense. So let me show you how that works. Let's generate a small event catalog. For this I can just create a configuration here and jump back to my terminal. So the code generator, you can run the code generator directly in the terminal by running gen. If you want to know how this works, there is a full email course that guides you through this process of building your own code generator. So basically it works you through an example of this. So if you you will get a link to this email course, you can just subscribe. It's completely free. You can play around with these code generators. And there are a few code generators available that you can simply use. One of them is the event catalog. Let's see if that works with our event model. So what's the project name? Timesheet. Render the app. Yes. So it creates. That's not too much. Should be a little bit more than that. Oh, I think it. I made a mistake. Timesheet should have said no. Let me quickly check. It should be fine. Let's see if that works. Let's do an npm install. So basically what happens here is the application generates a meta model directly from the event model. So what you see here is a big, big JSON file that gets generated with all the information and all the relations in the event model. And you can use and build your own code generator based on this meta model. basically to generate documentation, to generate production code, whatever you want to do. If you subscribe to this email course, it will basically guide you through a simple TypeScript example that simply shows you how to build your own code generator. Nothing complicated. So here's still a little bit of NPM install going on. Let's see if something worked. NPM run dev. So should be on localhost 3000. Shouldn't be that empty. Why is it empty? Something's missing. Not sure what. Turn the code generator again. Oh no, something is missing. Not sure what is missing. It should be able to generate it. Seems I'm missing something. So what it would generate is something like this here. It would basically generate the event catalog here. You would see the events. You would see the commands and you would see the relations between them. So you have events, services and domains. And this is basically, this is the example from my book, the book Understanding Event Sourcing. And there is an example using an e-commerce system where you have different relations. You have a card domain, you have a product pricing domain and the product inventory domain. And this basically shows you how these relations are. And this is basically what gets generated directly from the event model. I don't know why it doesn't work right now. It seems I missed something. I will figure it out later. You might, you will get an, a link to the event catalog. You can look at it, what gets generated from this example. All right. And what you also can do is you can generate production code from the event model. So I use this heavily, for example, to generate Axon code. So I work a lot with Spring Boot and Axon as an event to build event source systems. And you can generate event source systems with Axon directly from the event model. Let me quickly show you how that works. It's the same thing. So we can just say gen, which always starts the code generator. We say we want to generate an Axon application. So let me quickly add a few meta-informations here so I don't have to put this in. So we can just say this is the timesheet application and my package to generate to is the enabulate. That makes it simpler in the code generation. So Axon. Now, it doesn't ask me anything because I provided the meta information. I can generate the skeleton. The skeleton is a full-fledged and fully configured Spring Boot application, which is directly startable. So you don't have to do anything. You can just start it. It's a perfect playground to play around with event sourcing and simply start to learn how it actually works. But it's not enough. We need... Oh, I forgot something. We need to define... To work with Axon, we need to define... the swim lanes for our events. We didn't define any swim lanes. So for this, we need to define which of these events here belong together. And for our simple application here, we have only one swim lane. So the swim lane here is basically all these events here belong together. They form one swim lane and the swim lane belongs to an aggregate. So we could name our aggregate here. For now, it's just timesheet. So there's also a little bit of AI in the background to guess the correct thing. The AI decided timesheet would be the correct aggregate for this. And I would agree for the second. And I would also say we just need to adjust it a little bit. For example, let's say we need the ID attribute here just to be consistent with the rest of our modeling. So we have the timesheet aggregate in the swim lane and all the events in the swim lane basically belong to this aggregate. That's fine. And let's see if we can generate the aggregate. So you have basically three things you can generate here. One is the skeleton, which is the basic application that you can start, but without any slices, without any aggregates, just the basic application. So then you can generate the aggregates. And in our case, we only have one aggregate. We just defined it. It's the timesheet aggregate. And then it asks you, hey, should I generate your command and event sourcing handlers directly for you? In this case, yes. That would be lovely. Thank you. Overwrite existing aggregates. Yes, but we don't have any. So it creates the timesheet aggregate. What we generate here is Kotlin code. So it generates Kotlin code that you can basically directly implement. If you want to generate Java code, it could be easily adjusted. But right now the code generator just generates Kotlin code. And then we have now our basic application and we have the slices. We have the aggregates and what is missing is the slices. So it asks us, which slices do you want to generate? Well, all of them. And what it does is it basically generates a whole lot of code for the different slices. It generates test cases. And basically now we are good to go and we can have a look at our application. Where did we do it? In timesheet. No. What did I name it? Oh, I generated it directly into my temp folder. That was a bad idea. Let me do this again quickly. My timesheet.axon application. Just quickly regenerating everything again. Oh, it doesn't work. Why not? Oh, because I need the, of course, I need the code file here. Now it works. So generate the skeleton, generate the aggregates, generate the slices. That's much better. And now I can just open this in IntelliJ. And I want just to quickly show you what gets generated and how it works. And then we will jump to the Q&A. So what you see here is basically a slice-based architecture that gets generated. And you will see for every slice in our event model, there is a slice and a package in our system. So we have an addEntry slice, which becomes a package in our system. There is an addTimesheet slice, which also becomes a package in our system. The packages are guarded by SpringModuliv. So all these packages, all these slices are completely independent from one another. The only dependency between slices is the events. which define the contract and the aggregate, which basically defines the business domain. This is the only thing that is common between these slices. Every slice defines exactly what we do in the event model. So the code is basically a one-to-one mapping from the event model. That's one of the big benefits of using event modeling. It's very easily mapped to code. So for example, looking at the add timesheet, what we have here is a rest endpoint that gets generated. And also at timesheet, we have a command that gets generated. So looking at the command here, it's really exactly what is defined in the event model. So we have our attributes here. We have always this link back to the event model. So you can easily jump between the code and the event model. And basically that's it. That's our command here. And looking at the aggregate, we have our command handlers. So command handler here basically with our add timesheet command that gets handled. And also this is the axon code. So basically here, no logic. It just you get the add timesheet command. The only thing that happens is we have the timesheet added event that gets stored in our event store. So let's see if that compiles. Most of the time it works just well. Sometimes you need to adjust a little bit depending on how you model it. But Typically, it works quite well. Let's see. Yeah, compiles. Now we start the application. Just need to make sure because what it's using is by default under the hood, a Postgres database. I just want to make sure that the tables are created automatically. Let's see if it starts. What it generates basically, it generates a REST API for the application. It generates all the command handlers and you can basically start to work with the application right away. So typically, if I haven't done anything significantly wrong, we should now have our Swagger API that allows us to access the application. We have exactly our slices. We have the add timesheet. We have the add timesheet entry and basically allows us to work with it. So let's see if I can add a timesheet here. out of the box. Martin, not yet. Something seems to be wrong. The aggregate was not found in the event store because I haven't configured which aggregate creates the... which command creates the aggregate. That was a modeling error of mine. So let's say we want to create a timesheet and I need the command for this. So we are here at timesheet. I need to tell Axon that this is the command that creates the aggregate and we say creative missing. Let's see if that works. And you would also find this error in a test case. So if you look at the test cases here, the timesheet test case does exactly what we defined. It basically sets up the system, fires the command into the system and expects the event to be stored. We can even try. Let's see if we can execute this test case here. That works. So now that I defined basically it, this is the first test case that got generated and it works. So it's really you always start with these test cases. And if they are green, you can be pretty sure if you modeled correctly, you can be pretty sure that the application does exactly what it's expected to do. So just one more thing going back to the UI. Let's see if I can now submit my command here. Yes, that worked. So the command is executed. This means in my database is now an event stored in my event store. And maybe I even made my projections correctly. Yes. So you see, this is basically the first projection under the hood. It's a database projection. So it uses the events that get stored and projects them to a simple database table that gets displayed here. So we have now basically a fully running Axon application and we can start to... play around, implement new slices or implement new specifications. And this is basically exactly the process I typically go through in a project. You work slice by slice. You don't have to define the full model to get started. Basically, you define the first few slices in detail, including the given vendors, and then you can just start. And this allows you to get really, really fast in a project. And since these slices are independent from one another, you can implement them in parallel. So this is a perfect tool to scale your development. That was a lot of information. So we are way into the webinar. I talked a lot. Do you have any questions? Anything we should address? Feel free to ask. Just shoot them out. Don't raise your hand. Just shoot them out. okay what happens if i have several swim lines yeah how does that doesn't look like yeah they're a very good question so if you look uh to the very bottom on the board here there are a lot of resources linked and one of the resources is basically all the resources around my book understanding event sourcing and if you click on this link here it brings you to the myro board of this book which is An event model that really looks like it would also look in the real world. And here you have several swim lanes. Here you have the card inventory pricing swim lane. And this shows you how they interact with each other. Great question. Other questions? It would still be great to have access to the Mara board. We've tried a couple of times in different accounts, but it doesn't seem to work. That is really a pity. So I will definitely check why it didn't work. You will get a link. The Myrobot will stay as it is. You will get access to the Myrobot and you can definitely access it later. the live prototyping that you do is that who's most interested in that is would that be the uxers the the business people or the engineers as well no this this is really um most of the time it's it's basically we use this really in the modeling sessions very quickly so it's it's the engineers just to verify is the model really working so what you can do is you can you can define for the screens uh styling a little bit but it's not enough so that ux is really interested it's not You cannot get it look really good. So it's really it's a verification tool to quickly verify does the model work. That's the main use case. Martin, one question. So am I thinking that some of these slices are vertical and some of them are sort of diagonal, you know? Diagonal? Yeah, like the slice that feeds the read model. like from the event yeah to the rig model it's like a diagonal from bottom left corner to it yeah yeah it's just basically it depends on on how you see it so for me it's always the slice that creates the event is responsible for the event so this event is part of the of this slice here but of course the next slice is using this event so this is basically the common contract between these two slices so how would it work if Two developers work on these slices at the same time. They just agree on, okay, who creates the event and maybe you do it directly on the main branch, for example. So both have access to this event or you simply copy it over between branches because these events will look the same on both branches. There will not be a conflict. So it's just a matter of what slice do you assign the event to. For me, it's always the slice that creates the event. This is basically the owner. some idea of where the slice would be for the error case that's created in the third slice here where do we go with that yeah the error case it this really depends on um how would how you would do it so what you can do of course is you could just say um for this case here um i want to simply display an arrow to the user So in this case, this would not be a slice because showing an arrow is not something that changes anything in the system. So you could just say there is a new screen here, which simply shows a beautiful red arrow message. And I would do it like this. Linking the screens here and just showing, okay, sorry, didn't work. If there is a follow-up process because of this arrow, typically the arrow, Typically it's not an error. So typically you would have something like a timesheet entry added failed, adding timesheet entry failed, for example. And then you would have a follow-up process that basically works with this event. So these are the two cases how you can work with problems in your system. Either it's a clear error where you simply cannot do anything and there is no follow-up process. Then it's this red sticky note simply showing, okay, that's an exception. I cannot not do anything here. But if you have a follow-up process, it's typically always an event that gets stored and then you have processes that work with this event. These are the two cases. And then you would have slices for it. For this error case, no slices, typically. Which people do you include when you are discussing all the details, all the given events and technical details, like IDs and stuff like that? Does that change over time? Yeah, it does. It does indeed. So if you look at, let me quickly uncover the different phases. So the deeper you are into these seven phases of an event model, the less people typically join. So you always start in the brainstorming first session all the people should participate the more the better also in the in the In the timeline building The more you the deeper you go into this step three is defines screens step four is define apis and commands and read models and Step six already and talking about different lanes at some point in time you will focus on one specific area. And this is basically the specific area we call them chapters. So chapter is basically you see it down here. You would say, OK, in this session, we focus on product. This is all these blue arrows in this session. We focus on product and then only the people relevant to this context will join the session. So maybe you will only have five or six people, two developers, two product people and maybe one one of three. And then you can discuss these slices in detail. And to define the give and when thens, you need the business people because they have the knowledge, they know the business rules very well. And if there are questions, you need them in these sessions. Typically, before a slice goes into implementation, there will be one short session with only developers. And there you really go over the attributes again. Do we have everything? No questions. Everything great. Then we can go into the implementation. It's basically like the last refinement meeting before you get to a story into a sprint. You can compare it with that. Thank you very much. Martin, is it common that you have two events from one command? Common? No, no, it's not common. It can happen, but I try to prevent it. So most of the time it's a one to one relation, but it's not forbidden. You can have two events, three events from one command. It's possible. But I try to prevent it as much as possible. What is the advantage then to have multiple events? What is the effect? The effect is always that you have basically... Well, it's not forbidden. So it's much easier to reason about a system if it's a one-to-one relationship. It's easier to think about it. You have one command and you have exactly one thing that changes in the system. Sometimes you cannot do this. Sometimes you need more than one event. But most of the time you don't. Right, please. Which pattern? The automation. Oh, not today. Not today. So for this, there was unfortunately, was not enough time. Automation pattern is basically whenever you have something like a background process. So quickly, I can give a very quick example. So for example, here in our event model, we could say whenever a timesheet gets submitted, there needs to be an email sent. to someone else. So an automation pattern here would be we could first thing we would define is, OK, what is the event? So we could say the event would be, I don't know, something like notification sent, something like this with an email, for example. And then what you would do is you can just say, OK, this is an automation. You can use the one click modeling for this. So this would just create this automation for you. And this would basically look like this. And then you could say, okay, for the timesheet submitted event fills this read model here. And this again is one slice. So you would just say, okay, this is one slice here. So automations is, we would need to talk a little bit more about automations. There are some subtleties here, but this is described in extreme detail in the book. So that's an important thing, but I intentionally skipped it for today because I really wanted to show you the whole process a little bit. But if you have specific questions, just DM me on LinkedIn. I'm happy to talk to explain something if you have questions. Where is it? Where is Dennis? Okay. Yeah, do it. Yeah. for scenarios where a field included into the event is not in the command but calculated as a result of the command ending. I think that is a really interesting one. You can always say that a field is generated. So for example here just looking at the event here the email if we would remove the email from the command here you can always say it's generated and generated basically disables the validation because the system then knows okay I as a developer, I know where this is coming from. The system doesn't, but I trust the developer. So in this case, the validation is disabled. This is how you would do it. Martin, I wanted to mention that it's very cool that you showed us this age step schema, how to approach the AMM modeling from the picture to narrow down. Super helpful. I was looking for something like this. Now you have it. Thank you. Anything else? so we are we are already over time but i'm happy to answer any questions you have so feel free to keep asking i got a question yeah um i was wondering um for this timesheet example that we have built in the session how would we model something like um let's say we build a SaaS with subscriptions and we have different plans and based on a plan we can let's say we have a basic plan where you can have up to three subscriptions every time sheets a premium with up to 10 and things like this how would how would we model something like this into into the event model what you would do here typically is you would most probably start with different actors So you can, for example, say there's the concept of an actor, which is basically like a swim lane for something like a buff. And you could say this is a premium user with a better subscription. And you could also say we simply model the different flows in different models. So you could say in this case, for this model here, we model exactly the premium case. So you wouldn't model this all into one thing. It would be different models and different flows. Maybe reusing some of the slices, but in general, you always focus on exactly one flow for the user. And if there are different flows, for example, for different subscriptions, typically these are different models. But we would have to look at that in detail. So just based on what I've heard, that is how I would approach it. Okay, thanks. And when it comes to the decision making, so if we take the very first slide where it says add timesheet, where would we actually perform the check whether this particular premium user reached its limit already or not? Would this happen before in a different slice that is responsible for checking such constraints or would it go into this one somehow? So in this case, either it's basically it's happening in the infrastructure or if it's really business logic that you want to execute it would happen basically here in in the command handling there you have your business rules and there you do these kind of kind of validations okay thank you a question regarding our aggregate like these slices seem to be like they stand on on their own but the code which is in aggregate seems to be shared through the slices so my question is how do you deal with the like the code you use in the aggregate or with other strategies yeah the the aggregate is basically the only thing that is shared between between slices because currently using axon for example it's almost impossible to not do it like that but in the next version of axon for example there will be the concept called dynamic consistency boundary And with dynamic consistency boundary, it will be possible to implement these slices in full isolation. There will be no aggregate. Aggregate will be gone basically from this concept. And you can basically implement slices in full isolation, which will be hugely beneficial to this concept. Then you have truly uncoupled them. Right now it's hard. You always have this aggregate as a common dependency. Which other frameworks are there besides axons? also though i have heard you actually you don't need to have a sourcing uh that database yeah so you don't need you don't need a framework for it but it's beneficial especially if you have a team inexperienced with event sourcing then i i would not recommend to to start uh without a framework because what you will do is you will spend all your time building a framework. This will be the effect. And I would not recommend it. So depending on the stack, there are a few frameworks which simply help. So for example, in the .NET space, I think it's Martin and Wolverine. These are two frameworks which simply work. But I typically, I focus on Spring and Axon because I'm on the JVM. I work with Kotlin and Java. And this is basically my go-to framework because it simply works. Okay. Okay. In .NET. world yeah in in dotnet um what many many customers use so i i don't work in the dotnet i'm not an expert but i have a few customers that work in the dotnet space and many of them either use event store db which is now called current or they use cosmo db cosmo db is very popular as an event store okay i cannot tell if it's if it's really a good fit i'm really no expert here okay Okay, you don't know details. No, no, I don't. But I know a lot of my customers use CosmoDB as an event store. So it seems to work, but I'm not involved in that. So I simply know they do it. I have no details. Okay, okay, thanks. Any other questions? Martin, okay. Yeah. Martin, when shall we expect to, when are you going to plan to have a follow-up session talking about the others? Oh, we can do that. I typically I do one webinar per month. So we can we can do it next month. So would you be interested in talking about automations and stuff? Yeah, I do. Yeah. Yes. All right. Then we could do it next month. So I typically I do one webinar per month, always announced on LinkedIn. I really try to do it at least once per month. And there will be a workshop at the end of February by Adam and me. where we will also basically go through all these patterns. It's called event sourcing for beginners. It's a beginner's workshop for event sourcing. That might also be a good fit. All right. Anything else? Yeah, I had a question about... One of the questions before was about additional constraints. For example, like, oh, if you're a premium user, then... you know some other checks or some some other conditions have to be satisfied in order for the add timesheet to go through yeah but then how how would you model that you just put like a comment next to the the command or or how do you how do you put that on the model uh we would really have to look uh at a detailed example here so um typically you try to explain this with a given when then so either an event could for example be the question would be how does the system know that that you are in a premium subscription. So you could have an event which is simply called premium subscription activated. And you are given when then. This tells you exactly, okay, we're now exactly in this case. So you cannot just put a sticky note somewhere and say, we assume the user is a premium user. You need to tell exactly how does the system know? Where does this information come from? And this could be, this will almost always be an event. So, which event gives the information that we are now in a premium subscription case? And then, if you have this, you can describe these rules very precisely using the give and when lens. So, I would not add any sticky notes. I would really be very, very specific. If you stay vague, you're back at the beginning. We are not... doing anything wakier. This is really, we are going into the details where it really, really hurts. You discuss the very details of the system right at the start. This is the big benefit of this approach. Does that answer your question? I'm not sure. Yeah, I understand. It's just, for example, there, at least from what we do is we have like all these like services, right? And so we have like one service responsible for kind of like managing tenants. users within those tenants have certain permissions and so we have many many models of different areas of the system yeah but it also wouldn't make sense for us to have to replicate the oh like the user would added this role in this tenant or so and so forth so we're kind of trying to kind of remove the duplication there um so sometimes it helps to kind of be able to say hey like this is assuming yeah derivation towards memory that will help the assumptions being made yeah um and also sometimes like maybe this is missed is external so you don't really have the events Yeah. Yeah. Got it. So what I typically do in this case is you can start the flow with assumptions and the assumptions then are typically what I start with. I have a read model which says, for example, locked in premium users. That's what I was looking for. Yeah. So basically you always start your flow with something. Either it's an event that starts the flow. This could also be an external event. So you could you could have an external event that says premium user authenticated. which could come from a completely different system, but this is the starting point of your flow. Or you simply assume this is my locked-in premium users and maybe this is filled from a database. It doesn't really matter. But you know we are starting with this data that is already present. I think that is what you're looking for, right? Yes, right. But then there's the case where, okay, we now have to come up with fake events for systems that we don't control. Yeah. you know often having to explain to others no we don't actually have this I just have to put it here because of the model from Anzic that also sometimes becomes kind of like a like a crutch in a way so I do but I do kind of like the hey we're just gonna throw this read model in here it has this data yeah how it got that data doesn't really matter to what we're doing but would you consider that acceptable absolutely I do this I do this so this is typically whenever you start with something that is external I often start with these read models it's just you shouldn't it should be clear if you have this read model and there is nothing connected to this read model for me it's always okay we are starting with this data and we don't care where it's coming from what you also can do um using this tooling is just you can say okay this is if you want to be very very specific you can just say okay i want to add um where is it a table here so there's also the table reference here you can say this is a table and this table delivers this data and you can really define the schema of this table here. But it's possible, but the read model alone is typically sufficient for this use case. That makes sense. So how do you indicate, because I see we're dragging it now to the screen, right? And then the screen goes to the command. How do you make it very clear that the stuff that goes in the command or at least what is processed by the command comes from that read model? Well, what you see here is, you would define the fields here. You would define if the email and the name comes from this remodel, it's here. Name and email. It can only come from... I suppose you would have like, is premium boolean or something. Exactly. For example, if the UI needs a boolean flag to indicate it, then you would have a boolean here, premium user, which is a boolean. So, I would really... very clearly define exactly the data that we use to start our flow. So that we do not make any assumptions. We shouldn't make any assumptions. It should be very clear where this data is coming from. But so this is kind of where we go into the difference between the model and the implementation, right? Where when I'm processing the command on the backend, I would not trust the user to send in the is premium as a boolean. Like you would fetch that from the read model in the... Absolutely. absolutely so whereas what we're displaying here is the the view feeds the the screen and then the screen is what sends all the information needed yeah through the command right but we're kind of missing that extra hey like the command also reads from the view yeah what you can do what you can do of course is you can connect the read model directly to the command i typically don't do this so only because the read model is connected to the screen doesn't indicate that the data is also flowing through the screen it could also be that the command has just Before the command gets processed, it reads from a table and reads this data. So this is basically what this model indicates. I'm typically not connecting the command to the read models because it gets a little bit confusing then. I like this clear data flow. And we are not modeling implementation here. That is very important. We are modeling the information flow. And for this, it doesn't really matter if the information goes through the screen or to the command. so but there's kind of like mixed opinions on that like are we modeling of course you know or the implementation right and obviously if you're trying to coach and you know your coaching is going to get more efficient the closer to implementation the model is absolutely yeah so yeah that is also cool that is also very important so what you hear what i'm telling you is my opinion based on my experience from event modeling for a few years with many customers It's not absolutely not the truth about event modeling. Ask someone else, even ask Adam Dmitryk. I work very closely with Adam Dmitryk, but we are not we do not agree on everything. So I model things differently than Adam, which is absolutely fine. As long as you within your team, you should just define the rules. We model like this and then just do it every time. And then then it's fine. Yeah. Gotcha. Thank you very much. My pleasure. All right. So we are also, we are way over time already, which is fine. So let's wrap this up. I really hope this made a lot of sense. I hope you had a few nice impressions about how this process works, how you can work with event modeling. If you want to go deeper into it, just grab the book. I can really... recommend it because I've written it. But many people told me it's really a great book. It's a good read. So maybe give it a try. It's available on LeanPub. And there is also this little book here. It's directly linked here. It's freely available, which is basically like an FAQ for event modeling. I add small chapters to this book all the time. Whenever there's a question in the community, I add it to this book. That might also be a good fit. And of course, if you want to work with me together, you can book either the online course, which will be available very soon or book a workshop with me, which is also possible. After you will get a message on LinkedIn with all the information, including access to the board. So if you couldn't access the board, I'm very sorry, but you will get access. You can just look at everything and nothing will change here. So this board will stay here for quite some time. So I really hope this made sense. And then I think that's all for today. So as I said, I try to do one webinar per month. So yeah, maybe next month we will talk a little bit more about automations and the background processes in our system. So for that, thanks for joining. It was a lot of fun. And yeah, I hope it was worth your time. Thank you. One short question. We may use the event modeling toolkit. Yeah. Okay. You can just install it. It's freely available. So you won't have all the features. So code generation is commercial, but the basic features are available. It's just here. You can go to the marketplace. Just look for event modeling. You can just install it. Thank you. All right. So I can stay here if you still have questions. I'm happy to answer. But I wish you a very happy rest of your evening or day wherever you are. Thank you very much. Bye-bye. That was the webinar. I intentionally named it Full Circle because I wanted to show this whole process in as little time as possible. I hope you learned a lot. And as I said in the introduction, if you want to work with me, feel free to contact me. I'm very looking forward. hear from you i'm martin ceo of nebulit and i'm sure event modeling will change how your team operates
⚙️ Pipeline jobs
| Stage | Status | Att. | Updated | Error |
|---|---|---|---|---|
| download | done | 1/3 | 2026-07-20 15:14:16 | |
| transcribe | done | 1/3 | 2026-07-20 15:15:12 | |
| summarize | done | 1/3 | 2026-07-20 15:15:53 | |
| embed | done | 1/3 | 2026-07-20 15:15:56 |
📄 Описание YouTube
Показать
- This webinar introduces Event Modeling, a structured approach to improving communication between development teams and business stakeholders. - The session walks through a typical software development process using Event Modeling, from loose requirements to generating production code. You find the tooling used in the Video here: https://nebulit.de/eventmodeling-tooling There is a complete 4+ hourse Online Course available, that walks you step by step through the process ( and comes with Miro Toolkit License attached) : 👉 https://eventsourcingcourse.com Read the book: https://leanpub.com/eventmodeling-and-eventsourcing Subscribe to the newsletter: https://newsletter.nebulit.de Key Topics: 1. Introduction to Event Modeling - Event Modeling improves collaboration between tech teams and business stakeholders. - It helps uncover problems early when they are still cheap to fix. - The goal is to define a common language for the project. 2. Step-by-Step Event Modeling Process - Start with **brainstorming events (defining key system state changes). - Structure the events into a clear left-to-right timeline to tell the system’s story. - Define UI screens to visualize the process. - Identify **commands, events, and read models** to specify system interactions. - Use **an information completeness check** to avoid false assumptions and dependencies. - Implement **business rules using Given-When-Then scenarios** to describe policies and constraints. 3. Live Prototyping & Code Generation - A prototype is generated in real-time from the event model. - Demonstrates an event-sourced system using Spring Boot, Axon, and Kotlin. - Generates documentation using Event Catalog - Highlights a slice-based architecture where each function is independently implemented. 4. Q&A Discussion - Explains handling multiple swimlanes (parallel event flows). - Discusses error handling and how to model business failures. - Covers team collaboration and who should be involved in each session. Key Takeaways - Event Modeling simplifies communication by creating a shared understanding. - Slices make software modular and scalable, allowing teams to work in parallel. - Prototyping directly from the model** validates assumptions early. - Code generation reduces effort and speeds up development. Speaker: Martin, CEO of Nebulit, an Event Modeling company based in southern Germany. Next Steps: - Read "Understanding Event Sourcing" for an in-depth explanation. - Try Event Modeling in your own projects. - Contact Martin for consulting or training in Event Modeling.