Design the unknown (with the help of Event Storming)
TL;DR: Event Storming workshop can be used to start working with a new project, even if not yet fully defined. It can help to identify bounded contexts and modules which will allow developers to design better systems.
You may know this feeling: a new project is on the horizon. It’s completely different than the current application, but at the same time, some parts of it will be reused. You know that just throwing more, different things on top of your shiny monolith will bring technical debt that will cause you pain and tears in the near future. You need to do something before it’s too late.
The answer that might sound obvious is that we should plan ahead. We might want to identify bounded contexts in our new part of the application, to implement them independently, and prevent the coupling of different components that would paralyze our movements as we proceed. Another thing is that we might want to split the work between multiple teams and we don’t want them to stumble upon each other, creating conflicts, both in code and interpersonal. Ok, that sounds better.
But… how do we do that? Our product managers are Agile and want to iterate in small steps. There is no confirmed road map, everything is subject to changes and our assumptions are validated as we go along. We are handling the Unknown <scary background music>. Or to put it another way - the yet Unknown.
Here comes the sun
The shape of the final solution might be unknown, but surely we can use our brains and imaginations to discover the possibilities ahead. One of the tools that can help us with doing that is the Event Storming, a workshop defined by Alberto Brandolini in his book available here.
We might not be able to use it the “classic” way, described in the book, firstly because it involves a big part of the company working together to understand the current processes in the company and secondly because ideally it should be done physically, not online. However, in the age of global pandemics, even the creator realized that there can be some compromises and the format of Event Storming can be adapted to remote work (see this article).
That’s what happened in our case.
Ahead of us, there was a new, unknown project for “flexible testing”. We wanted to be able to work on it fast, at the same time avoiding the complexity of our legacy code. We wanted to be able to split work effectively, but we did not exactly know the problem area we would be working with. We adapted the process to help us discover the area of problems ahead of us. If you’d like to visualize it using Brandolini’s categories, this Event Storming would go somewhere between the Big Picture Event Storming and the Process Modelling Event Storming.
Present the heroes
Ok, but wait a minute, not everybody is familiar with what Event Storming actually is! Let’s take a look at the basic elements of it.
As first and foremost here comes the Event, giving the name to the Storming. This little guy is represented by an orange sticky note that contains a verb in the past tense. Yes, the color is essential, as it gives a common understanding and saves us precious time on identifying the content for a sticky and distinguishing it from other elements. The verb on the sticky note should express an important change in the process that we’re describing, should be embedded in time, and may include some extra information.
The Events are not hanging in the void. They should be placed on the horizontal board, ideally not limited in size, that will represent a timeline. If done physically, the board could be a long and big paper roll attached to a wall. In our case we used the Miro board.
During the workshop, we will be introducing more types of sticky notes. Most notably, we will use red sticky notes, representing Hot Spots - doubts, questions, problems, missing branches of the process, or points of dispute. As you may guess, when we’re dealing with the Unknown, there is a huge potential for Hot Spots. Other sticky notes may be introduced if it serves a purpose of better common understanding, but we need not use them at all, so I’ll skip them here.
Having these simple, but powerful, tools in our backpack, we begin our journey…
Chaotic exploration and enforcing the order
First, there was chaos. And we also start from chaos.
At the beginning of the workshop participants “storm” the events by placing them on our board wherever they see fit. We want to collect ideas from all the participants who would probably have different amounts of knowledge and use different words. That’s fine and that’s what we want.
It’s very useful to add colored tags for people on each sticky note, as it will allow us to save time when trying to identify its author (yes, I mean the 200 times when you would ask “Who wrote this note?” during the meeting). In the real world, handwriting would serve us as an identifying element, but with tags, it’s even easier (at least until we run out of the available colors).
Then there was a workshop facilitator, and the order emerged.
Now it’s time to order our Events. Most importantly we should enforce the timeline, i.e. order events one after another. We could split our ordering into several steps, like finding duplicates, grouping by topic, etc. There might be more than one process showing up on the board, so we might want to distinguish events from different processes. In our case though, we decided to do it all in one step.
During the physical workshop, it’s much easier to engage people and the facilitator’s role is secondary. He should guide the participants, not push them forward. However, in our experience when the workshop moves online it’s much easier for people to disengage and lurk into the awkward silence. So naturally, the role of the facilitator as a person leading the second phase of the workshop is bigger.
Ok, but how do we navigate the chaos? Where to start? In case we have many events, we might want to identify the first few most relevant from the business perspective, so-called “pivotal events”. They will create anchors for other events, which we will put in between and around them.
And now the real game begins.
The secret behind the effectiveness of Event Storming and also a necessary ingredient for its recipe is the communication between different people.
When enforcing the order of events and therefore visualizing processes in our project, we will get to some common understanding of the problems behind it. People will have doubts about the meaning of words. Some things will be named differently by different people. Thanks to that we will be able to start talking about some definitions. Eg. do we name the process of “testing” as a “test”, “run” or maybe “test execution”? In one team it’s understood this way and in the other team another way? Let’s clarify that!
Our friend here will be the Hot Spot red sticky note together with a question: “And what happens if <xyz> happens here?”. Sometimes it will be a matter of product managers explaining their visions to developers. Sometimes the other way around. And yet in other cases, we will get to a point where nobody knows the answer. This is very important information for software developers as it indicates a part of the system that may change frequently and requires to be elastic.
Pro tip - when doing longer workshops online, make breaks. We tested the model with a 3-hour meeting and one break, and then a 3-hour meeting with Pomodoro way - 40 min meeting, 5 minutes break. Pomodoro worked much better, also helping to resolve some standoffs.
The Big Picture
After two sessions and a lot of juicy discussions we’ve come to an artefact that looked like this:
It is what it is - a big picture of our new project. We can see some major parts of the process, some of them essential, some of them optional. We were able to move aside some potential features. We found common words for key elements in the new system. We also see the number of gray areas that need to be investigated before getting implemented.
Although this itself looks satisfying and we’ve clarified a lot of misconceptions around the project, it doesn’t bring us to the point where we wanted to be. We want to define bounded contexts that can be implemented into independent modules which can be then distributed as responsibilities among our developer teams.
It’s time to press the olives and extract the oil.
Bounded contexts discovery
If you’ve ever read or heard about DDD, you must have also heard about the term “bounded context”. As described by Eric Evans in his “Domain-Driven Design: Tackling Complexity in the Heart of Software” a bounded context is a defined part of the software where particular terms, definitions, and rules apply in a consistent way. He accents the linguistic aspect and so-called “ubiquitous language” that should characterize the bounded context. Each context has its own language, i.e. the same word can mean different things in two contexts, but never in the same context.
As we understand the bounded contexts, there are few more practical consequences that can help us when discovering where the bounded contexts can be defined.
First of all, have clearly defined borders, which describe what are their responsibilities. If they have clear borders, they also have clear points of entries, that we can call API endpoints. They communicate with other contexts through these endpoints. What’s also important is that they do not share data with other contexts. If other contexts need the data, they communicate through the API endpoints to get it.
All of the above has a goal of helping us - this way we make sure that contexts are independent of each other. This means that we can easily substitute a specific context with eg. a third-party service (let’s say an invoicing app).
Using the result of our Event Storming we followed up with a workshop for bounded contexts discovery. We also involved our product managers and it turned out to be a good idea - at this stage, we still had some doubts about the vocabulary used and foreseen responsibilities in different parts of the process. Five Pomodoro sessions later, we’ve ended up with a division for our contexts and names for these contexts.
It’s all fine and all, but you probably don’t see much in the whole picture. Let’s zoom in a bit then:
We’ve identified here a bounded context for Test Launching. It has an entry point which is called when the customer has requested a test. It contains some business logic for validating if a test can be started or not. Then one of the business events will happen inside it - the test is started or rejected. It could mean calling another context to run the actual test or just emit the event, depending on what communication model we will decide on.
This context in its basic form does not own any data but has clearly defined limits with one entry point. If we decide to add more complex logic for validating if a test can be launched or not, we know where to go and whom to ask.
Until now, we were talking about the scope of a whole new project, but we might want to go deeper, to identify which bounded contexts will be needed in the first iterations and what modules we want to create in the code to match those contexts.
At this point, we want to talk about the data that we will be using, which contexts will be responsible for its processing, and which ones will handle the storage. We also want to talk about the communication between the contexts, which ones will be communicating with each other and which can stay isolated. Based on that we might come up with something like this:
Having a collection of modules like above we are finally able to split the work among the teams. It does not mean that the teams will be already independent. To get there we still need to define contracts between the modules - what will be the exact endpoints for each of them, what input they will accept and what output they will produce. We also need to synchronize to agree on data ownership or when we want to update the contracts. But that’s a story for another evening…
When dealing with a design for a new, unknown domain, Event Storming can be used to help us understand the problem’s area, find common definitions, and clarify pain points.
Visualizing the new domain can help us in identifying bounded contexts which will help us to split the system into autonomous parts, easy to develop and maintain. When that is achieved we will be able to define modules for our new system that can be assigned as responsibilities to different developer teams.
Ok, but why not “just start coding”? Well, if you haven’t experienced it yet, the answer might be put in short words - Any design is better than no design. Our initial design of the new subsystem might not be perfect and will be subject to changes. But if we don’t do any design we risk getting a technical debt that we will never be able to pay back.
If you'd like to know more or speak with the author of this post, please contact us.