Software development and a game of chess. At first, it might not be obvious to compare these two subjects and they might seem fundamentally different for you; however, these two topics are based on navigating an abundance of possibilities and choices and have more similarities than you could anticipate. In this article, I will take you through the strategic and tactical principles of Domain-Driven Design (DDD) comparing it to strategies and tactics of a chess match.
The objective of chess is very clear: we want to win the game! However, this is challenging. Let’s imagine the beginning of a game: each Pawn can move one or two squares and each Knight can also make two different moves. So, there are twenty different options to make the first chess move. To make things more complicated, after our first move it’s our opponent’s turn and then we must come up with a new decision. The number of possibilities increases exponentially as we try to calculate the movements that can be done depending on our opponent’s decision. Some great masters are reputed to predict 15 to 20 moves ahead.
So, how do we know what is a good opening movement? Chess strategy can guide us. In the chess strategy the game is divided into three phases: opening, middle and end game. In the opening, we must follow these principles: control the center of the board, develop our minor pieces — the Knights and Bishops — castling to protect our King and move our Queen to connect our Rooks. After accomplishing these principles, we finish the opening phase and enter the middle game. Studies have proved that following these principles improve our chances of winning the game.
Having the opening strategy clarified it looks easier to choose our first move. For example, we can move our Queen Pawn to d4, and it seems perfect according to strategy principles and it meets two strategy objectives. First, the Pawn now is in position to control c5 and e5 squares and so we are in the center of the board and one step closer to get control of it. Second, it gives space for our Bishop and Queen to move.
As stated before, the number of possible moves in a chess game can be overwhelming and strategy helps us find faster and better ones. The mental technique of taking shortcuts to solve complex problems fast is called heuristic. It provides us with results that are good enough for our immediate goals. This is useful when we need to make a decision, but we would take too much time analyzing all the information and possibilities. Bringing this to our discussion here imagine it is your turn to make a move in the game and there are around 20 different possibilities, however now you know there are strategies you can follow and reduce this number to 5. The idea is that heuristic would help you choose within these 5 possibilities, making it possible for you to make a good move, not necessarily the best, but fast since you had less options.
It has been said that the objective of a chess game is to win. In comparison, what is our goal in an IT project? The simplest answer is that we must resolve a business problem with a software solution. Therefore, the most important element in a software project is to understand the problem, because no matter how good our implementation is, if we don’t understand the business requirements it will be impossible to achieve our purpose.
Furthermore, as in chess, in the IT world we are also overwhelmed with information and different possibilities. For example: how do we evaluate our options and choose the best one to build a software that can suit the business problem? Depending on the domain complexity the number of options is huge and it’s difficult to make a decision.
Domain-driven design (DDD) is a technique which was created by Eric Evans in 2003 to help us improve the communication between businesspeople and IT and give us heuristics to decide the best software implementation. In the same way which chess strategy helps us choose what piece we should move to start the game, DDD strategies also help us make choices to build a software that serves the business needs.
The strategies, simplifying, are to identify the business domain and its subdomains, build the ubiquitous language and design the bounded contexts. We should first understand these concepts and then see how they can help us build software projects.
The business domain is the market in which a company is inserted such as investments, credit card, marketing. It is divided into subdomains which are the business building blocks working together and allowing the company to exist. Let’s take a retail company for example, some subdomains could be customers, accounting, and stocking.
There are three types of subdomains: core, generic and supporting. Core subdomains are the important ones because they differentiate a company from others and it’s what makes the company special and successful. They are complex and are always changing to generate improvements.
Supporting subdomains are the simple ones, they don’t change too much and don’t make the company unique. However, we must build them ourselves because there are no pre-made solutions available, or it’s just an easier solution rather than developing the integration with a ready-made one.
Generic subdomains are complex but not unique and so they don’t make the company special. They are problems that have been solved before, even by other industries, and there are solutions out there that we can use, as software you can buy or use for free. For instance, think about encryption, unless this is the core business of the company it is smarter to use something that is already made instead of developing it from scratch.
In chess we wonder which piece we should move first. In a software project we ask what type of architecture we should use. Perhaps, layered architecture? Hexagonal architecture? Command and query responsibility segregation (CQRS)? Strategic DDD gives us some heuristics to decide. Depending on the subdomain type we can pick the best architecture. For a simple supporting subdomain, we can go with layered architecture but for a core subdomain, which is complex and changes often, hexagonal architecture could be a better option.
As mentioned earlier, communication between businesspeople and IT is challenging. Often, there are two separate languages: one understood by domain experts, and another used by software programmers. This issue increases the cognitive load on teams and makes misunderstandings more likely. It’s a bit like the telephone game kids play. The requirements from businesspeople need to go from the language domain experts use to the one programmers understand, and, frequently, this translation is far from perfect.
The strategy proposed by domain-driven design to tackle this problem of communication is to adopt the same terminology used by the business specialists in everywhere in a software project. This means that the same terms used in the meetings between the domain experts and IT people will show up in domain models, tables, and programs. That’s why the name of this pattern is ubiquitous language, which is a single language used everywhere to keep things clear and consistent.
However, when people talk, some words can have different meanings depending on the situation. For instance, in a sales context, “customer” might refer to someone who purchases goods, while in a support context, it could refer to someone seeking assistance. This dubiousness isn’t a problem for human conversations, but software programs don’t admit ambiguities, everything must have one clear definition.
To overcome this problem, strategic DDD has the bounded context pattern. The idea is just like the name suggest, we delimit a context to the meaning of our terms. In our previous example of the term “customer”, we would have a bounded context named “sales” and another one called “support”. Therefore, inside de “sales” bounded context, the word “customer” is going to have exactly one meaning.
In a microservices architecture, getting the size of our services right is very important. If they are too big, they become individually very complex and difficult to maintain. On the other hand, if they are too small, the global complexity of lots of tiny microservices communicating between them is going to be high. DDD helps us with some heuristics: a service shouldn’t be bigger than the bounded context, or else our language won’t be clear, and the software could get really complicated. Usually, the size of a microservice fits well with a subdomain. The application boundaries will follow how the business works, and new features from businesspeople typically get added to a single microservice, without causing a ripple effect where multiple microservices will need to be changed and deployed together.
Strategies serve as guiding principles that steer us towards optimal choices, offering a roadmap to attain overarching objectives. Whether aiming to triumph in a chess match or excel in a software project, strategies outline the trajectory for long-term success. In contrast, tactics are more about quick results. They focus on getting things done in a short amount of time.
Chess tactics are clever tricks that players use to catch their opponents off guard or win quickly. One famous tactic is the double attack. This happens when a single move creates two problems for the opponent, and they can’t solve both. Look at the picture below: the Knight is attacking both the King and the Rook at the same time. The opponent must move the King, and in the next turn, he will lose the Rook.
While strategic DDD provides us with guidance for comprehending business requirements and crafting software solutions aligned with company objectives, tactical domain-driven design operates within the practical realm of coding programs. The three most recognized tactical patterns of DDD are value objects, entities, and aggregates.
Value objects are important components in programming that help us represent specific pieces of information, like dates or money amounts, in a clear and consistent way. They’re like little containers for data and rules that make our code easier to understand and maintain. Value objects are special because once we create them, we can’t change them, which keeps our data reliable. They’re like building blocks that help us create strong and reliable software. Value objects can be identified by the composition of their values.
Entities are essential in programming as they represent the core elements in a system that have unique identities and behaviors. Just like characters in a story, entities hold important information and can interact with each other. These objects help us model real-world concepts, like customers or orders, making our software more reflective of the actual situation. Because entities have individual identities, they’re crucial for tracking and managing data accurately. In programming, entities act as the main characters that drive our applications.
Aggregates are vital in programming because they group together related entities and value objects, creating a more organized structure for our code. Think of them as containers that hold everything needed to handle a specific part of our system. Aggregates help us manage complex data and interactions by providing a clear boundary for operations. This makes our code more understandable and reduces the chances of errors. In programming, aggregates act as the guardians of consistency and integrity, ensuring that our data stays accurate and dependable.
To wrap things up, both DDD strategy and chess strategy guide our choices. Imagine strategy as a big plan for the long run, and tactics as practical steps for right now. It’s like having a map for the journey and tools for the adventure. Despite the differences between chess and IT, they both share a common goal: a desire for success. In chess, we aim to win the match, and in IT, we strive to succeed in our projects.