Simeon
Posted on January 26, 2024
Introduction
Eric Evans introduced the concept of Domain Driven Design (DDD) to the public through his book published in 2003, which is titled "Domain Driven Design: Tackling Complexity in the Heart of Software". Since then, DDD has become a well-known term in the software industry and is regarded as a crucial practice for creating high-quality software.
If you are an expert in technology and planning to develop a large, complex business application, DDD is a safe approach to consider. The goal of DDD is to make your software reflect a real-world system or process, and you are required to collaborate closely with a domain expert who understands the workings of the real-world system. However, it's important to keep in mind that DDD may not be necessary for all software projects, and you should only consider it if you recognize the problems it solves. This article will help you determine if you should use it.
What is Domain-driven design (DDD)?
Domain-Driven Design (DDD) is a method of software design that is centered around the subject or "domain" of the application being developed. For example, if an app is being created for online shopping, the subject area of the app would be the "domain." To manage large domains, the model can be divided into smaller sections known as "bounded contexts". In an organization that deals with food, for example, this could mean separating the sales and delivery departments, each with its own responsibilities and experts. This approach helps to simplify and organize the development process.
DDD is an agile method for developing complex software that closely aligns with the business domain. It places a significant focus on communication and collaboration with business domain experts, who can provide insights into how the real-world system works. This approach is mainly applicable to large-scale applications and organizations, but is not suitable for smaller, simpler applications like CRUD systems.
Effective communication between domain experts and developers is critical for successful collaboration in DDD. The approach uses "ubiquitous language," which means using the same terminology for the real-world concept being modeled, the software equivalent, and any structures that may be used to store the concept. This helps to avoid misunderstandings and inaccuracies, and the concepts described in the ubiquitous language should form the basis for the domain model.
Guiding principles of Domain driven design
Basically, DDD is about developing software that models real-world systems and processes. The principles guiding the DDD approach include:
Focus on the core domain: Before you begin coding, talk to people who work in that domain. They can help you to define all of the processes, procedures, and terminology of that domain. For example, if you are designing software to manage retail inventory, talk to the people who manage the store inventory rather than employees in HR or finance.
By basing designs on domain models, you can reduce complexity: Create a model that reflects the real-world domain once you have a firm understanding of the business domain. Inventory trend analysis, automatic restocking, barcode scanning, and other capabilities that are crucial to inventory managers should be included in your inventory management software. The organization and abstraction of the domain expert's knowledge are represented by the model, which can be a written paragraph, chart, or diagram.
-
Speak a common language: In his book, Evans talks about the importance of ubiquitous language. All project participants should communicate using a consistent language when discussing the domain. Listen to the words and phrases your domain experts use. Adopt the same terminology in your requirements document, in the model, and in the code itself.
Structure of Domain-driven design
Application layer: In our online shopping application example, the business domain here is to process an order. So the customer needs to browse the product, choose an item, confirm the order, pick a shopping fee, and pay. The user interface is where the customer can browse or initiate their order. This layer shows information to the client and interprets their actions. This is the front end of the application and is all the user can see. The application layer leads the user from one UI layer to another and interacts with other application layers. Its purpose is to organize and delegate domain objects to do their job and it's the only layer accessible to other bounded contexts.
Domain layer: The domain model layer is the core of business software, where concepts of the business, information about the business situation, and business rules are represented. The state that reflects the business situation is managed here, while the technical aspects of storing it are handed off to the infrastructure. It is the center for expressing the business. These include:
Entities: Entities represent objects by giving them a common identity. Typically, entities are stored in persistence with a key that allows for later retrieval.
Aggregates: These represent groups of objects that should be persisted as a unit.
Value objects: these represent concepts that can be compared on the basis of the sum of their property values. For example, date range consists of a start and end date.
Domain events: represent things happening within the system that are of interest to other parts of the system.
The domain layer should encapsulate complex behaviors and not just be a collection of properties. An anemic domain model, lacking behaviors, is not considered desirable in Domain-Driven Design (DDD).
3.
Infrastructure Layer:
This layer provides support for communication between other layers and may contain libraries to aid the UI layer.
What are the patterns Domain-driven design employs?
DDD employs various patterns to structure its design, including:
Repository Pattern
This pattern provides an abstraction for data storage, allowing the application to interact with a simple interface that resembles a collection. Operations such as adding, removing, updating, and retrieving items from the collection are straightforward methods that do not require knowledge of database concerns, like connections, commands, cursors, or readers. The repository pattern promotes loose coupling and can keep domain objects' persistence ignorant.
Factory Pattern
This creational pattern uses factory methods to create objects without specifying their exact class. It encapsulates the complexity of object creation.
Services
Services are used to encapsulate complex behaviors and infrastructure implementation details. According to Eric Evans' definition of a service in his book "Domain-Driven Design," a service is a DDD building component that symbolizes a major process or domain transformation that is not an inherent duty of an entity or value object. Services should be declared as stateless interfaces defined in the language of the model and should have operation names that are part of the ubiquitous language.
Command
This pattern decouples the act of issuing commands and executing the command itself.
Specification: DDD uses the Specification pattern to solve the problem of placing querying, sorting, and paging logic. The specification pattern describes a query as an object, allowing for a more flexible and scalable solution.
Characteristics of a good domain model
Models the problem domain correctly: A well-crafted domain model accurately represents the problem domain, but it does not have to be a replica of the real world. It should only include relevant information that is necessary to solve the problem at hand, while excluding any unnecessary details. Additionally, the relationships between the entities in the model must be accurate. However, to assess a domain model using these criteria, one must have a good understanding of the problem domain.
Speaks the right language: It is crucial to use appropriate terminology in a domain model, which is a depiction of a specific problem area. This helps to eliminate confusion and miscommunication between the expert and developer. Proper naming of the elements in the domain model ensures that both parties are on the same page and minimizes the risk of misunderstandings that can compromise the quality of the delivered product. Determining if the domain model meets this requirement is straightforward. If the elements are correctly named, the customer should be able to comprehend the model with ease.
Claims ownership of its information: A Good domain model asserts control over its information. It should have methods for modifying its contents and block any unauthorized changes to the information under its jurisdiction. The use of a single entry point to the information in a domain model offers two key benefits: it eliminates redundant code and ensures the consistency of the domain model. Adhering to this principle leads to clearer and less prone to errors in code, which should be the aim of every software developer.
Provides built-in support for logging: The domain model should have integrated logging functionality for ease of use. Because it is often useful to include the details of an object in a log message, the domain model should be straightforward to retrieve the information of an entity as a string. This eliminates the need for manual construction of log messages, as all you have to do is attach the relevant object to the log.
Is covered by unit tests: This aspect of having a well-constructed domain model being covered by unit tests is self-evident for experts, but relying on assumptions can be hazardous. I understand that strict guidelines can sometimes be problematic, however, I believe that it is possible to provide a clear rule for unit testing any domain model. The rule is straightforward: test every method that is not a getter or setter.
Advantages of Domain-driven design
Easier communication: Thanks to the ubiquitous language, communication between developers and domain experts are much easier.
Object-Oriented: As DDD follows an object-oriented approach, the entire domain is based on objects which provide more flexibility, making it easier to modify and improve the system.
Cleaner Code: Adopting DDD leads to cleaner, more robust code. By using best practices and design patterns, future projects are likely to run more efficiently.
Emphasizes Domain Over Interface: DDD places a strong emphasis on the domain and takes into consideration the input of domain experts, resulting in applications that accurately reflect the domain and resonate well with its audience. This approach prioritizes the domain over the UI/UX.
Disadvantages of Domain-driven design
Requires Domain Expertise: One of the limitations of DDD is that it requires deep domain knowledge, even for experienced development teams. There needs to be at least one specialist who understands the subject that is the focus of the application.
Inappropriate for Highly Technical Projects: While DDD is well-suited for complex business domains and logic, it may not work as effectively in highly technical projects where it is challenging to establish a common language that can be understood by both developers and domain experts.
Emphasizes Iterative Processes: While some may see this as a positive aspect, DDD relies heavily on iterative practices and continuous integration to build a flexible project that can adapt as necessary. This may not be suitable for organizations that are used to less-adaptable development models.
Communication Problems: Communication problems within development teams often stem from misunderstandings of the domain language and ambiguities in the language itself.
High Cost: To maintain the domain model as a clear and helpful language construct, a lot of isolation and encapsulation must be implemented, which can result in a relatively high cost for a DDD-based system.
###When should you apply Domain-driven design?
DDD is appropriate for large applications with significant business complexity and the need for domain expert knowledge. The domain model should have significant behavior that represents business rules and interactions beyond just storing and retrieving records.
If your system has 25-30 service interfaces, each with multiple methods, it might be considered complex and would benefit from using DDD. If there are 30-40 user stories or use case flows, it could also indicate the need for DDD.
Even if the application does not seem complex now, consider whether it may grow in complexity in the future. If there are indications of moderate complexity, it may be best to assume it will be more complex and use DDD. Working through complex usage scenarios with domain experts can help determine the level of complexity. If domain experts are already asking for more complex features, it may indicate that the application is or will soon become too complex to use a CRUD approach.
If the domain is new and unknown to you and your team, it is likely to be complex and DDD is recommended. You will need to work with domain experts and experiment with models to determine the complexity level.
When shouldn't you apply Domain-driven design?
The practice of Domain-Driven Design (DDD) involves significant investments in modeling, architecture, and communication, which may not be necessary for smaller or CRUD (create, read, update, delete) applications. If you follow DDD, but find that your domain model lacks behavior, it's possible that DDD is not required for your application or you may need to refactor it to include business logic in the domain model, instead of the database or user interface.
A practical approach would be to use DDD only for complex or transactional parts of the application and not for the simpler CRUD or read-only parts. For example, there's no need for Aggregate constraints when querying data for a report or dashboard. In such cases, a separate, simpler read model is sufficient.
If your system requires less than 30 business operations, it is likely to be straightforward. This would mean that your application would have a maximum of 30 user stories or use case flows, each with minimal business logic. If you can easily develop such an application using frameworks such as Ruby on Rails or Groovy and Grails without struggling with complexity and change, then DDD is probably not necessary for your system.
Conclusion
In this article we have discussed when and when not to employ Domain driven designs. For example we shouldn't use DDD when we want to develop a simple app that uses the CRUD(create, read, update and delete) system and use it for large applications with business complexity. If your organization wants to develop software that seamlessly integrates with the business domain, you may want to consider implementing DDD. I hope you found this article beneficial.
Posted on January 26, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.