#76 - Learning Domain-Driven Design - Vladik Khononov

 

   

“Interactions with domain experts play a key role in implementing software. You have to make sure that you understand the problem you’re solving. You cannot provide a software solution without understanding the problem first."

Vladik Khononov is the author of “Learning Domain-Driven Design”. In this episode, we discussed in-depth about Domain-Driven Design (DDD) and Vlad started by sharing why understanding business domain is crucial in software engineering and how DDD can help build the shared understanding between domain experts and software engineers. Vlad then explained the two important designs in DDD, i.e. the strategic and tactical designs, and how they relate to each other. For each design, Vlad touched on some important patterns, such as bounded context, context map, subdomain, aggregate, entity, and value object. Towards the end, Vlad gave great tips on applying DDD to brownfield projects and how those projects can benefit the most from some of the DDD practices.  

Listen out for:

  • Career Journey - [00:06:05]
  • Importance of Understanding Business Domain - [00:10:42]
  • How Domain-Driven Design Helps - [00:16:12]
  • DDD Strategic Design - [00:20:21]
  • Subdomain - [00:26:51]
  • DDD Tactical Design - [00:32:44]
  • Aggregate Pattern - [00:34:36]
  • Entity Pattern - [00:40:43]
  • Implementing DDD for Legacy System - [00:43:24]
  • 3 Tech Lead Wisdom - [00:46:52]

_____

Vladik Khononov’s Bio
Vlad (Vladik) Khononov is a software engineer with over 20 years of industry experience, during which he has worked for companies large and small in roles ranging from webmaster to chief architect. Vlad maintains an active media career as an author, public speaker, and blogger. He travels the world consulting and talking about domain-driven design, microservices, and software architecture in general. Vladik lives in Northern Israel with his wife and an almost-reasonable number of cats.

Follow Vladik:

Mentions & Links:

 

Our Sponsor - Skills Matter
Today’s episode is proudly sponsored by Skills Matter, the global community and events platform for software professionals.
Skills Matter is an easier way for technologists to grow their careers by connecting you and your peers with the best-in-class tech industry experts and communities. You get on-demand access to their latest content, thought leadership insights as well as the exciting schedule of tech events running across all time zones.
Head on over to skillsmatter.com to become part of the tech community that matters most to you - it’s free to join and easy to keep up with the latest tech trends.
Our Sponsor - Tech Lead Journal Shop
Are you looking for a new cool swag?

Tech Lead Journal now offers you some swags that you can purchase online. These swags are printed on-demand based on your preference, and will be delivered safely to you all over the world where shipping is available.

Check out all the cool swags available by visiting techleadjournal.dev/shop. And don't forget to brag yourself once you receive any of those swags.

 

Like this episode?
Follow @techleadjournal on LinkedIn, Twitter, Instagram.
Buy me a coffee or become a patron.

 

Quotes

Career Journey

  • What Eric [Evans] says is that not only [business logic] is important, that’s the heart of software and it deserves a lot of attention.

Importance of Understanding Business Domain

  • Business logic is the heart of software for a reason. It’s the reason software is being built.

  • You’re not building a software to demonstrate how fast and scalable your database is, or how sexy your user interface is. You are building a software for solving a particular business problem. This problem can be making someone more efficient, streamlining business processes. Nowadays, many businesses are built on software. That’s their business domain.

  • The biggest lie of software engineering is “to be a software engineer, you have to write code, and I am an introvert to the bone”. We’re not writing code for the sake of writing code. We’re writing code to solve a problem for someone. This someone, they are the domain experts. They are people who have the most knowledge about the business domain that we are modeling and implement it in code. In order to efficiently solve this problem, we have to communicate with them, talk with them. We have to be effective in that communication and collaboration with people. So software engineering is not only about code.

  • That’s why interactions with domain experts play a key role in implementing software. You have to make sure that you understand the problem you’re solving. That’s critical. You cannot provide a software solution without understanding the problem first. Either it’s going to be the wrong solution or it’s going to be the right solution, but for a different problem, and both are useless.

  • If we take the name of this methodology, Domain-Driven Design, I prefer to expand it a bit, and say business domain-driven software design. So we have three components here.

    • First, we have a business domain that we have to grasp and understand.

    • Second, we have software design. That’s what we are building here.

    • And we have that word “driven” in the middle, which means, in mathematical language, it’s like software design equals the function of business domain.

  • If you don’t get that business domains right, then you will get the wrong software design. You may be solving the wrong problem, or you may be trying to solve the correct problem, but in an inefficient way.

  • Second, as Domain-Driven Design guides us, there are quite a few design decisions that we’re basing upon that knowledge of business domain.

    • That’s strategic design decisions, like what are the coarse grained components that we’re going to use to implement our system? How are they going to communicate with each other? How do we allocate that work to software engineering teams?

    • And we have tactical design decisions like, what design patterns we are going to use to implement each component? How are we going to implement this business logic? How are we going to orchestrate the interactions of different parts of a component? It’s our internal architecture. Of course, we have high-level architecture. How components are working with each other?

  • If you get that business domain knowledge wrong, that’s a good opportunity to make some wrong decisions, both strategic and tactical ones. So that’s why we have to make sure that we have enough knowledge of the problem domain before we’re even trying to design a solution for it.

How Domain-Driven Design Helps

  • I actually believe that [high failure rate in software projects can be solved]. If we look for reasons why so many software projects fail - if you look at studies that were conducted on this topic, you’ll see that quite a few of them, if not all of them, failed because of communication issues or something related to communication. It can be communication between team members, communication between software engineers and domain experts, communication issues between management and engineering teams.

  • The core principle of Domain-Driven Design is building a shared understanding between the different stakeholders of the project so that they can speak and reason about that software system in the same language. In DDD lingo, it’s called ubiquitous language.

  • Once we will be able to facilitate communication in the same language without the need for multiple translations before knowledge reaches its destination, everything will be way more efficient. That can solve us lots of rework, lots of wrong assumptions. And eventually, I believe it will lead to more successful software projects.

  • Everything changes, especially if you’re working for a startup. Not only that we as software engineers have no idea how to implement things in the most efficient way, but business people have no idea how they’re going to solve a certain problem that they are focusing on.

  • They know that, “Hey, there’s something that we want to do. How we’re going to do it? We are going to iterate. We’re going to test a few solutions until we find the most optimal one”.

  • During that time period, everything is going to change. That understanding of the business domain is going to evolve. Not only you’re going to learn more and more about it, but those business people, those domain experts, they’re going to learn as well. As they gain more knowledge, that has to be reflected in software design decisions.

  • If that component business domain changes, it has to be reflected in software design. There can be many types of changes, starting from maybe a more efficient way to describe the business domain, a better terminology, a better understanding of the business processes.

  • But also, the whole business domain can change. Now, it’s not unusual for a company to start with one business goal, and change it along the way because the previous one wasn’t financially viable, for example.

  • It has to be reflected in software design. Failing to react to changes in the business domain will incur technical debt over time, and eventually, it will lead you to very big technical debt and a big ball of mud.

DDD Strategic Design

  • I think that strategic design is way more important. Because you can write pretty successful project while incorporating only strategic design decisions. But if you’re focusing only on tactical design decisions, well, that’s probably not going to end well, at least in my experience.

  • First, strategic design is about creating a shared understanding between software engineers and business domain experts. It’s about cultivating that shared language and shared understanding.

    • To do that, there are a few requirements from that language that you’re using in communication. Its main requirement is each term should have one and only one meaning.

    • People, unlike software, they are so unpredictable sometimes. They can say one thing, but mean something else because the context is different. We cannot allow that when taking a software design decisions. We have to make sure that every piece of knowledge is explicit.

    • Domain-Driven Design says, “Hey, when you have such ubiquitous language that depends on context, model it explicitly in code. Define the context in which that language applies. It’s bounded context”. And that’s the first strategic design decision.

    • It ensures that you have a model encompassed by the bounded context, which is clear. Each of its terms has only one meaning.

    • Because of some historical issues and mistakes, (many) think that bounded context is necessarily a microservice. That’s not true. A bounded context is rather your biggest valid monolith because it encompasses a model that has no conflicts in it. You can decompose it further. The idea is to find those boundaries that ensure that you have a correct model in it without no conflicts or collisions.

  • Second, a system doesn’t build itself. For that, we need us, software engineers. In any organization, there can be either one team of people or multiple teams of people working on the same project. And that again affects how you design those bounded contexts because they have to interact with each other.

    • Domain-Driven Design says, “Hey, that’s something you have to take into account when you’re designing those components, how they’re going to be integrated.”

    • That’s the second strategic design decision that we’re making according to both business domain and the structure of our teams.

    • The structure of engineering teams can change as well. That should affect the way those bounded contexts are integrated with each other.

Subdomain

  • The term subdomain is pretty challenging to define. The idea is that a subdomain is a business building block.

  • Let’s say we have two companies working in the same industry. So they will have the same business domain. But they are not the same company. They have different ways. They are competing in their markets. They have different offerings. So what differentiates them is their subdomains.

  • Subdomains are like puzzle pieces that complete that whole picture of how the company is planning to succeed in its business domain. These are activities that you have to implement, because of your business strategy, because of how you want to differentiate yourself from your competitors, or because you just have to, because that’s the law, for example, accounting, you have to do it.

  • Subdomains, as a starting heuristic, are usually correlated with organization units, departments. But that’s a too coarse grained boundary of subdomain.

  • Usually when we look deeper, we can find a more, speaking in software engineering terms, coherent sets of use cases that are interrelated, that are either working on the same data, or implementing related business logic. The ones we are able to find those interrelated sets of use cases, they’re usually the more optimal boundary for a subdomain.

  • Subdomain whole purpose is not to describe how organization works. For that, we need something else. That’s business capabilities. And that’s a more complex model because it’s hierarchical. There are different levels of business capabilities. Subdomains are more simple. We have only two levels here. We have business domain and beneath it are subdomains.

  • So we have to concentrate on what is really important for the software system that we are building. We have to decide whether the boundary of a subdomain that we found is good enough for our purposes or not.

  • According to Domain-Driven Design, we have three types of sub domains.

  • The first one is a core subdomain.

    • Core subdomain is how the company differentiates itself from its competitors. It’s something that you have, but competitors don’t. At least you are planning to make more money than they are. So that’s all kinds of intellectual properties, like patents or clever algorithms that are invented in their organization. They may present a novel way to solve some problem, or they just optimize an existing solution, allowing it to be solved more efficiently, in a cheaper way.

    • That’s something that you want it to stay in your company, because if your competitors will have it, that’s bad news. That means you just lost a bit of your competitive advantage.

  • The second type of subdomains is generic subdomains.

    • They are the opposite of core. So there is no competitive advantage here. These are solutions that are used by all the companies in the industry, and probably in other industries as well. And the good example here is an encryption algorithm.

    • So that’s a generic subdomain. Some solved problem. Problem you have, but you have an existing solution. You just have to go ahead and use it. It can be buying an off-the-shelf product, adopting an open source solution. But anyway, the bottom line is that you and your competitors will use the same solution and doesn’t affect your business.

  • The third type of subdomains is supporting subdomains, and they are somewhere in the middle.

    • Again, as in generic, there is no competitive advantage here. But on the other hand, as core subdomain, that’s something you have to implement in-house. And you have to implement it in house not because you want to, but because you have no choice. Because there is no generic solution available.

    • In their nature, supporting subdomains are generally way simpler than core subdomains. That involves some simple implementation. Because it’s simple, there might even be a generic solution, but you will choose not to use it, and instead, just to implement your own, because it will be easier to roll out your own solution than to integrate another one. Implementation is easier than integration.

  • My rule of thumb is to look deeper into a subdomain, and decide whether you should decompose it further. Only if decomposing further will produce subdomains of different types.

DDD Tactical Design

  • Strategic design is about what you’re implementing. What are going to be the components? Tactical design is about how we are going to implement them.

  • We have different ways of implementing the components, business logic. These patterns are the function of a type of subdomain that we are implementing.

  • If it’s generic, then we are just using an existing solution. If it’s a core subdomain, we need a design pattern that will address the complexity of that core subdomain. If that’s a supporting subdomain, that we need simple pattern because otherwise, we will be over-engineering.

  • Another aspect that is covered by tactical design decisions is how we’re going to architect the overall work of the components, like its internal components. How it’s going to work with the database? How it’s going to work with user interface, etc?

  • We have architectural patterns, namely layered architecture, which usually is more useful for supporting subdomains, or when you are integrating a generic subdomain. We have ports and adapters, which is also called hexagonal architecture, which is also called onion architecture, which is also called clean architecture.

  • And we have CQRS architecture. Which pattern you are going to use for designing your architecture and for implementing the business logic depends on the type of the business subdomain at play.

Aggregate Pattern

  • Aggregate is an object that encompasses both data and all the behaviors, all the business logic that affects the data. In other words, everything that can change the data of an aggregate should reside in the aggregated boundary. No outside components should be able to change its data.

  • Usually, we’re using this pattern when implementing some complex business logic. If it’s complex and if you allow external components to go ahead and just modify your data, then sooner or later, there will be some business rules that affect those pieces of data. And those rules are going to be duplicated. Duplicating business logic is usually not a nice idea, but duplicating complex business logic is usually a terrible idea. And that’s what aggregate pattern is supposed to prevent you from doing.

  • An aggregate is not a flat record in a database. Instead, it’s a hierarchy of objects. All that data can reside in the same aggregate.

  • The next question is where do we stop shoving things into the aggregate? Where do we decide where we stop putting things in?

  • An aggregate is not only a boundary of data and behavior, but it’s also a transaction boundary. Meaning that all the changes in the data of the aggregate should be committed in one atomic transaction.

  • So we have to look for smaller boundaries, more efficient ones. What [Vaughn Vernon] says, use transactional boundary as your heuristic for choosing boundaries of the aggregate. Make sure it includes only the data that has to be strongly consistent for implementing the business logic that resides in it. So whatever has to be strongly consistent, leave it in the aggregate. Everything else that can be eventually consistent, put it into another aggregate or another component. But in the aggregate, you should only have data that has to be strongly consistent.

  • How do you know whether you need to be strongly or eventually consistent? Try to evaluate both paths. What’s going to happen if something is eventually consistent? Can you implement all those business rules and business logic correctly? Or will it lead to corrupting your data? When you are analyzing it in such a way, usually it’s pretty evident what information you need is strongly consistent, and what information you can have eventually consistent.

  • That’s an aggregate in a nutshell. It incorporates data, behavior that affects it, and the transactional boundary around all that data.

  • Because all the behavior belongs to the aggregate, we have to expose a public interface that will allow us to execute it. Usually we call it a command. So we’re executing a command on an aggregate. And by command, I mean, not some message that you put in message bus or whatever. No. That’s offensive way of saying that you have a public method. That should be the only way to modify the contents of the aggregate.

  • Very important part of an aggregate’s public interface are domain events. Because sometimes aggregates can be pretty big. You better keep them small, but it depends on your business domain. There are some important business events that can happen in it. The domain event has to be formulated in the ubiquitous language, in the language of the business.

  • So once the change, the aggregate is committed to the database, we need to publish that domain event so that whatever component is interested in it will be able to subscribe, and to do something related to that occurrence of domain event.

Entity Pattern

  • When we see the entity discussed on the same level with aggregates, we start to think that these are two patterns that you can choose from, which is not right. An aggregate is an entity. An aggregate is a hierarchy of objects. So it’s a hierarchy of entities. An entity is a building block in the aggregate.

  • The main reason we need that entity is to differentiate it something from a value object. So value object is the important thing here, not an entity. The difference between them, as you said, an entity has an ID. A value object, on the other hand, can be identified solely by its values.

  • That differentiation allows us to model those value objects as immutable objects in code. As entities, value objects are not independent. You cannot use a value on its own. It has to describe something. So it’s a property of an entity residing in an aggregate.

  • That’s the hierarchy of those three core patterns. Aggregate contains entities described by value objects.

Implementing DDD for Legacy System

  • Somehow we’ve got this wrong understanding of that Domain-Driven Design can only be applied for greenfield projects, but it’s very rare. Most of our work is brownfield projects. Ironically, brownfield projects can benefit the most from some DDD treatment.

  • When implementing Domain-Driven Design in the brownfield project, the main thing you need is patience. You have to be patient about everything.

  • In those cases, I usually suggest starting with mapping the existing solution. So you have this brownfield project you want to evolve with, but before you even start thinking about where you want to go, you’ll have to be sure that you know your starting point. So you have to map those bounded contexts that you have.

  • Now, of course, those are not going to be Domain-Driven Design’s bounded contexts. They won’t necessarily encompass coherent models. But still, these are components that you want to change. So you have to find them, map the bounded context that you have. You have to map how they’re interacting with each other, those integration patterns.

  • Once you did that, the next step would be to start learning the business domain. And usually it’s done by building a ubiquitous language. In real life, it’s challenging, especially for brownfield projects. Because if there is a language that has been spoken for a while in the company, it will take lots of time to change it.

  • In this case, I will suggest to be the example, to go ahead and speak with domain experts. Make sure you understand them. Make sure you can communicate in the same language. Try to identify some wrong assumptions about the business domain that are already implemented in the code. Once you started cultivating the shared language, use it at least yourself in your code, when you’re talking to people.

  • It will take time for that ubiquitous language to be adopted in the organization. But again, be the example. Make sure that whatever you’re producing is in the ubiquitous language. When communicating with people, resort to the principles behind ubiquitous language.

  • Why do we want to make sure that each term has only one meaning? Because we want to eliminate assumptions. We want to eliminate inconsistencies in the communication. So when you are talking with people, you can use those principles as a reason to try and change the way they’re using the terminology of the business.

3 Tech Lead Wisdom

  1. Apply the Domain-Driven Design thinking everywhere.

    • Think about problems and solutions and the connection between them.

    • When someone tells you about a best practice, like some design pattern or technological solution, that is the absolute best practice and should be used everywhere, don’t believe them. Instead, treat it as a solution to a problem. Once you have this solution, ask what problem is it solving? Is that necessarily a problem I have? And this applies both to best practices and what they call anti-patterns.

    • Whatever someone is trying to convince you about or to sell you, treat everything as a solution to a certain problem. Identify the solution and look for problems which are addressed by it.

  2. The Cynefin model.

    • When talking about evaluating problems that we are solving, that we are dealing with, I like to use the Cynefin model. Cynefin model is a decision -making framework that was implemented to help leaders to take actions in different types of problem domains. Let’s discuss three out of five.

    • The first one is “obvious”. These are problem domains which are obvious. You know what problem you have and you know how to solve it.

    • The second one is “complicated”. “Complicated” means you have a problem, you don’t have a solution, but you know that there is someone you can consult, who is an expert in that field, and they will provide you a solution. It can be a person, it can be a book, it can be a Google search or whatever.

    • Third one is a “complex” domain. “Complex” means that we have a looser relationship between a cause and effect. In other words, I’m not really sure what’s going to be an effect of doing something, and no book, no external expert can tell us. Therefore, to make a decision, we have to conduct a safe experiment. It shouldn’t be something big or a huge undertaking. We just have to make small experiments to better understand the nature of that domain.

    • These three domains can be correlated with subdomains of DDD. So “obvious”, probably “supporting”. “Complicated”, where we need to consult someone, and that’s generic subdomain. And “complex”, these are core subdomains.

    • Core subdomain is complex, and that complexity causes us to not be so sure about the outcome of doing something. The safe experiment that we are doing can affect that whole problem landscape because it can trigger some emergent behavior.

    • It’s crucial to keep that in mind, to differentiate between something that we can consult someone about. Complicated and complex, something which requires a different, let’s call it, thinking model of approaching such a problem. It’s important because in our culture, we celebrate confidence.

  3. Don’t be afraid of conflicts.

    • My advice here would be not to try to escape such conflicts, but embrace them because the only way to sell something is to resort to principles behind the solution.

    • When selling Domain-Driven Design or anything, resort to principles behind those solutions. Why they were designed in the way they are?

    • Another benefit of having this conflict, it will uncover some blind spots in your understanding of Domain-Driven Design over the way you are trying to sell.

    • Once you have that area of the solution explicit, it will help you do some further research and to understand it better, to understand maybe the crucial part that you are missing.

Transcript

[00:01:51] Episode Introduction

[00:01:51] Henry Suryawirawan: Hello again to all of you, my friends and listeners. It’s good to be back here again with another new episode of the Tech Lead Journal podcast. Thank you for spending your time with me today listening to this episode. If you’re new to Tech Lead Journal, subscribe and follow the show on your favorite podcast app and social media on LinkedIn, Twitter and Instagram. And if you are a regular listener and enjoy listening to the episodes, will you subscribe as a patron at techleadjournal.dev/patron, and support my journey to continue producing great Tech Lead Journal episodes every week.

My guest for today’s episode is Vladik Khononov. He is the author of the book titled “Learning Domain-Driven Design: Aligning Software Architecture and Business Strategy”. In this episode, we discussed in-depth about Domain-Driven Design, or DDD, and its fundamentals. Vlad started by sharing why it is so crucial for us to understand business domain in software engineering and any kind of software projects, and how DDD can actually help build the shared understanding between the domain experts and software engineers. Vlad explained the two most important designs in DDD, which are the strategic design and tactical design, and how both designs relate to each other. And for each of the design, Vlad touched on some of the most important and widely known patterns, such as bounded contexts, ubiquitous language, context map, subdomain–and the three different types of it, aggregate, entity, and value object. Towards the end, Vlad clarified that DDD is not only applicable to greenfield projects, and he gave great tips on how to apply DDD to brownfield projects and how those projects can actually benefit the most from some of DDD practices.

I deeply enjoyed my conversation with Vladik, learning the fundamentals of DDD and strengthening my understanding. And Vlad really did well in explaining the most important concepts of DDD and make it easier for me to grasp the essence. And if you also enjoy and find this conversation useful, I encourage you to share it with someone you know, be it your friends or colleagues, who would also benefit from listening to this episode. You can also leave a rating and review on your podcast app, or share some comments on the social media on what you enjoy from this episode. Before we continue to the episode, let’s hear some words from our sponsor.

[00:05:15] Introduction

[00:05:15] Henry Suryawirawan: Hello, everyone. Welcome to another new episode of the Tech Lead Journal podcast. Today, I have with me an author named Vladik Khononov. He is actually a very experienced software developer and architect. He has around 20 years of industry experience, worked on many different companies, large and small. He’s an active media speaker as well. A public speaker in conference, a blogger, and also recently published a book titled “Learning Domain-Driven Design”.

So I’m sure many of you would have heard about Domain-Driven Design. It’s probably one of the latest trend in the architecture and especially in microservices world these days. So today we’ll be talking a lot about Domain-Driven Design, obviously, mostly taken from his book. So Vladik, I will call you Vlad probably, thanks so much for your time today. Looking forward to have this conversation with you.

[00:06:02] Vladik Khononov: Thank you so much for having me. It’s a pleasure to be here.

[00:06:05] Career Journey

[00:06:05] Henry Suryawirawan: So Vlad, in the beginning, for people who do not know you yet, would you be able to share your experience or maybe your highlights or turning points in your career?

[00:06:14] Vladik Khononov: Yeah, sure, definitely. So I started learning programming when I was about eight years old. So I had this Soviet personal computer that was bought mainly for playing games, but eventually work. So I was bored, and I started reading this book that came along with it about the BASIC programming language. And it gave me this nice idea that, “Hey, if I will learn programming, one day, I’ll be able to write my own games.” Guess what? I learned programming, no games. But I did install SharePoint. So yeah, that how it usually happens. I know that many people share this story. They got into programming because they wanted to do games, but they fell in love with it all the way for different reasons. So I started learning it when I was eight. I did some simple games. I cannot really call them something finished. It was just like trying to do something.

But when I was in high school, I was lucky. I got an opportunity to work for a local chain of computer stores here where I lived. They actually needed a website, and it was like late nineties. So I said, “Hey, I can do your website. I know HTML and I know CSS, and I know JavaScript”. What I was lacking back then was knowledge of backend programming. It was funny because on the same street, there was a bookstore. And I went there, and I found the book about Perl programming, and there was a chapter about doing backend programming for the web. So I read it in the store. Couldn’t afford to buy it back then. That’s what got me my first paid job as a programmer, as a webmaster. I built a website for them, like an online shop. It was the poster child of security issues and vulnerabilities that you can introduce in an online shop, but nobody knew about it back then.

My next job was for a bigger company. It was Israel’s probably biggest outsourcing company called Malam Team. It really got me interested in Domain-Driven Design way before I knew about Domain-Driven Design. So that’s the story I shared in the book’s preface. On my first week there, my colleagues were showing me the ropes and telling me how they were working here. And what they meant by that is, “You are not going to implement the same type of code you did for that computer shop. We are not doing that. We are serious here. So here’s how we do stuff, and here’s layered architecture.” Back then, that was the best practice to develop software, layered architecture. That’s how we are designing the presentation layer. And we spent quite some time discussing, back then that was ASP.NET Web Forms, how to design the presentation layer for web, WinForms for client, data access layer, ADO.NET, and how they’re connecting to the databases, and how do you implement store procedures?

Anyway, they spend almost no time on business logic layer. That didn’t make any sense to me because I had the sense that if there was this word business in there, it has to be important, but it didn’t get any attention whatsoever. So I asked, “What are the best practices for implementing business logic?” And I got an answer sort of, “Well, you’ll figure that out as you go along. That’s the simple stuff. It’s just if-else statements. I had that in back of my mind for a few years until I heard about Eric Evans' book, “Domain-Driven Design” on one of podcasts I used to listen to. And finally, after I read it the second time, because it took me two times really to grasp it. I just thought that, “Hey, that’s business logic. I wasn’t wrong.” What Eric says is that not only it’s important, that’s the heart of software and yeah, it deserves a lot of attention. Here’s how you do it correctly.

So one day, I got a call from a friend of mine and he said that, “Hey, I’m starting a new company. It’s not going to be simple. Come along, join us. You’ll be the chief architect”. And I said, “Hey, that’s an opportunity to apply Domain-Driven Design”. And that’s where I got most of my experience in Domain-Driven Design. We’re using this methodology from the very first day the company was founded and until its very last day. So that was my real turning point. Having this opportunity to apply Domain-Driven Design in a greenfield project. Yeah, it was an amazing learning experience, and eventually, I was able to get it tried, at least I think so.

[00:10:29] Henry Suryawirawan: So it’s very interesting that I’ve heard multiple times that people started playing computers just to write games. In the end, it turns out like many different career paths from there. Some go to UI, some go to architecture, and some go to different ways.

[00:10:42] Importance of Understanding Business Domain

[00:10:42] Henry Suryawirawan: So I read that particular preface in the book as well. Your story about starting in this new company, and you thought that you will learn a lot of things about software and the business logic, which apparently was not emphasized. And actually, DDD actually emphasizes this importance of business logic or domain in this particular sense. Why do you think domain is still the key thing in software? Because these days a lot of technologies, right? So there are plenty, abundant frameworks, programming language, cloud, whatever that is. Why do you think business logic is still the key in this modern era?

[00:11:18] Vladik Khononov: Yeah. So business logic is heart of software for a reason. It’s the reason software is being built. You’re not building a software to demonstrate how fast and scalable your database is, or how sexy your user interface is. You are building a software for solving a particular business problem. This problem can be making someone more efficient, streamlining business processes. Nowadays, many businesses are built on software. That’s their business domain. So that’s where business logic steps in. If you’ve got everything right, except for business logic, you will get technology demo for a computer game. It looks nice, but you’re looking at it for a few minutes and then you’d get bored because it’s meaningless.

[00:11:59] Henry Suryawirawan: So you also mentioned in the book that actually DDD brings not just software developers as the important actors in the software development life cycle, but actually also the business domain experts. Tell us more about this. Why business domain experts should be involved in the overall software development life cycle?

[00:12:17] Vladik Khononov: Yeah, so that’s actually the biggest lie of software engineering. And it’s “to be a software engineer, you have to write code, and I am an introvert to the bone”. After sometime, I realized, “Hey, we’re not writing code for the sake of writing code. We’re writing code to solve a problem for someone. This someone, they are the domain experts. They are people who have the most knowledge about the business domain that we are modeling and implement it in code. So in order to efficiently solve this problem, we have to communicate with them, talk with them. We have to be effective in that communication and collaboration with people. So software engineering is not only about code.

That’s why interactions with domain experts play a key role in implementing software. You have to make sure that you understand the problem you’re solving. That’s critical. You cannot provide a software solution without understanding the problem first. Either it’s going to be the wrong solution or it’s going to be the right solution, but for a different problem, and both are useless.

[00:13:19] Henry Suryawirawan: Yep. And there’s a critical point in the book that you mentioned as well. If you fail to understand the business problem, or maybe the problem per se, the user problems or the customer problems, you will eventually write a sub-optimal solutions. Even though your technology might be advanced, the most advanced in the current era, but your software is always sub-optimal. What do you mean by this? Can’t technology actually solve how your software is being written? Why it’s always be sub-optimal?

[00:13:48] Vladik Khononov: Yeah. So if we take this name of this methodology, Domain-Driven Design, I prefer to expand it a bit, and say business domain-driven software design. So we have three components here. First of all, we have business domain that we have to grasp, we have to understand. Second, we have software design. That’s what we are building here. And we have that word “driven” in the middle, which means, in mathematical language, it’s like software design equals function of business domain. So if you don’t get that business domains right, then you will get the wrong software design. First of all, it’s going to affect the logic over your code. As I said, you may be solving the wrong problem, or you may be trying to solve the correct problem, but in an inefficient way. Second, as Domain-Driven Design guides us, there are quite a few design decisions that we’re basing upon that knowledge of business domain. So that’s strategic design decisions, like what are the coarse grained components that we’re going to use to implement our system? How are they going to communicate with each other? How we allocate that work to software engineering teams? And we have tactical design decisions like, what design patterns we are going to use to implement each component? How are we going to implement this business logic? How are we going to orchestrate the interactions of different parts of a component? It’s our internal architecture. Of course, we have high-level architecture. How components are working with each other? And that also has implications both on strategic and tactical level.

Now, if you get that business domain knowledge wrong, that’s a good opportunity to make some wrong decisions, both strategic and tactical ones. So that’s, in my opinion, why we have to make sure that we have enough knowledge of the problem domain before we’re even trying to design a solution for it.

[00:15:43] Henry Suryawirawan: And sometimes what I can see as well, software developers. I mean, we are all clever people, right? We also sometimes think of imaginary problems or imaginary solutions. We think that, oh, it will be cool if, the most typical one, is something happens in atomic fashion. So everything is just one transaction, they will be real time, cool, and people will just see the result as soon as possible. But sometimes, business process doesn’t work this way. It’s okay to have some delay, and that’s why we have more event driven architecture, asynchronous and things like that.

[00:16:12] How Domain-Driven Design Helps

[00:16:12] Henry Suryawirawan: And this leads to a lot of things that we know, software projects tend to fail. Traditionally, we all learn about that maybe 50% or more of software projects are failing. Do you think by Domain-Driven Design, this crisis can actually be solved?

[00:16:27] Vladik Khononov: Yeah. I actually believe that. So if we look for reasons why so many software projects fail. If you look at studies that were conducted on this topic, you’ll see that quite a few of them, if not all of them, failed because of communication issues or something related to communication. It can be communication between team members, communication between software engineers and domain experts, communication issues between management and engineering teams. The core principle of Domain-Driven Design is building a shared understanding between the different stakeholders of the project so that they can speak and reason about that software system in the same language. In DDD lingo, it’s called ubiquitous language. Once we will be able to facilitate communication in the same language without the need for multiple translations before a knowledge reaches its destination, everything will be way more efficient. That can solve us lots of rework, lots of wrong assumptions. And eventually, I believe it will lead to more successful software projects.

[00:17:35] Henry Suryawirawan: And it probably also could help in translating the changes in the business as well. So let’s say, these days everything gets disrupted easily. If you really understand the business domain and use the same understanding, the shared understanding, like what you mentioned, the ubiquitous language, and maybe the business process, maybe you can also adapt your software easily. You can use the same terms, same understanding. Even your software, the code, the classes, maybe the objects are named similarly. So you can actually probably adapt to the changes pretty much easier because the business domains, the business understanding and software developers understanding basically are the same. Am I right to say that actually the case what DDD is trying to solve?

[00:18:14] Vladik Khononov: Yeah. Yeah. That’s as well, because everything changes. Especially if you’re working for a startup. In many cases, the startup is new. Not only that we as software engineers have no idea how to implement that in the most efficient way, but business people have no idea how they’re going to solve certain problem that they are focusing on. They know that, “Hey, there’s something that we want to do. How we’re going to do it? We are going to iterate. We’re going to test a few solutions until we find the most optimal one”. And guess what? During that time period, everything is going to change. That understanding of the business domain is going to evolve. Not only you’re going to learn more and more about it, but those business people, those domain experts, they’re going to learn as well. As they gain more knowledge, that has to be reflected in software design decisions.

So going back to that formula of software design equals function of business domain. If that component business domain changes, it has to be reflected in software design. There can be many types of changes, starting from maybe a more efficient way to describe the business domain, a better terminology, a better understanding of the business processes. Like what you just said about transaction boundaries, for example. What should be strongly consistent and what can be eventually consistent? But also, the whole business domain can change. Now, it’s not unusual for a company to start with one business goal, and change it along the way because the previous one wasn’t financially viable, for example. Software project that was implemented in the first reincarnation of the company is not necessarily relevant for the new one because business domain may change, its sub domains may change, everything can change. It has to be reflected in software design. Failing to react to changes in business domain will incur technical debt over time, and eventually, it will lead you to very big technical debt and a big ball of mud.

[00:20:12] Henry Suryawirawan: And typically then engineers will say, yeah, we need to rewrite the whole thing again. So starting from scratch. That’s like the typical problem in the software industry.

[00:20:21] DDD Strategic Design

[00:20:21] Henry Suryawirawan: So you mentioned that we have two things in DDD, right? What is called strategic design and also tactical design. Throughout my journey learning about DDD as well, I typically started from the tactical design. I mean, just to be honest with everyone here, I started with, oh, I can see repository, use case, service pattern. It looks cool. And I even started from a framework back then, it’s like Spring framework. They have all these terms in the framework. So I started from there. I learned the Eric Evans books as well. So that’s where probably people started as the first path towards Domain-Driven Design. But actually along the way as I learned about it, the most important part is actually the strategic design. Can you tell us more about strategic design? What is it actually about? And why it is much more important than the tactical design?

[00:21:07] Vladik Khononov: Yeah. First of all, I fully agree with you. I think that strategic design is way more important. Because you can write pretty successful project while incorporating only strategic design decisions. But if you’re focusing only on tactical design decisions, well, that’s probably not going to end well, at least in my experience. I wrote the chapter in the book about my story of applying Domain-Driven Design in that company. Pretty similar to what you just said. I read four chapters of the blue book and let’s get started. Let’s model everything as an aggregate.

So strategic design, what is it? First of all, strategic design is about creating a shared understanding between software engineers and business domain experts. It’s about cultivating that shared language and shared understanding. Now, to do that, there are a few requirements from that language that you’re using in communication. Its main requirement is each term should have one and only one meaning. People, unlike software, they are so unpredictable sometimes. They can say one thing, but mean something else because the context is different. We cannot allow that when taking a software design decisions. We have to make sure that every piece of knowledge is explicit.

So Domain-Driven Design says, “Hey, when you have such ubiquitous language, that depends on context, model it explicitly in code, define the context in which that language applies. It’s bounded context”. That’s the name of the pattern, bounded context. And that’s the first strategic design decision. It ensures that you have a model encompassed by the bounded context, which is clear. Each of its terms has only one meaning. Now many, because of some historical issues and mistakes, think that bounded context is necessarily a microservice. That’s not true. A bounded context is rather your biggest valid monolith because it encompasses a model that has no conflicts in it. You can decompose it further, but that’s a different discussion. But the idea is to find those boundaries that ensure that you have a correct model in it without no conflicts or collisions. So that’s your first strategic design decision. You are deciding what you’re going to implement. What is the business domain and what are the core components of your system that you’re going to build?

Second, a system doesn’t build itself. For that, we need us, software engineers. In any organization, there can be either one team of people or multiple teams of people working on the same project. And that again affects how you design those bounded contexts because they have to interact with each other. Now let’s say you have two bounded contexts implemented by two different teams. Think of two examples. In the first case, they have a really good collaboration between them. They’re like two teams, but they understand that they’re going to succeed or fail together. So they’re really trying to care for each other. If there are some integration conflicts, they’re going to just go ahead and fix it without making much drama about it. Now let’s fast forward to same company, lots of money, and suddenly they became a huge enterprise. And again, we’ll have two teams working on two different bounded contexts. Now suddenly, there is no such good collaboration between the teams. One team asks to modify the integration interface, and now you have drama. Now you have meetings, etc, etc. And that, of course, postpones what they release. It negatively affects the progress, etc, etc.

Well, Domain-Driven Design says, “Hey, that’s something you have to take into account when you’re designing those components, how they’re going to be integrated.” So, for example, in the first case, the pattern can be partnership. Those teams, they’re partners. They’re interested in succeeding together. In the second case, one of the customer supplier patterns might be a better choice because they provide that certain level of isolation between the teams so that the changes won’t propagate across the integration interface and cause all that drama. So that’s the second strategic design decision that we’re making according to both business domain and the structure of our teams. Going back to our previous discussion, the structure of engineering teams can change as well. Two teams can be in partnership in the beginning, but a few years later, they will be like enemies of each other. That should affect the way those bounded contexts are integrated with each other. That’s an important design decision.

[00:25:46] Henry Suryawirawan: So it seems that a few things here, if I heard what you mentioned just now, right? The first thing is actually ubiquitous language. It’s like almost every book I read, every resource I read about Domain-Driven Design, ubiquitous language is the first thing. Which also then translate into multiple things. Bounded context, that’s also another important aspect. Within the context itself, the ubiquitous language should also translate, what you said is, without any collision, without any clash of understanding of a particular term. So let’s say, a user, you’ve mentioned is in one bounded context. Yeah. It’s clear what is the term used in this bounded context. But in another bounded context, it might mean something different depending on that context.

And then another thing that you mentioned, the funny story about the integrating between two teams. I think what I understand is something related to like integration of the bounded context, and what the book says, it’s about context map, right? So how do you actually map between two bounded contexts? There are different ways of how you can integrate things, like what you mentioned: partnership, customer supplier, conformist, and things like that. Those are the key things that I just listen from you.

[00:26:51] Subdomain

[00:26:51] Henry Suryawirawan: There’s another thing that I think also worth to clarify, which is about the term domain and subdomain. So in the DDD, it’s clear domain is like business domain, but there’s another term called subdomain. What do you think is subdomain?

[00:27:04] Vladik Khononov: Yeah. So the term subdomain is pretty challenging to define. The idea is that a subdomain is a business building block. Now, let’s say, we have two companies working in the same industry. So they will have the same business domain. But they are not the same company. They have different ways. They are competing in their markets. They have different offerings. So what differentiates them is their subdomains. So subdomains are like puzzle pieces that complete that whole picture of how the company is planning to succeed in its business domain. These are activities that you have to implement, because of your business strategy, because of how you want to differentiate yourself from your competitors, or because you just have to, because that’s the law, for example, accounting, you have to do it.

So subdomains, as a starting heuristic, they’re usually correlated with organization units, departments. But that’s a too coarse grained boundary of subdomain. Usually when we look deeper, we can find a more, speaking in software engineering terms, coherent sets of use cases that are interrelated, that are either working on the same data, or implementing related business logic. The ones we are able to find those interrelated sets of use cases, they’re usually the more optimal boundary for a subdomain. Subdomain is this concept, its whole purpose is not to describe how organization works. For that, we need something else. That’s business capabilities. And that’s a more complex model because it’s hierarchical. There are different levels of business capabilities. Subdomains are more simple. We have only two levels here. We have business domain and beneath it is subdomains. By definition, it’s going to lose some of the precision about how the company works. So we have to concentrate on what is really important for the software system that we are building. We have to decide whether the boundary of a subdomain that we found is good enough for our purposes or not.

For that, another good rule of thumb is to look at a type of subdomain. That’s something that we didn’t talk about before. So let’s do it quickly. According to Domain-Driven Design, we have three types of sub domains. The first one is a core subdomain. Core subdomain is how the company differentiates itself from its competitors. It’s something that you have, but competitors don’t. At least you are planning to make more money than they are. So that’s all kinds of intellectual properties, like patents or clever algorithms that are invented in their organization. They may present a novel way to solve some problem, or they just optimize an existing solution, allowing it to be solved more efficiently, in a more cheaper way. In one way or another, that’s something that you want it to stay in your company, because if your competitors will have it, that’s bad news. That means you just lost a bit of your competitive advantage.

The second type of subdomains are generic subdomains. They are the opposite of core. So there is no competitive advantage here. These are solutions that are used by all the companies in the industry, and probably in other industries as well. And the good example here is an encryption algorithm. The last thing you probably want to do is implement your own encryption algorithm. Unless that’s your core business, that may be something else. But if not, you better be using some existing solution, right? And your competitors are going to use it as well. That’s not going to affect your bottom line. It’s not going to affect your business strategy. So that’s a generic subdomain. Some solved problem. Problem you have, but you have an existing solution. You just have to go ahead and use it. It can be buying an off-the-shelf product, adopting an open source solution. But anyway, the bottom line is that you and your competitors will use the same solution and doesn’t affect your business.

The third type of subdomains are supporting subdomains, and they are somewhere in the middle. Again, as in generic, there is no competitive advantage here. But on the other hand, as core subdomain, that’s something you have to implement in-house. And you have to implement it in house not because you want to, but because you have no choice. Because there is no generic solution available. In their nature, supporting subdomains are generally way more simpler than core subdomains. That involves some simple implementation. Because it’s simple, there might even be a generic solution, but you will choose not to use it, and instead, just to implement your own, because it will be easier to roll out your own solution than to integrate another one. Implementation is easier than integration.

So these are three types of subdomains: core, supporting, and generic. My rule of thumb is to look deeper into a subdomain, and decide whether you should decompose it further, only if decomposing further will produce subdomains of different types. But if you see that, I keep looking further, I keep decomposing it, but all of them are just of the same type, then it will help us to make better software design decisions. We can just stop at the first level that produces that type that we are working with.

[00:32:22] Henry Suryawirawan: Thanks for explaining all this concept about subdomains and the three different types. So there’s the core, supporting and generic, right? Just to recap the strategic part. We have the ubiquitous language. We have the bounded context. We have the context map. How to integrate between two or more different bounded contexts. And the last one is the differentiation between the domain and subdomains, where you have the three different types.

[00:32:44] DDD Tactical Design

[00:32:44] Henry Suryawirawan: So that’s a strategic part, which is the most important thing in DDD. Let’s move on to the tactical design, which is probably what some software developers are excited about when they write software. What do you think is the description of tactical design here? And why it is also one of the key thing in DDD to get right?

[00:33:01] Vladik Khononov: Yeah. So we said that strategic design is about what you’re implementing. What are going to be the components? Tactical design is about how we are going to implement them. So here we have different ways of implementing the components, business logic. These patterns are the function of a type of a subdomain that we are implementing. If it’s generic, then we are just using an existing solution. If it’s a core subdomain, we need a design pattern that will address the complexity of that core subdomain. If that’s a supporting subdomain, that we need simple pattern because otherwise, we will be over-engineering.

Another aspect that is covered by tactical design decisions is how we’re going to architect the overall work of the components, like its internal components. How it’s going to work with the database? How it’s going to work with user interface, etc? So we have architectural patterns, namely layered architecture, which usually is more useful for supporting subdomains, or when you are integrating a generic subdomain. We have ports and adapters, which is also called hexagonal architecture, which is also called onion architecture, which is also called clean architecture. So here’s another example why ubiquitous language is important, right? And we have CQRS architecture. CQRS is more advanced one. Which pattern you are going to use for designing your architecture and for implementing the business logic depends on the type of the business subdomain at play, what you’re working on. That’s the function part in software design equals function of business domain.

[00:34:36] Aggregate Pattern

[00:34:36] Henry Suryawirawan: So it seems like there are plenty of tactical designs. If I read from Eric Evans' book, or in your book as well, there are a lot of things. One thing that I want to clarify with you, which seems to be one of the most important tactical design is about the concept of aggregates. So a lot of people actually are confused with this aggregate pattern. Similarly, when I was learning about DDD as well, I stumbled upon aggregate. Didn’t actually completely understand. And maybe you can also strengthen my understanding now. So what is actually an aggregate?

[00:35:07] Vladik Khononov: It’s a complex object. I think the aggregate pattern deserves its own book. So aggregate is an object that encompasses both data and all the behavior, all the business logic that affects the data. In other words, everything that can change the data of an aggregate should reside in the aggregated boundary. No outside components should be able to change its data. And the reason for that is simple. Usually, we’re using this pattern when implementing some complex business logic. If it’s complex, and if you allow external components to go ahead and just modify your data, then sooner or later, there will be some business rules that affect those pieces of data. And those rules are going to be duplicated. Duplicating business logic is usually not a nice idea, but duplicating complex business logic is usually a terrible idea. And that’s what aggregate pattern is supposed to prevent you from doing.

The second thing is, an aggregate is not a flat record in a database. Instead, it’s a hierarchy of objects. So an aggregate can be a user with a collection of interests, and each interest will have its own collection of related websites. All that data can reside in the same aggregate. So the next question is where do we stop shoving things into the aggregate? Because it may sound tempting, you know, to just say, hey, so an aggregate is a hierarchy of objects. That’s a pattern for implementing complex business logic. So we’re going to use it. Where do we decide where we stop putting things in?

Maybe we show them. Let’s just take that enterprise ERD diagram from one of the walls in the organization. One of those scary diagrams that are put there just to impress people how complex things here are, but no one really uses it or even understands it. Let’s put all of it in the aggregate. Will that work? No, it will fail miserably. Why? Because an aggregate is not only a boundary of data and behavior, but it’s also a transaction boundary. Meaning that all the changes in the data of the aggregate should be committed in one atomic transaction. That means if you put all of our enterprise ERD diagrams in the aggregate, it means we’ll be able to run, execute concurrently only one transaction, which is probably not a good idea in any organization. So we want to make it efficient.

So we have to look for smaller boundaries, more efficient ones. And the rule of thumb I’ve learned from Vaughn Vernon back in the days, even before he wrote the red book, he wrote a paper called “Effective Aggregate Design”, and it was worth of gold. It was an amazing insight into how to design aggregates properly. What he says there is, since it is a transactional boundary, use that as your heuristic for choosing boundaries of the aggregate. Make sure it includes only the data that has to be strongly consistent for implementing the business logic that resides in it. So whatever has to be strongly consistent, leave it in the aggregate. Everything else that can be eventually consistent, put it into another aggregate or another component, whatever. But in the aggregate, you should only have data that has to be strongly consistent. How do you know whether you needed to be strongly or eventually consistent? Well, try to evaluate both paths. What’s going to happen if something is eventually consistent? Can you implement all those business rules and business logic correctly? Or will it lead to corrupting your data? When you are analyzing it in such a way, usually it’s pretty evident what information you need strongly consistent, and what information you can have eventually consistent. So that’s an aggregate in a nutshell. It incorporates data, behavior that affects it, and the transactional boundary around all that data.

Now, because all the behavior belongs to the aggregate, we have to expose a public interface that will allow us to execute it. Usually we call it a command. So we’re executing a command on an aggregate. And by command, I mean, not some message that you put in message bus or whatever. No. That’s offensive way of saying that you have a public method. So you have a public method. That’s your command. It’s doing something. That’s your public interface. That should be the only way to modify the contents of the aggregate.

Very important part of an aggregate’s public interface are domain events. Because sometimes aggregates can be pretty big. You better keep them small, but it depends on your business domain. There are some important business events that can happen in it. So, for example, if you’re implementing a user. User may add a new interest, and other components may be interested in that event. Calling those components from the aggregate is going to be a bad idea. What we can do instead is have the aggregate raise what we call a domain event. Of course, the domain event has to be formulated in the ubiquitous language, in the language of the business. So in this case, it will be “interest added”. So once the change, the aggregate is committed to the database, we need to publish that domain event so that whatever component is interested in it will be able to subscribe, and to do something related to that occurrence of domain event.

So that’s aggregate design in a nutshell. Again, I think this topic deserves a whole book. But if you’re just looking for how to implement aggregates, I think Vaughn Vernon’s three-part article is the best source of knowledge on that.

[00:40:43] Entity Pattern

[00:40:43] Henry Suryawirawan: I’ll make sure to find that paper. You can also send it to me, so I’ll put it in the show notes. Another one tactical design, which I think deserves some kind of explanation as well, is about the entity itself, which is probably the basic fundamental core design pattern in DDD. And people refer to entity as something like, okay, it has persistence. It has an ID and lifecycle. But there’s also another anti-pattern that some people said, anemic entity model. So can you explain also this core component of the tactical design, the entity pattern itself?

[00:41:15] Vladik Khononov: Yeah, to be honest, I wanted to exclude the entity pattern from my book. But the technical reviewers were not a fan of that idea. So I had to put it back. And the thing is, when we see this entity thing discussed on the same level with aggregates, we start to think that these are two patterns that you can choose from, which is not right. An aggregate is an entity. Remember, we said that an aggregate is a hierarchy of objects. So it’s a hierarchy of entities. An entity is a building block in the aggregate. The main reason we need that entity is to differentiate it something from a value object. So value object is the important thing here, not an entity. The difference between them, as you said, an entity has an ID. A value object, on the other hand, can be identified solely by its values.

The best example here is a person. Two people can have the same name, but they’re different persons. So they need some way to explicitly identify them. So a person is an entity. It needs an explicit ID. A value object, on the other hand, can be identified by its values. So color green is green. Can be light green, can be a different shade of green, but once you have a specific shade of green, it’s going to be green. It’s not going to be red in other system. So you don’t need an explicit ID to identify that. That differentiation allows us to model those value objects as immutable objects in code. Immutability makes some things more simple and easier to model. And again, as entities, value objects are not independent. You cannot use a value on its own. It has to describe something. So it’s a property of an entity residing in an aggregate. So that’s the hierarchy of those three core patterns. Aggregate contains entities described by value objects.

[00:43:09] Henry Suryawirawan: Thanks for clarifying all this. I really think these three different patterns, so to speak, or maybe tactical designs, are the critical piece of the tactical design part of DDD. Make sure you get it right. And there are plenty other more, which you can refer in the book.

[00:43:24] Implementing DDD for Legacy System

[00:43:24] Henry Suryawirawan: So Vlad, if people want to implement this DDD. Everyone seems to love about DDD. But sometimes they work with legacy code base or existing systems. So what are your tips for people who want to start with DDD, but yet they are stuck with legacy software?

[00:43:39] Vladik Khononov: Yeah. So somehow we’ve got this wrong understanding of that domain-driven design can only be applied for greenfield projects, which again, I was very lucky to have that opportunity, but it’s very rare. Most of our work is brownfield projects. Ironically, brownfield projects can benefit the most from some DDD treatment. So when implementing Domain-Driven Design in the brownfield project, the main thing you need is patience. You have to be patient about everything.

I have a whole chapter in the book talking about it. I think I called it Domain-Driven Design in real life. Not in some imaginary heaven where everything is greenfield, and everybody knows what Domain-Driven Design is, and proficient in designing aggregates and value objects, etc. No. Usually, it’s a brownfield project. Usually, your teammates have no idea what Domain-Driven Design is. In some cases, they don’t even want to know about it because they are not really interested in learning. And you have to find your way into making that design better by implementing Domain-Driven Design. So in those cases, I usually suggest to start with mapping the existing solution. So you have this brownfield project you want to evolve with, but before you even start thinking about where you want to go, you’ll have to be sure that you know your starting point. So you have to map those bounded context that you have. Now, of course, those are not going to be Domain-Driven Design’s bounded contexts. They won’t necessarily encompass coherent models. But still, these are components that you want to change. So you have to find them, map the bounded context that you have. You have to map how they’re interacting with each other, those integration patterns.

Once you did that, the next step would be to start learning the business domain. And usually it’s done by building a ubiquitous language. In real life, it’s challenging, especially for brownfield projects. Because if there is a language that has been spoken for a while in the company, it will take lots of time to change it. So in this case, I will suggest to be the example to go ahead and speak with domain experts. Make sure you understand them. Make sure you can communicate in the same language. Try to identify some wrong assumptions about the business domain that are already implemented in the code. Once you started cultivating the shared language, use it at least yourself in your code, when you’re talking to people.

So it will take time for that ubiquitous language to be adopted in the organization. But again, be the example. Make sure that whatever you’re producing is in the ubiquitous language. When communicating with people, resort to the principles behind ubiquitous language. Why do we want to make sure that each term has only one meaning? Because we want to eliminate assumptions. We want to eliminate inconsistencies in the communication. So when you are talking with people, you can use those principles as a reason to try and change the way they’re using the terminology of the business. Again, it will take more time, but it will work. You just need patience. You just need to be patient about it.

[00:46:36] Henry Suryawirawan: So thanks for emphasizing the patience. And I think reading the legacy code base itself could be challenging in terms of understanding the mental model that was used when the software was built, and also maybe the domain experts have long gone. So, you’re just left with a piece of code which you are trying to understand.

[00:46:52] 3 Tech Lead Wisdom

[00:46:52] Henry Suryawirawan: So Vlad, thanks so much for explaining the DDD. I think it’s really great for people to learn more about DDD. Your book, I think, is one of the great resource s that people can use to learn DDD. And before I let you go, I have one last question that I always ask from all my guests, which is to share what I call three technical leadership wisdom. So an advice from you to tell people based on your journey, based on your experience, and maybe based on your architecture experience as well.

[00:47:19] Vladik Khononov: Yeah. So the first one would be to apply the Domain-Driven Design thinking everywhere. And by that I don’t mean to apply Domain-Driven Design everywhere, but think about problems and solutions and the connection between them. So when someone tells you about a best practice, like some design pattern or technological solution, that is the absolute best practice and should be used everywhere, don’t believe them. Instead, treat it as a solution to a problem. Once you have this solution, ask what problem is it solving? Is that necessarily a problem I have? And this applies both to best practices and what they call anti-patterns.

And let’s take the more extreme example, big ball of mud. That’s definitely not something you want in your production code, right? That’s an anti-pattern. Well, let’s talk about it as a solution. It produces code pretty fast. Code that probably works. Probably, its first version is going to work. The second one is going to break apart, but the first will work. So in what kind of problems would you need such solution? Maybe when you’re building a POC, proof of concept. You need to show something that works to potential customers, whether they will like it or not. Going ahead and implementing event sourcing and CQRS there will be just a waste of time. Now, of course, you have to treat it as a throwaway code. Because again, big ball of mud will work on its first version, not the second one. So you have to keep that in mind, but it will be more efficient. You treat it as a learning experience. You’re learning about the business domain. You’re learning about your customer’s needs. So go ahead, use a big ball of mud. Implement it. That’s not something you should avoid everywhere at all costs. If you go back to lean startup book, it says that your first solution can be a PowerPoint presentation that just mimics an app. Go and implement event sourcing in PowerPoint presentation. It’s okay to sometimes cut corners and do something that works. So again, whatever someone is trying to convince you about or to sell you, treat everything as a solution to a certain problem. Identify the solution and look for problems which are addressed by it.

Let’s talk about problems because there are different types of problems. When talking about evaluating problems that we are solving, that we are dealing with. I like to use the Cynefin model. So Cynefin model is a decision -making framework that was implemented to help leaders to take actions in different types of problem domains. Let’s discuss three out of five. So the first one is “obvious”. These are problem domains which are obvious. You know what problem you have and you know how to solve it. The second one is “complicated”. “Complicated” means you have a problem, you don’t have a solution, but you know that there is someone you can consult, who is an expert in that field, and they will provide you a solution. It can be a person, it can be a book, it can be a Google search or whatever. That’s “complicated”. Third one is a “complex” domain. “Complex” means that we have a looser relationship between a cause and effect. In other words, I’m not really sure what’s going to be an effect of doing something, and no book, no external expert can tell us. Therefore, to make a decision, we have to conduct a safe experiment. It shouldn’t be something big or a huge undertaking. We just have to make small experiments to better understand the nature of that domain.

By the way, these three domains can be correlated with subdomains of DDD. So “obvious”, probably “supporting”. “Complicated”, where we need to consult someone and that’s generic subdomain. And “complex”, these are core subdomains. So core subdomain is complex, and that complexity causes us to not to be so sure about the outcome of doing something. The safe experiment that we are doing can affect that whole problem landscape because it can trigger some emergent behavior. So we did something and that changed the whole problem that we’re trying to solve. And it’s crucial to keep that in mind, to differentiate between something that we can consult someone about. Complicated and complex, something which requires a different, let’s call it, thinking model of approaching such problem.

Why it’s important? It’s important because in our culture, we celebrate confidence. Another story from when I just started. Someone told me when you’re talking to your boss, you have to answer quick and you have to sound confident. Even if you have no clue what you’re talking about. That can work for a complicated domain. Because even if you have no clue what you’re talking about, you can do some Googling, you can talk to someone, you will find the solution. But if you are dealing with something that’s complex, that’s a whole different beast. It doesn’t mean that you should say, “Hey, I have no idea. But someone else will probably do a better job than me.” No, definitely not. But you have to make sure that it’s explicit that in order to find the optimal solution, you have to conduct some safe experiments. You have to understand that problem domain better. It’s crucial, especially when implementing core subdomains. So those were two.

And the third one is going to be, don’t be afraid of conflicts. Going back to this topic of introducing Domain-Driven Design in brownfield projects. When you have people working on the project, and suddenly you’re telling them, “Hey, I read that amazing book over the weekend, and it says that everything that you are doing here is wrong.” That’s going to trigger some conflicts. So, of course, you have to do it in a gentle way. But one way or another, it will lead to conflict. It will lead to people saying, we don’t need that aggregate stuff or that event sourcing is not going to work. That’s another part of our job, which is more related to people than technology, when you have to sell those solutions. We have to explain why this is the optimal solution for the problem at hand. So my advice here would be, first of all, not to try to escape such conflicts, but embrace them because the only way to sell something is to resort to principles behind the solution. So if we are discussing aggregates, why can’t we expose a public setter as well? Well, because that way, it can lead to duplicated business logic. Do you want duplicated business logic? Probably, they will tell you no.

By the way, in my book, the focus I put on the concept behind Domain-Driven Design, the principles behind them. So make sure that you understand it. When selling Domain-Driven Design or anything, resort to principles behind those solutions. Why they were designed in the way they are? Another benefit of having this conflict, it will uncover some blind spots in your understanding of Domain-Driven Design over the way you are trying to sell. You can be senior engineer getting questioned from a junior engineer, and you have no idea how to answer it, because they have a different way of thinking about the problem. Once you have that area of the solution explicit, it will help you to do some further research and to understand it better, to understand maybe crucial part that you are missing. So anti-patterns and best practices, don’t trust anyone, use Cynefin to identify complex domains, where you need to do some experiments to find the optimal solution. And don’t be afraid of conflicts. Use them to make you a better professional engineer.

[00:54:32] Henry Suryawirawan: Wow. It’s beautifully explained and also described. I really love all those three. So thanks so much for emphasizing this problem and solution thinking. Sometimes we jump into solutions straightaway, or sometimes we read some blogs or some books saying, “Yeah, this is the holy grail of everything.” Thanks for reminding us that actually you should think about what is the problem that solution is trying to solve.

So Vlad, it’s been a pleasure talking to you. If people want to continue the conversation or find your book online, where they can find it?

[00:55:03] Vladik Khononov: Yeah. So my book is available on Amazon. It’s also available as many other books on O’Reilly’s online learning platform. Right now, I’m working on my next book, which is called “Balancing Coupling in Software Design”. If everything goes according to plan, it’s going to be released in second quarter of 2022. I have a blog which is quite boring in the last year because I was working primarily on the book. And I have Twitter account, so you can follow me. My DM is open. If you have any questions, you can just DM me.

[00:55:32] Henry Suryawirawan: I’ll make sure to put that in the show notes. So good luck with your second book coming. So hopefully we can have another conversation by then.

[00:55:40] Vladik Khononov: I’d love to.

[00:55:41] Henry Suryawirawan: Thanks, Vlad.

[00:55:42] Vladik Khononov: Thank you so much for having me. It was a pleasure.

– End –