By Robbert van Os
Posted on 2023-04-16T00:00:00.000Z

Mastering Domain-Driven Design

Explore Domain-Driven Design (DDD) basics, its philosophy, and methodology for effective software development using shared domain language and context mapping.

Domain-driven design (DDD), initially introduced by Eric Evans, is an approach to software development that involves a variety of interrelated techniques. Understanding the basics of DDD can lead you to question how to learn and implement it effectively.

At its core, DDD is simple: capture the domain model using domain terms, embed the model into the code, and protect it from corruption. While a comprehensive explanation would take several lengthy books, these foundational ideas are accessible and valuable. Note that the examples discussed here assume an object-oriented project, but the principles can also be applied in other contexts.

Philosophy and Methodology of DDD

DDD is recognized for its strategic value, which is why numerous businesses operating in complex domains rely on it to develop software that can quickly evolve alongside the business. Philosophy is also a central aspect of DDD, as illustrated by the term "ubiquitous language." This term emphasizes the importance of specialized language in DDD, which can be applied in three main ways:

  1. Engage with domain experts to gather the domain model using domain language. Communicate with employees at the companies you're creating solutions for to see things from their perspective. Establishing a shared language for the domain lays the foundation for coherent models.
  2. Incorporate appropriate domain terms into the source code. Classes, methods, commands, and most importantly domain events should all be named in a way that the domain expert would understand. This helps to embed the domain model in the code.
  3. Safeguard domain knowledge from contamination by unrelated fields or technical subfields. If your code discusses topics belonging to different subdomains, such as the domain solution and technical implementation, separate the code into multiple parts. This approach usually results in classes that focus on one task and use a limited vocabulary. Utilize "translators" at the boundaries of subdomains to prevent unnecessary dependencies and confusion.

Applying these three guiding principles forms the basis of DDD. Even if you're not familiar with or using other DDD practices and patterns, you can still benefit from understanding and implementing these concepts. Let's explore how integrating this knowledge into our software projects can contribute to success.

Developing Industry Knowledge and the Ubiquitous Language

The ubiquitous language concept is based on capturing the domain model in domain terms. It provides a shared vocabulary for both technical and non-technical team members, using language familiar to those in the business world.

By understanding the problem in business language, developers can better communicate with stakeholders and among the technical team. When everyone uses the same terminology and tells the same stories, the team develops a shared understanding of the challenges, which helps guide solutions that reflect the business's functions rather than the software's operations.

Before meeting with domain experts, prepare questions to ask them. Use real-world scenarios to drive domain understanding, and create simple models to capture the essentials. Have the domain experts explain processes and problems to you, then repeat their explanations using the same language. Continue this approach when discussing potential solutions, defining key concepts and clarifying misunderstandings along the way.

Domain-Driven Design (DDD) Examples

1. Domain Logic

Domain Logic refers to the rules, policies, and operations that define how the domain works. These rules are typically represented as methods and properties in the domain model's classes.

Example: Online Shopping Platform

Let's consider an online shopping platform as our domain. The platform allows customers to search for products, add them to a shopping cart, and complete a purchase. Some examples of domain logic in this context would be:

  • Calculating the total cost of a shopping cart, including taxes and shipping fees.
  • Validating that a customer's payment information is correct before allowing the purchase.
  • Applying a discount to a shopping cart if the customer has a valid coupon code.

These examples represent the business rules and operations that define how the online shopping platform works.

2. Subdomain

A Subdomain is a smaller, more focused area within the larger domain. It typically represents a specific aspect or functionality of the system that can be designed and developed independently.

Example: In our online shopping platform, we can identify several subdomains:

  • Product Catalog: This subdomain is responsible for managing the list of available products, their categories, descriptions, and prices.
  • Shopping Cart: This subdomain handles adding, removing, and updating items in a customer's shopping cart, as well as calculating the total cost.
  • Order Management: This subdomain is responsible for processing completed orders, tracking their status, and handling refunds or returns.
  • User Authentication and Authorization: This subdomain manages user accounts, including registration, login, and managing permissions.

Each of these subdomains can be developed and maintained independently, allowing for better separation of concerns and modularity.

3. Design Patterns

Design Patterns are reusable solutions to common problems that arise during software design. They provide a general approach or template that can be adapted to specific situations. DDD often uses design patterns to structure the domain model and its components.

Example: In our online shopping platform, some design patterns that might be applied include:

  • Repository Pattern: This pattern is used to abstract the way we access and store domain objects, such as products and orders. It allows us to separate the concerns of data storage and retrieval from the domain model itself.
  • Factory Pattern: This pattern is used to create new instances of domain objects, like creating a new shopping cart or order. Factories can help enforce business rules and ensure consistency when creating new objects.
  • Aggregate Pattern: This pattern is used to group related domain objects together, like a shopping cart and its items, or an order and its associated products. Aggregates help enforce consistency and maintain the integrity of the domain model.

These design patterns provide a common vocabulary and structure that helps developers build a more maintainable and understandable domain model.

Testing the Waters

Now that you've explored DDD, have you noticed any benefits to your software development efforts? Using the same term for the same object in the same context every time helps avoid misunderstandings, simplifies the code, and improves communication with non-technical stakeholders. Proceed with DDD and observe the results.