Domain-Driven Design and Clean Architecture in PHP — Part 2 (Event Storming)

Andrew Pogulailo
4 min readAug 28, 2022

--

Photo by Parabol

In the previous part, we dealt with the structure of Domain-Driven Design and Clean Architecture layers and directories. But there are still many questions. How do correctly define bounded contexts? How to correctly build system behavior? How to avoid unnecessary dependencies in the system. How to build a Ubiquitous Language? In this part, we will answer these questions using Event Storming.

What is Event Storming?

“It is not the domain expert’s knowledge that goes into production, it is the developer’s assumption of that knowledge that goes into production.”

― Alberto Brandolini, author of Introducing EventStorming

As developers, we usually only think that we know what is happening in the domain. And in fact, we are only making assumptions. Event Storming allows you to explore the domain together with experts, and build our system carefully and without assumptions.

Ubiquitous Language is also built during Event Storming sessions. Experts and developers must communicate using the same terms, it greatly simplifies communication in the future. Therefore, we must write our code using terms from our Ubiquitous Language. For example, if experts refer to the end user as Reader, then in the code we should also call this entity Reader, and not Customer, Client, User, or something else.

We all write code using English, but not everyone on the team speaks English to each other. If this is about you, it may be difficult for you to understand exactly what Ubiquitous Language is and its advantages, because you will still have to translate the terms from your language into English. But that doesn’t mean you don’t need to do it.

What are Reactive Systems?

As we can understand from the name, Event Storming focuses its attention on events, so let’s figure out what a domain event is and why we need them.

A domain event occurs as a result of the execution of a logical block of code. For example, after creating an account in the system, we publish the Account Created domain event with useful information. And if in the future we need to do something after creating an account, we will not have to change the account creation code, but instead, we will only need to subscribe to this event and execute the code after this event is published.

For example, we need to send an e-mail with a request to activate the account after creation. We simply subscribe to the Account Created event and send the email.

Systems in which actions can be triggered not only by the user but also by reacting to some events are called reactive.

Building blocks

Domain event

A domain event is the result of some action in the system that took place earlier.

Command

A command is an action in the system that must be performed. Commands can be initiated both by the user and as a result of a reaction to another event.

Actor

The user who initiates the execution of the command.

Aggregate

This is an entity or a set of entities that executes a command and generates a domain event. Choosing the right unit is probably the most difficult part of the Event Storming session.

Modeling our system

Collecting domain events

To begin with, we need to collect all domain events that may occur in our system.

Collected system domain events

Add actors and connections

Next, we need to add commands that precede domain events, and actors that call these commands. We also need to add links between our events and the commands that precede them.

System domain events with commands and actors

Add aggregates

Next, we need to add Aggregates to our domain events and commands.

Domain events, commands, actors, and aggregates

Separate bounded contexts

We see that separate contexts that we can highlight have already begun to stand out.

System bounded contexts

Сonclusion

This is the second part of my series of articles on Clean Architecture and Domain-Driven Design in PHP. In this part, we got acquainted with the basics of the Event Storming technique. We allocated Bounded Contexts for our system and built our Ubiquitous Language which we will use during implementation.

In the following articles, we will implement our system using Symfony, implement the SPA frontend using React, and deploy our application using Kubernetes.

So subscribe and don’t miss the next part.

--

--

Andrew Pogulailo

I specialize in developing high-load systems. I'm passionate about using my skills to create innovative web solutions that drive business success.