Domain Driven Design: discovering domains
In the previous chapter of the Domain-Driven Design series, we talked about the basic concepts of DDD. As I mentioned last time: one of the most difficult parts of the approach is to properly identify and discover domains. With the basic knowledge of DDD, we can jump into this topic and try to understand how to properly identify domains.
Three kinds of domains
You already know that DDD is not the best choice for small or not complex projects. During some planings, meetings, or brainstorming sessions the natural thing is you will find some functionalities or groups of functionalities that are not connected at the implementation level. You can figure out that only a few or one part of your system functionalities are advanced or big enough to use the DDD approach. Domain-Driven Design is a very elastic thing and allows you to use it in specified parts of your solution, which need better implementation. It’s not a problem to implement DDD alongside simple CRUD or external modules. Domains from a strategic perspective are usually grouped by their complexity and importance for a company.
Parts of your system which have low priority or low meaning are called “generic domains”. The generic domain contains logic which from a strategic perspective is not important as other things. For example, if you have to create a vet helping system, probably the most important thing to you is to automate the registration process or provide a mechanism for storing a patient’s diagnosis and data. On the other hand, you will put less emphasis on the invoice system, which can be e.g. bought from an external company or you can implement it on your own, but as simple as it’s possible because it doesn’t contain important business logic. In this scenario, the invoice module is a generic domain for you.
You probably guess that scheduling and storing parts of your system will have their own domain category, and you are right. The most important domains with business logic are called “core domains” because they contain core features. According to the paragraph header, where is the third domain kind? The answer is: between generic and core.
What does it mean? In reference to our previous example, imagine that you have to implement the next module which is responsible for calculating – let’s say – a pet health level. Pet health level is a number between 0 and 10 and represents a pet’s health. The level is calculated according to the pet’s blood tests results, diagnosis, and subjective vet mark. It’s a cool feature to be able to present pet’s owner that information or use it by the vet to make some decisions but it’s not important business logic. It makes some supportive calculations which are in addition to patient data. These kinds of domains are called “supportive domains” because they support core ones with their logic and don’t provide meaningful features (from a business point of view).
How to discover domains?
Let’s stay with our previous example of a vet helping system. Actually, we already discovered a few domains during our domain kind consideration. In that case, domains have been discovered only according to my guesses how this system should work. In real life, customers’ problems are more complicated and the needed logic is not that obvious. The best way to discover domains in complicated logic is to organize a meeting with domain experts and together try to understand obtained knowledge about the system – instead of reading 300 pages of documentation.
Such meetings are conducted in different ways, for example, using simple ubiquitous language with UML (or different notation – e.g. custom) and designing system functionalities with real-time assumptions. The second way is to organize event storming sessions and use colored sticky notes to clearly describe system functionalities by its events (about this topic I’ll create another series in the future). In this example, we’ll use custom notation to visualize vet helping system flow.
Vet helping system
Our imagined client said:
“I have a lot of patients nowadays and still, I’m using a notebook to schedule appointments and classic paper patients’ documentations. It’s hard for me to work with patients and at the same time scheduling visits or exporting patients’ diagnoses for their owners. I can’t afford a secretary in the long run so I’ve decided to implement a schedule and diagnosis system which won’t need my attention to book patients or share the diagnosis with owners”.
Let’s design that flow by using the previously mentioned custom notation.
This is a simple auth system visualized by using one actor called “guest” – which means not authenticated user.
The whole flow of our vet helping system with authenticated users – called pets owners. The vet actor is on the other side and has more privileges than a pet’s owner. About the first ones, they can list their pets, add new ones and schedule new appointments for their pets. Also as our client said, a pet’s owner should be able to check the diagnosis of pets. Additionally, the vet can add a diagnosis for the pet, remove the pet and accept or reject an appointment.
Right now we have everything and we can think about the domains and bounded contexts of our implementation. As we know we don’t have to use DDD for everything, so let’s make the authentication module a normal one that will be a part of application nested features. Our first bounded context should include logic to proceed to schedule. It should allow us to schedule an appointment, cancel and list our appointments. The second bounded context is connected with diagnosis during appointments, we should allow there to attach consultation results to registered pets and allow to read diagnosis for pets’ owners.
From a strategic perspective, we can distinguish three kinds of domains: core, generic and supportive. They reflect business logic importance and should determine building effort. You should put emphasis on core domains and consider using existing solutions for supportive domains. Features that are not so important but still have a crucial impact on your business should be implemented as generic ones. To discover system domains/bounded contexts you can organize meetings and live designing processes with a client, instead of trying to understand concepts from the documentation. To properly discover domains you can use UML, custom notation system or sticky notes, or whatever you want, just remember to keep it simple and be sure that a client understands your flow. After all, you will get a complete system image.