⏩ Introduction
Software applications always evolve around the sphere of knowledge and activities that make up a company’s business. We need to learn how the company works, and how they use technology and then we explore ways to create our product or maximize our processes through our technical knowledge, which most of times means coding.
Domain-Driven Design is a software development approach that solves complex problems by connecting the implementation to an evolving model; it offers a set of tools aimed at designing and implementing code that delivers high business value.
When you start learning DDD, you start approaching the way you solve problems and develop software for your company in a more conscious way, because you build the domain knowledge you need to make conscious choices.
Let’s jump into the issue to discover the core concepts of DDD and how they can help make a difference!
🧩 A way to solve complex problems
This is the “enhanced version” of this old article I wrote on my previous Medium blog: it was time to discuss again about DDD, so I decided to revamp that article and expand it, but on my blog.
The first thing that is important to highlight, in my opinion, is that DDD aims to solve complex problems: a simple consequence is that it may be overkill if the complexity is not sufficient to justify it. This typically means that it’s very hard to see a startup having enough complexity to justify DDD from the beginning, especially because startups often are exploring new fields, meaning you don’t know enough of the domain.
The best thing to do when starting is to keep things simple, the smallest possible, with a tested and clean enough code that allows you to move fast when you learn from the customer feedback.
Coming back to DDD, it basically offers two levels of approaching problems, one called “strategic” and the other called “tactical”.
The Strategic Approach
The strategic approach helps the team make the best design and integration choices from a business competitiveness perspective. The company benefits much more from software modeled to explicitly reflect the organization’s competencies. Important concepts such as bounded context and ubiquitous language are defined here.
The definition of bounded context is that of a semantic contextual boundary. Within the enclosure of this boundary, each component of the software model has a specific meaning and specific responsibilities. The components that are within the boundary are specific to that context and semantically consistent with it.
On the other hand, the ubiquitous language is the language that is developed in a team working within a Bounded Context, spoken by every member of that team. Software models must be modeled consistently following that language, which is then both spoken among team members and implemented in code.
The Tactical Approach
The second approach described by DDD is the tactical approach, which helps the team design truly useful software that accurately models the business. The organization should benefit from various options to release the solution, with various infrastructure options, whether in-house or in the cloud. This is where aggregates are implemented.
To explain the concept of aggregate we must first mention those of Entity and Value Object.
An Entity is a software element that uniquely models an object. An Entity by definition always has a unique identity expressed through an ID that distinguishes its individuality from all other Entities of the same type. The entity is often mutable, therefore its state changes over time.
A value object, instead, is a software element that models an immutable concept. Unlike the model, we simply have a value that, contrarily to the Entity, does not have a univocal identification. The equivalence between value objects is in fact determined from the simple equality of their value.
A perfect example is the banknote: imagine modeling a 5€ banknote. Generally, within a business that requires payments, a €5 banknote is equal to another of the same value, they are perfectly interchangeable. But if our domain was instead a Mint, each banknote would require an ID to identify it uniquely because each of them is no longer interchangeable with the others.
Now back to the point: an aggregate is a composition obtained from one or more Entities and one or more Value Objects. Typically one of the Entities has the role of Aggregate Root, which is the main element. The aggregation of various elements of these two types then forms an aggregate that must have a transactional consistency boundary. This means that the state of the aggregate must always be consistent with the business rules in all its parts and therefore all necessary changes to the elements that compose it must be persisted simultaneously.
The Subdomains
Finally, to conclude this overview of the fundamental concepts of Domain-Driven Design, we need to talk about subdomains.
While the entire business the company deals with constitutes the Domain, a Subdomain is a section of that business. Subdomains can be used to logically subdivide the complete domain in order to understand the problems thereby breaking down the complexity. In DDD, Subdomains are ideally implemented as a clear Bounded Context.
Within a company’s subdomain, there are “Domain Experts”, people who understand very well the aspects that make up that part of the business because they work there every day. Not all subdomains are the same, however: we can recognize three categories.
The core domain is the most important subdomain because it means great results for the business; this is the subdomain in which the organization must excel and that can make a real competitive difference for the company if succeeds.
The supporting subdomains are less important than the core but are still important for the business because without them the core domain cannot succeed; it is a situation in which the company still wants to do custom development, even if not with the same investment put on the core domain, because we want to have control over them.
Finally, we have generic subdomains: you will typically find a lot of ready solutions on the market for them that you could buy, or you will decide to develop in outsourcing the solution - that’s because here the company wants to make the least investment possible to achieve what they need.
Until next time, happy coding! 🤓👩💻👨💻
Dan’s take 🙋🏻♂️
Domain-Driven Design is one of the most amazing methodologies I ever learned in my life as a Software Engineer.
I was lucky: I had some colleagues who already knew it, and organized a book club around the “Implementing Domain-Driven Design” book to spread the knowledge since the company wanted to move to a DDD approach. I’ve also experienced a couple of Eventstorming as a participant, but also an Eventstorming Facilitation Online Course with Brandolini itself when I was in Casavo.
I remember the feeling the first I heard about the topic: it all seemed so natural. It was the response to a lot of answers I made myself in my first years of careers - turned out they were very great questions, I just didn’t find such great answers before DDD.
I mean, DDD is full of great concepts, but I want to stick to my emotions here, and hey: the concept of domain is great!
We, as software developers, often fall into the worldwide generalization error (I just made up this name, not sure if there is already one), especially when we are juniors/mid: let’s say we need a calculator logic to sum and subtract numbers - it’s so easy to think “hey, it’s a calculator, so let’s also implement a multiply and divide function… you never know, we might need it in the future” - and then discover some months after that you never used those functions, but still they exist and add useless code.
The fact is: if we only need to add and subtract, it may make sense to design it as a calculator, maybe, but it doesn’t make any sense to add functionalities because “you never know”. You must know! If we only need those two, just implement those two - when the need for another one shows up, you will implement it.
In your company domain, you may never need to multiply or divide, for some reason. If that need shows up, you will face it when it shows up.
This has a main positive side effect: you will implement only what you need, a choice that will lead to reducing development time and also keep the codebase shorter.
Bounded context is another concept that changed the way I looked at organizations in general, and software development, especially once related to Conway’s law, which states “organizations design systems that mirror their own communication structure”.
If you identify the bounded context in the company and organize the software product teams each around one bounded context, Conway’s law will be positive because you will likely avoid the typical problems due to an organization divided in “skill teams” (marketing/dev/sales/etc). Skill teams are useful from some point of view (without going deep, think sharing best practices), but then the daily jobs should be made by people organized in cross—functional product teams.
The last core concept I want to highlight that made me feel in love and enlightened me, are the subdomains: when you are in an organization, especially a big one, is very hard to understand how it all works, and typically everything looks important at the same way. Of course, this it not true, and the 3 categories of subdomain are such a smart answer to this - it just makes a lot of sense.
I often use them as a reason for some choices or questions about priorities - once you can make people understand what core, support, and generic subdomains mean, it’s a lot easier to make reasoning around how much we want to spend into something and if it’s really worth it to keep it in-house or not.
Also, if you know in which category is the software you are working, you can also make conscious decisions about how much control and safety you really need: think to when you need to add an external library, interact with a 3rd party API, or integrate a low/no-code solution or AI, for example. The approach to this needs should keep in consideration if you are doing it for a core or generic subdomain - in the first one, you probably want to be sure that everything is safe, tested, and well designed so that users is not impacted if any error occurs with the external part (simple example: make the API request async), while in the generic context, you can be totally fine with the simplest solution possible (example: if your website is just a showcase, maybe with a blog, you don’t need to code it internally - just use a website builder or externalize it).
I don’t want to oversimplify: DDD is hard to master, especially when it comes to implementing the code that respects it’s principles - yet, it can be enormously useful even if you just learn his concepts.
It’s a complete game-changer in how you see an organization, the software you build for it, and everything around it.
Go Deeper 🔎
📚 Books
-
Domain-Driven Design: Tackling Complexity in the Heart of Software - This is not a book about specific technologies. It offers readers a systematic approach to domain-driven design, presenting an extensive set of design best practices, experience-based techniques, and fundamental principles that facilitate the development of software projects facing complex domains.
-
Domain-Driven Design Quickly - This book is a short, quickly-readable summary and introduction to the fundamentals of DDD; it does not introduce any new concepts; it attempts to concisely summarize the essence of what DDD is, drawing mostly Eric Evans' original book, as well other sources since published such as Jimmy Nilsson's Applying Domain Driven Design, and various DDD discussion forums.
-
Domain-Driven Design Distilled - Concise, readable, and actionable, Domain-Driven Design Distilled never buries you in detail–it focuses on what you need to know to get results. Vaughn Vernon, draws on his twenty years of experience applying DDD principles to real-world situations.
-
Implementing Domain-Driven Design - This book presents a top-down approach to understanding domain-driven design (DDD) in a way that fluently connects strategic patterns to fundamental tactical programming tools. Vaughn Vernon couples guided approaches to implementation with modern architectures, highlighting the importance and value of focusing on the business domain while balancing technical considerations.
-
Cronache di Domain-Driven Design: Storie di successo, esperienze sul campo, progetti reali [ITA 🇮🇹] - A choral book in Italian made up of independent stories, which are the result of the application of Domain-Driven Design on real projects.
📩 Newsletter issues
-
DDD: Build Meaningful Aggregates [Crafting Tech Teams by Denis Čahuk]
-
APIs with bounded contexts [Microapis.io by Jose Haro Peralta]
📄 Blog posts
-
All You Need To Know About Domain-Driven Design - a concise but complete recap of the core concepts of DDD, by Knóldus blog
-
Domain-Driven Design: building the Right thing Right - a focus on how DDD help us building the right thing for business, by Val’s Tech Blog
-
A series of articles from Thoughtworks blog (you can find more there!) :
🎙️ Podcast episodes
👨🏻🏫 Online courses
-
Domain Driven Design Made Easy (Educative)
-
Domain-Driven Design Fundamentals (Pluralsight)
I can also focus my Personal Coaching service around DDD - discover more here.