Photo by "My Life Through A Lens" on Unsplash
Domain-Driven Design for dummies (I)
Domain-Driven Design can have a big learning curve. Let's cover the key concepts and principles.
10 min read
Let's play a little game
Start by whispering something to your teammate, she will whisper what she heard to another colleague, and this colleague will do the same to another one and so on.
When we compare what was originally said and what the last person in the chain heard, we realize the meaning has been completely distorted. Now imagine you order a custom cake, and you call the bakery to give them instructions. A friend of yours has graduated recently and you want a cake with a graduation cap, some flowers, and especially, you want sprinkles, lots of them. When you get the box and open the lid, this is what you find:
Have you seen these situations frequently during your career? I've heard things like:
I once worked with a team to analyse their historical bugs and we found 50% were related to misunderstanding of requirements.
I would honestly say [the project] was like 90% of the work we were doing was fixing ‘bugs’ that were misunderstandings.
Misunderstanding the requirements is just one of the things that could happen.
The code will reflect the misunderstandings, the gaps in our business and customer knowledge, our organization's communication structures (Conway's Law), etc.
The final state of our dysfunctional system could be summarized like this: a big ball of mud.
If you see the development team as a box, features as output and requirements as input, you could say the requirements were wrong.
Many would mention in a retrospective meeting that we should create long and utterly descriptive requirements, covering all edge cases and treating them like a contract. Essentially, the fix is to add more processes and more gates. Locally, within the context of devs getting requirements and producing features, this can look like a decent solution. I've heard it many times. Adding more processes is usually the default solution to every software team problem, and many times is a recipe for disaster.
Solving problems and delivering value in a business flow spans different areas, expertise, and knowledge, and optimizing for local solutions won't make the complexity of the system more explicit, or manageable, or the business processes clearer because we only see a part of the whole system.
Enter Domain-Driven Design (DDD)
Domain-Driven Design is an approach that focuses on creating software in complex business domains that reflects the mental model of the people that intimately know the business. Instead of handing off requirements down to the developers, and passing them from stakeholders to experts to business analysts... we all create a shared language and model, which is used by everyone in the project and is described in the code.
DDD is an approach that can help us go from the telephone game and handoffs, something like the picture below:
To a way of collaborating where the different parties involved co-create a shared model. The code becomes the model and uses the same language we use to communicate to each other about the business, the user, outcomes, etc. If the model changes, the code changes as well.
Domain-Driven Design is all about dedicating time to discover and model our domain, using a shared language and being ready to embark on a journey of continuous collaboration and learning.
Domain-Driven Design is not meant to be a static, once-only process. It is meant to be a continuous collaboration between developers, domain experts, and other stakeholders. So if the requirements change, we must always start by reevaluating the domain model first, rather than just patching the implementation.
Domain Modeling Made Functional, Scott Wlaschin.
In the feature that I had to rework, changing the development process wasn't going to fix anything. What we needed was to have continuous collaboration between everyone involved, and focus on creating a shared understanding, a shared language and a model.
Bear in mind that there are many other complementary ways of improving collaboration. User story mapping, described by Jeff Patton in the book of the same name, shows a fantastic way to get shared understanding. While DDD requires cross-functional collaboration to be successful, it's more than collaboration, it's an approach to software design that focuses on:
People collaborating continuously to understand the domain, and create a shared language and model.
Creating a software model that solves a problem in the business domain. When the model changes, the code changes.
Architectural patterns and best practices with business logic at its core.
The domain and a model
This is a picture of London:
I'm rushing to finish this article because I have an important meeting in The Shard, how can I get to the meeting from Whitechapel? I don't know about you, but this picture doesn't help me much, there's no way to identify Whitechapel, The Shard, or any streets or landmarks to guide me. Somebody shares with me a different picture:
I can see Whitechapel and The Shard, I can even recognize some landmarks! I know where to go, this should be easy. This last picture is not reality, it's a simplified representation of London: a model. It allows me to ask specific questions and get answers. I can only ask specific questions since it's not all-inclusive, it omits information, uses a single language and simplifies reality in such a way that it's useful for our particular purposes. If my fingers are tired from writing this article and I don't want to walk to The Shard, what tube station should I use? Our previous model doesn't help us, we need to use a different one:
The person I was going to meet has changed the meeting location, I have to meet him at Tate Modern. Our little map of London doesn't include Tate Modern, but if we adapt it to include more areas of the city, it becomes useful. If we extrapolate this to a business with complex rules and procedures, the domain would be what the company does and how it does it to achieve its goals, the domain is our picture of London. To work with this complex domain in such a way that we can see the business rules, and easily adapt and expand them while being able to use the same shared language, we need to model it.
How can I start modelling?
Software development is a learning process, working code is a side effect.
The DDD community offers us several guidelines to model our domain:
Focus on business events and workflows.
Partition your domain into smaller subdomains.
Model each subdomain.
Listen to the experts' language to guide you and use it with everyone and everywhere (code included).
Business events and workflows
When our domain is complex to the point that the whole is more complex than its individual parts (complex adaptative systems), knowing to perfection our specific functional area won't help us deliver a full system.
In a world where we reign supreme over our silo, when it's time to create something that involves an entire business flow (which touches multiple areas) we don't have enough knowledge, we engage in constant hand-offs, sporadic meetings with different teams to gather more information and, in summary, lots of waste in the process. In the extreme case, we might think we don't need other people, that we can do it alone, we're the best.
The path towards reducing silos and optimizing for global problems is to start focusing on optimizing for flow, global understanding, and collaboration.
Collaboration not only involves developers, but also requires all involved areas of expertise to work closely. Breaking up silos and organizing teams for fast flow is not the topic of this article, for more information I highly recommend Team Topologies.
Through collaboration with the business and technical teams involved in our domain, we can start getting a better view of it, foster global knowledge sharing, and go in a direction of creating our models and boundaries and interactions between them. Since we want to model a complex business domain, we'll focus on the behaviours of the business and its operations, one of the best ways to do that is to focus on business events and workflows.
A business doesn't just have data, it transforms it somehow. The value of the business is created in this process of transformation, so it's critically important to understand how these transformations work and how they relate to each other.
Domain Modeling Made Functional, Scott Wlaschin
Event Storming is a highly collaborative workshop that brings together anyone who has questions and anyone who has answers: experts, developers, managers…
The goal is for everyone (technical and non-technical) to engage in insightful conversations and discover our processes and understand and model the domain, which is achieved by creating a visual narrative of the business. Nothing beats a good story.
We create a cohesive story of the business by focusing on the business events, and the things that happened that the business cares about, e.g. Account Deleted, Payment Confirmation Email Sent, and Booking confirmed. By creating a narrative together, we face our misunderstandings, resolve conflicts and discrepancies, and discover the unknowns…
Most importantly, we reach a single story of the business, instead of disjointed versions, we create a shared understanding. This rather simple concept, shared understanding, is the real outcome, not the wall of post-its or documents after the workshop.
While it's not the only tool to model the domain, Event Storming is one of the best ways to do it. It involves everyone in the business flow or company, and it hopefully helps chip away at the silos and starts sharing knowledge and working on the global problems.
Every event is normally caused by doing work to satisfy an action, a command.
When we get the Account Deleted event, that means there probably was a Delete Account command.
For Payment Confirmation Email Sent, the command could've been Make a Subscription Payment, which caused the payment to be made, sent a confirmation email to the user, and turned on autorenewal.
The command doesn't do the work, it only gives an order. The actual work is done by the workflow, which takes a command, actions it, and returns events. These events might trigger commands in other areas, with their corresponding workflows.
In this first part, we've seen that:
A domain is what the company does and how it does it. The business and its operations.
A model is a simplified version of reality that solves a specific challenge of the domain.
Domain-Driven Design is an approach to software that focuses on modelling the mental models of experts in complex business domains and shared understanding.
Silos are optimal for local problems, but when working on business flows and complex problems, they hinder our ability to deliver and see the big picture.
Event Storming is a great tool for shared understanding and modelling the domain. We see the business, in the most basic form, as a narrative composed of events.
Command → Workflow → Events
In the next post, we'll talk a bit about partitioning the domain into smaller subdomains and model each subdomain. As well as how Event Storming can still help us in partitioning and discovering our contexts.
Implementing Domain-Driven Design. Vaughn Vernon
Domain Modeling Made Functional. Scott Wlaschin.
Event Storming. Alberto Brandolini.
User Story Mapping: Discover the Whole Story, Build the Right Product. Jeff Patton.
Team Topologies. Matthew Skelton and Manuel Pais.