Domain-Driven Design: Dealing with Complex Domains
Domain-Driven Design (DDD) is a highly effective methodology that helps software architects:
- Better match their designs to real-world use cases
- Allow software modules to be more nimbly upgraded to match changes in business models
- Help non-technical clients contribute more effectively to software functionality
This post takes a quick look at DDD principles and practices. For purposes of clarity, terms related to DDD programming are cited with initial caps.
Even if you have little or no programming experience, we hope that you gain some enjoyment and insight from looking into the world of coding and design.
For the uninitiated, the term itself — Domain-Driven Design — may be a source of confusion. In this context, you can think of a domain as a business, organization or enterprise. For example, a university could be a domain.
Focus on the domain
DDD is a programming methodology that focuses mainly on a domain — its structure, functions, logic and language. In short, it encompasses virtually every aspect of a domain.
DDD began as a concept advanced in a 2004 book by Eric Evans, Domain-Driven Design. The methodology works especially well with complicated domains packed with complex subjects and processes. Small wonder that DDD continues to exert strong influence on programming practices today.
There are three central requisites for DDD:
- Use a domain model as the basis for design
- Create solutions to solve problems existing within the domain
- Bring programming and domain experts together to form a partnership and create a domain model
DDD works on the premise that code language and structure should be in accord with the language of the domain the code will serve. For instance, code intended for use in banking could specify methods like Deposit, Withdrawal and Transfer. Software classes might include names such as HomeEquityLoan and AccountHolder.
“Watch for ambiguity”
Evans observed, “Domain experts should object to terms…that are inadequate to convey domain understanding.” Likewise, “…[software] developers should watch for ambiguity or inconsistency that will trip up design.” In other words, code nomenclature should be straightforward and logical. Ideally, users (the domain experts) and programmers alike will understand the purpose and content of class variables, methods and names.
Evans termed this type of disciplined communication a universal or Ubiquitous Language. It lies at the heart of all DDD.
A Bounded Context is a description of a boundary (typically a subsystem or the work of a specific team) within which a model is defined and applicable. Although they may represent discrete entities, Bounded Contexts can contain both unrelated and shared concepts.
Consider a business domain of sales and repairs. For efficacy of programming, a DDD approach might divide the big domain into two Bounded Contexts, one for sales and the other for repairs. In this instance, shared concepts include customers and products, whereas an unrelated concept (such as a replacement part) might exist only in the context of repairs.
Each context describes a logical boundary, and all concepts and terminology within it contribute to a Ubiquitous Language.
Ubiquitous Language is structured around the domain model and created via collaboration between the Domain Experts and the development team. The language is then used by all team members to connect all the activities of the team with the software.
Reinforcing communication and common purpose
In programming practice, the value of Ubiquitous Language lies in its ability to reinforce communication and unity among all parties concerned. For example, when every team member uses the same terminology, communication and cohesion improve. When non-technical domain experts also speak the same Ubiquitous Language, they can communicate more effectively among themselves and with the programmers.
Rigors of language discipline
During the coding process, the rigors of language discipline can help keep things better organized and understood — whether by teams of coders or just one individual. Just like everyday language, Ubiquitous Language is dynamic. It can evolve and develop as a project changes and matures.
In one of the first steps of initiating a programming project, a software engineer/analyst conducts extensive interviews of the client regarding software project requirements. The conversations mark the beginning of Requirements Modeling.
To substantiate a complete understanding of project needs, the analyst represents them simply in a few formats, including text, diagrams and other technical representations.
The resulting models help to create both a requirements specification and a design drawing for the software project. Both should be easy for the client and programmer to understand. The model should also serve as a reference to ensure accuracy and consistency during the programming process.
Especially in early stages of development (or in later stages of product maturity), close examination of a Requirements Model often reveals missing elements, inconsistencies and errors. The evidence of shortfalls helps keep stakeholders focused on areas that need further refinement, development and definition. The Requirements Model is an essential part of any programming project, large or small.
It’s worth mentioning that any of the following elements might serve as a basis for Requirements Modeling: Scenario, Data, Class, Flow or Behavior.
Domain Modeling involves all members of the software design team as well as participants from the client side. They work together in an iterative (repetitive) process that determines the best ways in which the domain can be parsed out into logical, inter-related components.
The process is intellectually rich and rigorous. Many of the participants learn to think and rethink critically and analytically in ways they previously thought impossible. Everyone agrees to speak a Ubiquitous Language.
An iterative process
During the Domain Modeling process, participants:
1. Establish a model
2. Test and evaluate the model, observing shortfalls and flaws
3. Apply and analyze knowledge gained in step #2
4. Return to step #1
All parties involved play an active role. For example, the people who work in a domain’s shipping and receiving department probably know more about it than anyone else. They receive as much attention for their expertise as other members of the organization do for theirs.
Representing the model
The representation of a domain model can take a multitude of forms: text, drawings, flow diagrams, graphs or a combination of such elements. The ultimate purpose is to discover and portray an accurate and thorough model of the domain and entities and relationships contained by it. Finally, everyone (both technical and non-technical) involved in creating the model should be able to understand it.
Refactoring is the practice of altering computer code without changing its functionality or behavior. It typically relies on the application of micro-refactorings, each of which affects a minuscule change in source code.
The objective of Refactoring may be to produce faster performance, less memory usage or more efficient coding.
Because it is far less expensive than generating new code from scratch, Refactoring can also lower software costs. In addition, several programming languages offer IDEs that can automate many Refactoring processes. In some instances, it is even possible to convert an “anemic” domain model (one that lacks business logic and rigor) into a robust DDD structure.
Keep in touch
At SkyePoint, we design and produce cybersecurity applications of the highest caliber. Our clients include the State Department, Department of Treasury, the Environmental Protection Agency and the Department of Defense, among others. We welcome the opportunity to work with you.
To learn more
Please reach out to us at firstname.lastname@example.org for more information on our approach to Domain Driven Design or to discuss collaboration opportunities.
 Evans, Eric. Domain-Driven Design. Addison-Wesley, 2004.