Part 1: Domain Driven Design like a pro 🏅

Introduction phase: Tackling the ambiguity of DDD

Anders Gill
Raa Labs
38 min readNov 9, 2019

--

Domain modeling is hard. Teaching & learning about domain modeling is even harder. So, my aim is to help you on your journey on learning this vast topic, giving you a solid fundamental understanding of what it means to go Domain Driven. Conceptual notions and digging into examples is what this series is all about. People often dive straight into developing Line of Business applications (LoB) with code, but not knowing what DDD really stands for before implementation can lead to disaster. Historically, monolithic architectures have been the king, and microservices has slowly made its adoption.

Picture of me before I started learning DDD

There are tons of frameworks out on the internet which are more aligned towards using the DDD approach in implementation, but encapsulating a whole lot of principles just because it sounds ÂŤappropriateÂť is not good enough. There must be a clear reasoning behind decisions, and we will look at specific areas and benefits of implementing DDD where it makes sense to do so. By the end of this series, you will not only see that DDD is more than a collection of patterns, but hopefully also understand the philosophy behind it. Before we crack it open, there are some prerequisites that needs to be in order. Demystifying these complex prerequisites is essential before you will be a pro on developing with the DDD mindset.

This series attempts to take away the super-complicated vocabulary and abstract these parts into simple and easily digestible drawings and small pieces of information. Hopefully, all the buzzwords will make much more sense to you and you feel ready to dive into the world of DDD. Secondly, this series will work as a starting point for people who are new to the concepts of Software Engineering, and it is recommended to follow it from top to bottom before choosing a learning path.

Game plan of how to become a pro in DDD

This series will consist of multiple parts. The introductory section is split into two parts (you are now reading part 1). There will be at least one part for each track (uncertain of the number at the time of writing). This is as earlier mentioned recommended to be completed before diving head first into your specific area of choice. You can choose to learn more about the Business track or the Developer track later on. By staying cooperative to the process, you should by the end of the series have enough knowledge to continue your DDD journey with practical approaches and implementations. Each respective track has its own focus points, maybe you’ll even finish them all? Awesome, now let’s get going!

Disclaimer: Being a data scientist myself for the last 4–5 years, and coming from a background as a software engineer, I have personally not stayed updated on the latest trends within concepts and design principles within software integration. I am therefore always open for corrections, fixes, suggestions and other helpful ideas that might arise from reading this series. The series has resulted from countless hours of reading, talking to educated people, watching tutorials and YouTube videos.

Let‘s start off by listing the jargon I will abstract from the introductory paragraph.

• Microservices

• Monolithic architecture

• LOB (Line of Business) applications

I am sure that once we get going on explaining these concepts, new question marks will arise, and we will continue to point them out and explain these.

Microservices

Microservices architecture

A Microservices architecture seeks to package its components (services) into completely independent units. That’s the easiest way to put it. Everything should be decoupled so that each microservice can scale independently. Previously, software projects were often big monolithic monsters that were highly coupled together and hard to maintain. You usually chose a programming language and process and just stuck with it. With Microservices however, you are free to pick the best tools for each particular job. When starting on a project, you might start with a few larger services and carve them up into Microservices as the logical boundaries reveal themselves. However, if you are struggling with articulating with reasoning for splitting a larger service into microservices, then maybe the best way forward is to keep the larger service as it is. By working in a modular way, like Microservices allows you to, you have a better chance of rapidly fixing problems and avoid severe system failures if one microservice goes down. You know exactly which part of the pipe that fails, and you can therefore issue a fix and redeploy that exact microservice instead of having to bring down the whole monolithical monster of a software project. There are obviously some trade-offs you should be aware of before choosing to go down that path, but my job is to resonate on the jargon while plenty of others has brought up the pros and cons.

Monolithic architecture

Monolithic architecture

The awesome thing about monolithic architectures is that they have proved the test of time. They still work and do their job. Many enterprise architectures are still built upon this method, but their obvious flaw is the complexity of updating them. Not only could they be built on long abandoned frameworks that makes it hard to stay relevant, but people move on and the development team that initially built the big black box is not necessarily the same team that continue developing it further. Thus said, the biggest advantage of a monolithic architecture can also be looked upon as its biggest flaw. As a comparison, in the world of Microservice everything is decoupled and the parts talk to each other through the works of APIs. The beast is divided into much smaller chunks, which are easier for developers to digest.

Line of Business (LoB) application

Line of Business (LoB) Applications

A line of business application is an application which is more important for the business than other software. Word, PowerPoint or email for instance, are not LoB applications, but rather tools that aid you in your work day. LoB applications are more directly aligned towards generating revenue for the business. In other word, these application are business critical, or even the generator of revenue in itself. Many companies develop bespoke software for their needs, and those are often the mission critical software that needs to work. For them, that would be a line of business application. Pretty simple explanation for a simple concept that has drifted away from its literal meaning and towards the section of IT buzzwords.

Problems when tech choices are made by upper management

One problem that often applies in real world scenarios, is when upper management make tech choices without rational reasoning. If the developers are to cope with these choices, management has to convey the reason for why decisions were made. If they don’t, scenarios like the illustration below can occur.

Use the right tools for the job

My point: Use the technologies that make sense. Alternatives might be better in someone else’s eyes, but you still have to evaluate what’s best for a particular scenario or use case. Be critical — there is no silver bullet!

By continuing this series, I will not only help you understand the core basics of IT jargon that has found its place within the field, but I will also give you facts, tips and tricks. Just look for the light bulb illustration!

These information snippets are handy if you are a developer, but also useful if you are simply interested in expanding your knowledge. I will link you to some of the many amazing resources that exist, so that you can deep-dive and continue your rapid growth. Some of the resources in the next parts of the series are even created by the Raa Labs team, how cool is that?

Going forward…

This is where the fun part starts, but we are still in the introduction phase! So, if you cant wait to dive into your track of choice, I suggest you hold tight a bit longer so you grasp all the concepts. This is the first part of the introdcution phase, but we will need one more part before separating into your track of choice.

We have now introduced the most common ways of carving out overall software architectures and explained some basic terminology.

We will now dig deeper into what this series is all about: Mastering the big beast, Domain Driven Design (DDD). More complex words will now need to be explained, and daunting principles be uncovered. But don’t worry! We will do our best to Keep It Simple Stupid (KISS).

Domain Driven Design

The follow topics will be discussed and reflected on in this section:

• What really is Domain Driven Design?

◦ Domain

◦ Model

◦ Ubiquitous language

◦ Distilling the problem space of DDD

◦ Bounded context and sub domains

◦ Distilling the solution space of DDD

◦ Unpacking Strategic DDD vs Tactical DDD

Software is made to solve problems, and software written with the DDD mindset doesn’t shy away from that fact. People that write the software however, often dive straight into frameworks and code, missing critical supporting information for the specific problem. Remembering what the code you wrote yesterday actually does can also some times be a struggle. And if you struggle with it, you can bet a new developer also will! Maintainability in development, and writing self-explanatory code can often be difficult and time consuming.

The people surrounding the team of developers and other stakeholder, often shy away from the development process and does not get involved enough. This can result in a barrier where people talk their own language and the development team doesn’t really understand what they are conveying. And vice-versa…

This is not how DDD works! Adjusting the «get it done yesterday» mentality is something that DDD tries to solve with its implementation. Before jumping straight into this implementation, you need to understand the gist of DDD and get a deep understanding of what domain that concept is implemented in — while iterating. And that’s exactly what DDD focuses on, the domain. Trying to bring «commonality and collaboration» across the primary focus of the project, is DDD´s mantra. Thus said, not only to raise focus on the domain for non-developers, but the developers as well. Having a specific vision and approach for dealing with inconsistencies around a project is something DDD can help manage with its ever increasing focus on the domain at hand. So what really is a domain and why is the domain so important for DDD other than having the word «domain» in its name? Let’s find out.

Classical challenge in DDD space

What really is Domain Driven Design?

But first… I’ll be honest, I read the book from Eric Evans and it was quite a read. Super comprehensive and, quite frankly, difficult to comprehend. So instead of giving up on learning DDD, I found help elsewhere. InfoQ had a short summarized version based on «the blue book» called «Domain Driven Design Quickly». I read it, and I instantly loved it. Another inspiration is the book named “Pattern, Principles, and Practices of Domain-Driven Design” by Scott Millett with Nick Tune. My inspiration is based upon these two books and examples are crafted from those books. If you are interested in learning even more about DDD, I recommend you read these to further expand your knowledge on the subject. Keep in mind, these books are more in-depth than what we are to cover in this series. So, if you would like to stay high-level on the topic, keep on reading!

Eric Evans Domain Driven Design overview

Looking at the illustration above, you might feel a bit baffled. But don’t worry, my aim is to break down the barrier that prevents us from understanding what the picture really illustrates. The figure is from Eric Evans book, and gives an overview of Domain Driven Design. For us to understand the topic, we will have to divide the figure into small easily digestible subtopics and work our way up from there.

Let’s start with understanding what a domain is.

Domain

A domain is the problem space that should be solved by designing a software.

Shifting focus

A domain is often a complex collection of variables in a set environment that can shrink, expand and evolve — depending on how you define the boundaries. For complex environments you can’t sit down and write code without understanding the essence of it.

Consider the metaphor of a ship manufacturer. A ship can consist of hundreds of thousands of parts, and the workers working on the development of the ship, don’t have a full overview of all the manufacturing that goes into building a ship because of its share scale. Workers focus on one particular area of the ship and complete that while other workers are working on other parts of the ship in parallel. In other words, progress is happening simultaneously. The worker that is working on the rear of the ship, doesn’t need to know exactly how the progress is going on in the front of the ship because it’s out of his scope and will not impact the work he is doing.

Ship manufacturer

There are however some people that have the job of knowing the exact status of the development of the ship from a bigger picture. Those people have a better overview of the full progress but doesn’t need to know the exact implementation as particular knowledge is required. As long as the work is being done and he can see the overall progress, he is happy. Now we jumped from people working on the nitty gritty details of the implementation, and up to the project leader that has an overview of the overall progress. In between these two roles, there are plenty more. Each level we go up or down, new knowledge is required to understand the boundaries of the work being done and how to do it.

Software is similar to the complexity that a ship manufacturer sees. If we were to craft software for ship manufacturing, we would have to know much more about the ship manufacturing domain. There will be tons of requirements that needs to be met for the ship, and without having a good understanding of the domain, it is not possible to write good ship manufacturing software. In trivial cases, you can jump straight into code but in complex environments, a lot of consideration must be made.

So how do you get to know the domain? By involving the specialists. The domain experts. By involving the people who actually have the knowledge about why we are making the decisions that we do. These are the people that will transfer knowledge that eventually will reflect the core elements of the domain to yield good ship manufacturing software. To enhance a domain and plant the roots of bespoke software in it, you have to understand it and model it.

So now that we understand what a domain is, how do we express it in code? That’s a particular subject within the back-end track of this series. In order to get a better overview of DDD in general, there are many more topics that we need to address, and keeping the explanations short and concise will benefit us going forward. We still haven’t modeled the domain which is essential in order to implement it properly. So, what do we mean by modeling a domain?

Model

The three-point summary of DDD depends on the definition of the terms:

• Focus on the core domain

• Explore models in a creative collaboration of domain practitioners and software practitioners

• Speak a ubiquitous language within an explicitly bounded context

These bullet points are straight out of Eric Evans DDD reference booklet. We have elaborated on the first term and will explore the second one.

A model is, simply put, a representation or abstraction of the target domain. In order to map a domain in an easy and understandable manner, we need to organize information, systematize it and divide it into smaller blocks as our thinking process is synthesized into this model. And sometimes, you need to exclude parts of the domain because it gets too vast and complex. For now, this will be our elaboration of the model. Going forward, we will give concrete examples and visualize how a model can look like, extracting the key elements of the domain into an abstraction.

Let’s revisit the model representation later, and currently keep up the pace and dive straight into the third bullet point from the three-point summary. This next topic on the agenda is critical to understand in order to move forward, and is looked upon as one of the core building blocks of DDD.

Ubiquitous language

A big part of DDD is to keep all communication in a language that makes sense for the domain so that all stakeholders fully understand each other and can work efficiently. In order to model a domain, you need to communicate in a certain way. So what do we mean by that? Are we talking about speaking in English or French? Well, not really. The idea is to define a language that developers can implement into code so that its understandable from the outside. Of course, you have to use an actual language as the core foundation for communication, but we mentioned earlier that developers need to implement the domain into something tangible as code. This is where the developers would come up with class names, variables, etc. in their code. In order for the developer to come up with good and well defined variables and class names that makes sense, the developer needs to write them as simple as possible while keeping it domain specific so that if a new developer comes in, he should in theory understand and make sense of the domain while understanding what the code does. This all sounds well and good, but I did write ÂŤin theoryÂť on purpose, because practically, it is not easy.

Confusing words in different contexts

You might be wondering why this is so difficult. Well, everyone has their own communication style, and mixed into that style are ideas and personal understandings of subjects that might not be the same for others. If you look at the word clouds above, the experts in their respective domain has their own way of communication. On the left, you have a ship manufacturer that is talking about hydraulics and forging and such. On the other side, you have developers talking about their domain. When coming up with a domain model you have to communicate with domain experts. These experts will use their jargon while developers will have their own language tuned for discussing the domain in terms of design. If there is a barrier of understanding between the implementing party and the key stakeholders, the domain implementation will absolutely suffer from this. If the day-to-day discussion is disconnected from the terminology embedded in the code, transient information expressed from domain experts might not get encapsulated properly in the implementation. Coming up with a ubiquitous language for communication and implementation is therefore one of the most important parts of the project in order to make it succeed.

In short, learn the domain! And the process of doing that, is to not impose a new language. Rather embrace the domain and make an understanding of it. Recognize that a change in the language is a change in the model. Iron out difficulties by experimenting with alternative expressions, which reflects alternative models. Then refactor code, renaming classes, methods, and modules to conform to the new model. (Eric Evans, June 2014)

Robert Smallshire has a short and concise way of describing the ubiquitous language. Some of the key bullet points he boiled the ubiquitous language down to during a presentation at the euro python conference in Edinburgh, were the following:

• Context dependent

• Valid within limits of applicability

• Used by a community of problem domain experts

• Shared meaning

• Single meaning

• Expressed in the software model

• Reduces distance between problem and solution

I think Robert´s take on it pretty much sums up what the ubiquitous language is all about. If you want to watch his presentation, I have linked it in the references section in the bottom of this article.

When the developer is left out, confusion appears

Domain storytelling

Domain Storytelling is a knowledge crunching technique. The people who participate in a Domain Storytelling workshop will get new insights into the domain. The resulting Domain Stories express their shared understanding. Other ways to build domain knowledge include scenarios (Vaughn Vernon) and scenario exploring(Eric Evans). Domain Stories help you to come up with scenarios and to visualize them. I Recommend reading the book from Stefan Hofer and Henning Schwentner on Domain Storytelling. The book covers the gist of domain storytelling and illustrates it with easy-to-grasp examples. One of their case studies which illustrates the concept, is based on a chain of Cinemas. Imagine if you are asked to develop an app that allow their customers to make reservations and buy electronic tickets. To familiarize ourselves with the domain, we set up a Domain Storytelling workshop. After discussions back and forth, you will eventually end up with a use case diagram that illustrates the ticket system.

Use case diagram for Cinema application

From the illustration above, you seem to have covered all the features that should be implemented into the cinema app based on the illustrated use case diagram which evolved from the domain storytelling session. But you keep on discussing and it turns out that the ticket system actually has the ability to issue tickets directly back to the customer through the app. This was not discovered at first, but as it turns out, the ticket system can issue QR-based tickets; the user will get the tickets instantly — making it much easier for the customer not having to manually collect the tickets from the cashier at arrival. This is new information! Clearly this should be illustrated as well, so we update the use case diagram to look as following:

Revised use case diagram for Ciname application
https://github.com/WPS/domain-story-modeler

By having knowledge crunching sessions like this, you can really make sure you meet all requirements that are set. It is easy to get confused by big and complex domains, but using techniques like domain storytelling will help you break down the problem into simple parts like we did in the trivial example above.

Distilling the problem space of DDD

The problem space of Domain Driven Design

The figure above is a blueprint replica of how Scott Millett and Nick Tune illustrates the problem space of DDD. Already from the looks of it, there are a couple of new terms that we are not familiar with. Let’s discuss these in the next section, but first get an overview of what we are looking at.

The blueprint starts with understanding the problem domain and business wish. From there, the domain experts and the development team sit together and understand the language of the domain — the ubiquitous language. Once the language is set and everyone are on the same level, they crunch through the domain knowledge. At this point, the development team should be ready to implement the distilled domain knowledge into code. They separate the code into appropriate sub domains with appropriate models. Hopefully, the development team has understood the domain vision as the domain experts envisioned it. Focusing on the core domain is critical as this is the main reason for the system being built.

Bounded context and sub domains

A bounded context defines the limits of applicability for a ubiquitous language. Since domains often can become very complex and big, it is a good approach to distill the domain into smaller and separate models. So instead of having one big model for the domain, you have many smaller ones that are properly defined and has specific boundaries of what they are to encapsulate. Many larger domains will have multiple bounded contexts within them. So, the meaning of specific words will therefore be determined based on which bounded context it belongs to. Therefore, we can say that a words meaning is easily understood in a context. The bounded context is a description of the boundaries that exists within a particular model.

Let me give you an example. Consider the figure below:

Words have different meanings depending on their context origin

As you can see, these words clearly point to different things depending on the context, even though they are spelled the same way. These words can easily create confusion, unless you know the model you are referring to and which bounded context we are talking about. Maintaining a strong decoupling between different bounded contexts makes large systems simpler.

The word Serve means something totally different in a restaurant context compared to a Tennis related context. Set and Pour are other examples as well.

Alireza from developer.com explains the concept of sub domains and how it differs from bounded contexts in a simple digestible way. What’s important to know is that sub domains are different from bounded contexts.

A large problem domain can be decomposed into sub domains to manage complexity and separate important parts from the rest of the system.

Different types of sub domains

There are three kinds of sub domains that we here differentiate based on how much competitive advantage it yields:

  • Core domain: The most important part of the system, the reason for the success. This will give you competitive advantage, so focus on this and make this as good as possible.
  • Generic domain: This is not the core, but the core depends on it. e.g. email sending service, monitoring service and such. Try to re-use existing parts and don’t spend too much time on these systems.
  • Supporting domain: ÂŤExtraÂť domains that help to support the core but does not provide any competitive advantage. Not recommended to invest heavily on but still needed in order to succeed in the core domain. Maybe even outsourcing could be a possibility here?

From the bullet points above, you can clearly see that some domain types are more important than others. In a bigger domain; you usually split the domain into smaller domains. Within the context of a sub domain, there can exist an independent model for each sub domain. This is important to know as there does not only have to be one model, but many models for each domain. Unlike a sub domain, a bounded context is a concrete technical implementation that enforces boundaries between models within an application.

How to focus on the core domain

Treating large problems as one huge problem, often results in failure. Common practice is to partition the large problem domain into smaller sub domains to manage complexity and separate important parts from the rest. In the domain of butchery, a pig is sliced into much smaller pieces much like a problem space. If understanding of the sub domains is acquired, you can easily break down the problem space. (Scott Millett and Nick Tune) has a very valid point about sub domains.

Sub domains are abstract concepts; don’t get sub domains confused with the organizational structure of a company. Sub domains represent areas of capability, define business processes, and represent the functionality of a system.

By attacking the problem space in this manner, you should be able to more easily conquer it and reduce complexity of the larger problem.

I highly recommend reading their book as it clearly illustrates these concepts, and many of the figures in this series is re-created based on the originals from Scott and Nick.

A pig marked with its cuts

Distilling a problem domain as an example

Let’s consider the domain model of an online auction website. As we might expect, there are plenty of elements within an online auction, and a lot of these will be unique for the domain and specific business.
Starting point:

Now we need to separate the domain into smaller partitions based on what makes sense. Membership within an auction site takes care of the registration process. Seller is another partition which takes care of all behaviour related to seller activity. Auction is the area of the problem that deals with managing the timing of auctions and dealing with bid activity. Listings takes care of listings on the auction site. Finally, we have the dispute resolution which handles all disputes between members and sellers. It is not written in stone that a auction site has all of these parts, maybe some don’t have a system for dispute resolution, or maybe some have others which I havent listed. For the sake of the example, let us use the aforementioned as a foundation as we classify each individual separation into subdomains.

At this point, you have already distilled knowledge from domain experts and revealed the different parts of the problem. We know that some parts are unique, and some are dependent on each other. Now comes the time to classify each part into the appropriate partitions called subdomains.

What would be the deciding factors for the success of our auction site? Those vital parts should be classified as the core domains. It is worth mentioning that you don’t only need to have one core domain but can have many if it makes sense.

The core domains for the auction site is seller and the auction. The seller domain contains ratings for seller and the domain logic needed in order to determine the seller fees. The auction core domain however, consists of mechanisms to handle biddings and running the auctions. These are important. The membership domain and listing domain are supportive for the core domains by providing possibilities to create accounts and find items for sale. The dispute resolution domain is generic in the sense that it can be served with off-the-shelf software. An example of this could be a ticketing system.

The main idea is to know where to invest, where to put your efforts and what parts you can outsource and get from elsewhere. All these decisions that outlines the domain into subdomains are results from knowledge-crunching sessions which not only the domain experts are part of, but also the developers to help them grasp and understand the domain in a collaborative effort.

These subdomains will help you shape a solution.

Domain separation illustrated

Two systems have resulted from the process. One part of the domain can be fulfilled by an off-the-shelf package while the core and supporting domains have been built using a custom web application.

What if I don’t have a core domain?

There are many reasons that businesses build rather than buy software. If you can do it cheaper, faster, or smarter then it’s a good candidate for a custom build.

Distilling the solution space of DDD

The solution space of Domain Driven Design

The solution space covers patterns that can shape the architecture of your applications and make it easier to manage. DDD is architecturally agnostic in that there is no single architectural style you must follow to implement it.

Mismatch between models

How does mismatch between models occur? And why is it so important to remedy this? I mentioned that there is no single architectural style you must follow in order to implement DDD as it is architecturally agnostic. There is however some architectures that historically haven’t aligned as much towards the DDD mindset as others. The usual way of crafting a monolithic architecture leans towards a waterfall approach where you plan the whole system upfront. Diving straight into UML sketches of the entire solution is not always the best way of solving things. After the domain experts and business analysts create the analysis model and hand it over to the developers, the analysis and code models can diverge from each other if the development team is not involved in domain knowledge crunching.

As developers start to implement the analysis model in code, they often find a mismatch between the high-level artefact produced by architects and the reality of building the system. Models need to be isolated and defined within an explicit context in order to stay pure and focused. However, at this stage there is often no feedback loop for developers to talk to the business and architects, so the analysis model can be updated, and their input enacted. Instead, the developers diverge from the analysis model, and their implementation often overlooks important and descriptive domain terms and concepts that would have provided deeper insight and understanding of the domain (Scott Millett and Nick Tune).

Important concepts get lost and misinterpreted when there isn’t a joint effort on collaboration between the two sides. Proper ubiquitous language will help the two models to stay aligned. This is where the added importance of a feedback loop takes place.

Having a more unified team approach suggests leaning towards collaboration efforts far more important when doing DDD than any other practice. Having a constant feedback loop enables the discovery of important concepts that doesn’t get misinterpreted as the ubiquitous language is in place. These two models will also be bound to each other because of the ubiquitous language. A change in the code will and should also reflect a change in the analysis model because of the importance of synergy between those two.

So how can you potentially solve the problem with a DDD implementation, and how do you get to an architecture? One tool is to come up with a Context map through the work of an Event Storming Session! We will learn more about event storming and context map in a second. First, we need to unpack the strategic elements of DDD.

Unpacking Strategic DDD vs Tactical DDD

Remember the big complicated image with all the boxes earlier on which we didn’t understand? Now is the time to split it up into two parts, respectively into Strategic and Tactical sides. By splitting it up, we can define certain boundaries and tackle elements that are relevant for that part. Strategic patterns shape the solution, while tactical patterns are used to implement a rich domain model.

But why does splitting it up make sense?

Anes Hasičić summarized this pretty well in a Medium post which I highly recommend to read. We haven’t reached all of the concepts mentioned in the post below, but will eventually get there.

Evans has earlier stated that he regrets putting the strategic patterns way back at the end of the book, which probably resulted in many people giving more importance to the tactical patterns because they come first or even worse, they get so caught up in the intricate implementation details of tactical patterns, they don’t even get to the most important part of the book.

The thing to take away is that building blocks provide you the tools to implement DDD, but you should give much more focus to strategic patterns, even more so because tactical patterns/building blocks will continue to evolve, some will become obsolete, new ones will be added (e.g. Domain Events).

Let’s start by looking at the strategic side before we dive into the tactical side.

Strategic DDD

Strategic side of Domain Driven Design

Looking at the elements from the figure, we have already covered some of them. Elements like Continuous Integration, Big Ball of Mud, Context Map are worth talking more about before we close the strategic chapter.

Continuous Integration

Continuous Integration (CI) is a practice for developers, where it aims to have a shared code repository and push commits to in a high frequency. Based on these commits from the developers, bigger build and release pipelines trigger for continuous deployment (CD) of the application. This is an automatic process which checks integrity of the code and can help in detecting problems that might have been introduced during the latest commits. DDD heavily emphasizes on this practice, hence the reference in the strategic DDD figure. Some organizations may have trouble with these practices, particularly if their experience is largely tied to less-flexible development models, such as the waterfall model or the like. (Andew Powell-Morse)

Below is an article I wrote on the topic of DevOps which consists of elements like CI/CD.

Big Ball of Mud (BBoM)

A big ball of mud

A Big Ball of Mud is a haphazardly structured, sprawling, sloppy, duct-tape-and-baling-wire, spaghetti-code jungle. These systems show unmistakable signs of unregulated growth, and repeated, expedient repair. Information is shared promiscuously among distant elements of the system, often to the point where nearly all the important information becomes global or duplicated.

The overall structure of the system may never have been well defined.
—
Brian Foote and Joseph Yoder, Big Ball of Mud

What do you do if you are dealing with a legacy system, a big ball of mud? How do you get a taste of DDD there (assuming you still can employ the iterative development approach, and have access to domain experts)?

Well, just because the legacy system i.e. “the big ball of mud” exists, it does not mean you have to keep cramping it with new features, but rather, employ your context mapping techniques here. Draw a line around it and say, “this is my big ball of mud”, and after that draw a line around your new service and treat it as a separate bounded context.

As Evans puts it, it’s probably inevitable that your service will get enclosed by the big ball of mud eventually (since it will eat almost anything), but at least you had a nice run for a time. (Anes Hasičić)

Context mapping

TLDR; The boundaries defined with integration points illustrated.

How do you identify the existing problem space? And how do you then split the domain into sub domains and create bounded contexts? Through the work of event storming! You will learn more about event storming in the next upcoming topic, but through the work of event storming is a resulted context map which essentially maps the existing terrain. But why is it important?

In large and complex applications, multiple models in context collaborate to fulfil the requirements and behaviours of a system. A single team may not own all the various sub components of a system, some will be existing legacy code that is the responsibility of a different team, and other components will be provided by third parties that will have no knowledge of the clients that will consume its functionality. Teams that don’t have a good understanding of the different contexts within a system, and their relationships to one another, run the risk of compromising the models at play when integrating bounded contexts. Lines between models can become blurred resulting in a Big Ball of Mud if teams don’t explicitly map and understand relationships between contexts. (Scott Millett and Nick Tune)

You can look at the context map as the defining visualization of how the boundaries are defined for your project situation, and where boundaries have been separated into different contexts.
A context map is not(!) a highly detailed document created in some kind of enterprise architecture tool, it is a high-level, hand drawn diagram that communicates a holistic picture of the contexts in play. A context map should be simple enough to be understood by domain experts and development teams alike. As well as clearly labelling the contexts the teams understand, the diagram should also show areas of the system that are not well understood to reflect the messy and often unintelligible reality of the codebase. (Scott Millett and Nick Tune)

This might seem a bit confusing, let me give you an example of a context map:

An example of a context map

The figure above illustrates a context map. You can see that there is an Anti-Corruption Layer in place which protects the HR context from the recruitment context. This is because the recruitment context is a third party which is prone to other forces which shouldn’t affect our prime contexts. We will dig deeper into ACL (Anti Corruption Layer) further down.

It is extremely important that context maps reflect reality, showing the code in the present state rather than an ideal future state. Context maps doesn’t need to show the detail of a model; instead, they must demonstrate the integration points and the flow of data between bounded contexts. We still haven’t illustrated the relationship status on the context map other than connection points, so learning more about how we can illustrate the flow of relationship is the next topic.

Upstream/Downstream relationship

A very important factor in DDD context maps, is the direction of the relationship between two contexts. DDD uses the terms upstream or downstream: an upstream context will influence the downstream counterpart while the opposite might not be true. These are often shortened to the letter d and u respectively. This might apply to code (libraries depending on one another) but also on less technical factors such as schedule or responsiveness to external requests. In the example below, you have a context map which illustrates a Personal Finance Management Application that talks to an online banking service through an API. So, in this case, the PFM application is the downstream, and the online banking service is the up streamer. We will go more in depth around the relationship further down.

A good context map would give you a picture of the odds against you. You might know if the organization is — consciously or not — working against your project’s success, even before the project starts.

InfoQ has an easy to digest example on how a context map could look like for a web-based Personal Finance Management Application (PFM). The PFM is made to track budgets, manage banking accounts, stocks and such. In the application, the term “Account” might have different meanings. In the banking context, an account is looked upon as “container of money”. In another context however, take the web application context; the account has a different meaning. In the banking context, you expect attributes like balance, account number, IBAN and such. For the web application you have attributes related to authentication and user credentials. In other words, not the same concept. At this point, we meet the case of ambiguity related to the term “account”. Now we are starting to see the meaning of the ubiquitous language.

So, when we have ambiguities like the case above, we need a tool to distil the domain into smaller more tangible bounded contexts to make sure that the whole team is aware of the existence of the different concepts. This is where context map shines. As mentioned earlier, context maps are NOT super high-fidelity illustrations, but more sketches that shows that contexts can be a bit fluffy and hard to define, so having a “rough” look is needed.

Unified Modeling Language (UML)

UML is an industry standard in the space of data related modelling. With UML diagrams, you can easily sketch out your whole system in high details. In programming and project engineering, UML is widely used to draw class-diagrams that shows the attributes, methods, parameters and such. This diagram is a “visual representation” of the class that the developer is to implement. So, using UML to showcase underlying concepts will simplify and bridge the abstraction between a context map, model and code. UML is a language for describing software systems. It’s software first. Domain-Driven Design is a focus on understanding the actual concepts of domain experts. So, this is people first. But these are just tools and choosing one does not indirectly invalidate the other.

As Martin Fowler said:

“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”

That’s much more likely to happen if programmers start with the existing human understanding of the situation. So UML can therefore be used to express code in more tangible and illustrative ways than just huge amounts of text on a screen.

Let’s draw a simple class representation for Banking Account and further delve into the concept of context maps.

UML example

Modeling the same concept

So, what happens when the concept is the same, but used in multiple ways? Consider the banking account class illustrated above. Some PFM apps allows us to manage payments, usually keeping a Payee registry. In this case, a payee might be associated with one or more banking accounts. But for this scenario, we won’t know anything about the internals of the payee banking account, nor can we do any operations on the banking account… Does it make sense to model the Payee account together with the Banking Account class we just defined?

From a real world scenario, it might be that our payees account is in the same physical bank as our banking account, but we are not supposed to issue any operation on the payee banking account, or to track anything on it. So conceptually, it doesn’t make sense. This is a simple example of two different contexts within the same application where modelling them separately makes sense. We just modeled the same domain concept in two different ways as they were calling for distinct uses. The BankingAccount might still be a class that allows us to perform (or track) specific operation (such as deposit or withdraw) while a separate class PayeeAccount could possibly have some data in common with BankingAccount (such as the accountNumber), but a simpler model and a definitely different behavior (we shouldn’t be able to access the payees’ balance, for example)(InfoQ).

This might sound obvious to some, but it’s not. When working on a class diagram, or a UML modelling tool you might really easily start modelling a Payee that has a bankingAccount attribute and think “I’ve already a class for that”. The pavlovian attempt to get rid of code duplication might do more harm than good, sometimes(InfoQ).

As long as our domain knowledge increases, the context map evolves! Now, we just split the PFM application into two separate contexts; Banking and Expense tracking.

Elaborating on a context map

Since there is a dependency involved on an external party, the relationship between two contexts can become brittle. Either, the external party from our perspective; can choose to listen to our demands and develop software that fits towards our requirements, or they can create something that the using party (us in this case) has to conform with. Since the PFM application is interacting with the online banking service through an API, we need some kind of protection against changes coming from the upstream context. This will help us to preserve the integrity of the banking context. The most common practice to do so, is to implement something called an Anti Corruption Layer (ACL). This puts up a barrier at the tip of the context that the stream has to go through before getting accepted into our PFM context. In the ACL, an explicit translation is happening at the code level between the two contexts. An example could be to transform the incoming object from the legacy model to the domain object in your main application’s model. This works as a place to manage all the subtle differences between the models on both ends. Microsoft has a pretty well defined guide on ACL. I recommend reading that if you are to implement this. There might also be an idea to put up an ACL between your main context and the potential big ball of mud.

There is also going to be other contexts in a bigger picture within the organization, that are not external. These contexts might be maintained by other people and are subject to different forces. We might need to interact with these as well. If Banking and Expense tracking were to be maintained by different teams, they’re likely to be in a partnership relation: they’re both developed towards a common goal (and upstream-downstream doesn’t make much sense since they’re on the same level). If Web User Profiling is achieved with an external module, we’re probably going to use it “as-is”, meaning that we’re downstream and Conformist, towards Web User Profiling.

Let’s suppose now our PFM application grew larger, and another team (Team B) has been assigned to work with us (we’re obviously Team A) on a new trading module of the same application. Team B might be in a different room, building, city, company or country and is fully dedicated to the trading area. In the example below, Team A shares some of the code with Team B, even if they tend to work on separate portions of the code base. Eventually, team B writes some class (A in Figure 12 below) that implements functionalities needed by team B, that were already available in class A(InfoQ).

That’s code duplication, the root of all evil! In a single, well defined, bounded context, this is definitely true. But for some reason this does happen in almost every non trivial project. This is normally a sign that there are probably not-so-well-separated contexts in play(InfoQ).

A Context Map reflects our current level of understanding of the whole system and will be updated as long as we learn something more, or the environment changes. Currently, we don’t know exactly what’s going on, and this is “our current level of understanding”. So, since we are not 100% sure about the Trading part of the domain, we might need put up a sign illustrating this. This is illustrated as the overlapping round element that partially overlaps with our PFM application and has an exclamation mark on the intersection.

An example of a complete context map illustrated

As long as we gather more information, the map will become clearer. As mentioned before, simply acknowledging that there are different models in play within our application and that model integrity can be preserved only inside a well-defined bounded context, provides a lot of value to our domain modelling perspective. Many models lose integrity as they grow, context mapping helps a lot in this sense(InfoQ).

Event storming

TLDR; Process for landing on a vision

Event storming illustrated

Event storming as an actual facilitated workshop where there are many participants, including developers, domain experts and others. The facilitators role is to keep the group of people engaged and aligned towards the same goal: modelling the domain. There is a lot of back and forth in this session, and it is recommended that the group of people are familiar with the concepts of DDD before execution. Event storming is a tool within the DDD toolbox and should be used as a tool. There are certain boundaries that are defined on how to conduct an event storming session. Aberto Brandolini has written a book on this topic and is recommended for those who wants to learn more about how you conduct an event storming session.

Philippe Bougau has also created a fantastic ongoing guide on how to conduct Event storming. It’s short and concise and explains the core concepts of it. Highly recommended to read if you don’t feel like diving head-first into tons of content.

Tactical DDD

Tactical side of Domain Driven Design (DDD)

The tactical parts of the DDD chart, should give you building blocks in order to help you implement a successful implementation. These are all big topics that are more technical than what we have covered in this stage, but we will need to cover these in the next part of the series.

How are the two parts of DDD connected?

Through ubiquitous language — the binding between the code and the analysis model.

At this point, you should have enough information to grasp the concepts of what is happening in the DDD illustration below. If you can’t make an educated guess of the flow, I suggest you scroll up and read the topics discussed once more before jumping into the next stage of the series as we will cover more concepts that might seem confusing.

The concepts and overview of Domain Driven Design (DDD) illustrated

When to use DDD

When are you supposed to leverage the power of Domain Driven Design? That is a good question that is difficult to give one answer to as every software project is different. Even literature disagrees with each other. Some say you can apply DDD principles into every project, whilst others tend to use DDD in projects where business logic is rather complex and convoluted. My take on this is that you have to weigh the advantages to the disadvantages for your particular project. In some cases, DDD would be a great fit, but in others not, especially where the applications have marginal domain complexity, but conversely have a great deal of technical complexity. Andrew Powell-Morse has a good summary on the topic. Since DDD so heavily emphasizes the need for (and importance of) domain experts to generate the proper ubiquitous language and then domain model on which the project is based, a project that is incredibly technically complex may be challenging for domain experts to grasp, causing problems down the line, perhaps when technical requirements or limitations were not fully understood by all members of the team (Andrew Powell-Morse).

I sketched this simple drawing to represent where I feel DDD can be used, although it is not a requirement:

Matrix of when to use Domain Driven Design principles

Going forward

Wow, that was exhausting! A lot of information went into this section of the series. I’m glad you are still going strong. Let’s continue on that note and jump into other relevant subtopics that makes sense to elaborate on.

  • Tactical DDD building blocks
  • Event sourcing
  • CQRS
  • DDD frameworks

These are all big topics. To not risk writing a book about the topic, I think we should end the first part of the introduction phase. We will tackle these topics and many more in the next part of Domain Driven Design like a Pro. You do have pretty good knowledge of DDD at this point, but there are still some topics that needs to be reflected on in order to fully grasp DDD and to be able to implement it into your own endeavours.

Stay tuned and comments are appreciated in the comment section below. I strive to make it easier for you to grasp the concepts, so feedback is important and highly appreciated 🎉

I would like to end on a note from an interview conducted by InfoQ where they asked Eric Evans about any pitfalls when trying to learn DDD. Evans responded:

Don’t try to apply DDD to everything. Draw a context map and decide on where you will make a push for DDD and where you will not. And then don’t worry about it outside those boundaries. Experiment a lot and expect to make lots of mistakes. Modelling is a creative process. — Eric Evans

Special thanks to the following resources for giving me the inspiration and ammunition to make this series:

References:

  1. Domain-Driven Design: Tackling Complexity in the Heart of Software (Eric Evans)
  2. Domain-Driven Design Reference: Definitions and Pattern Summaries (Eric Evans)
  3. Domain Driven Design Quickly (abel avram, floyd marinescu)
  4. Patterns, Principles, and Practices of Domain-Driven Design (Scott Millett, Nick Tune)
  5. A Decade of DDD, CQRS and Event Sourcing (Anes Hasičić)
  6. Drafting a Functional Architecture Vision with Event Storming and DDD (Philippe Bourgau)
  7. Domain storytelling (Stefan Hofer)
  8. Introducing EventStorming (Alberto Brandolini)
  9. Domain Driven Design Patterns in Python (Robert Smallshire)
  10. Domain-Driven Design — What is it and how do you use it? (Andrew Powell-Morse)

--

--