Introduction
The primary purpose of most software projects is to add value to the customer’s business. This is done by abstracting the complex web of thoughts inside a human mind in the form of a software program. Most software projects cater to a particular domain, and in many software projects, the domain of a software project is not technical. Unfortunately, majority of the technical people do not give enough importance to the domain of the software, and hence, they lack the required domain knowledge. This lack of domain knowledge leads to a situation where What(to do?) takes over Why(to do?). Generally, in such a scenario, it might be possible to deliver a usable product, but the primary purpose of adding business value is often neglected.
The above mentioned situation is quite common and there is a continual influx of thoughts, which intend to provide a solution, by various experts. Eric Evans is one of such experts, who based on his experience, gained by working on complex projects, epitomized his findings in the form of tips, suggestions, patterns and guidelines, and coined a term Domain Driven Design, better known as DDD. In this blog, I intend to present various aspects of DDD and how it suggests to tackle the complexity of the domain.
What is DDD?
A picture is worth a thousand words and, sometimes, is better suited to convey a message. Similarly, a domain model is a simplification of the domain of the software and it abstracts the elements of domain which are relevant to the problem the software intends to solve. A domain model is representation agnostic, i.e., it can be represented as an UML diagram, as written code, as simply plain English, or as a simple diagram. The decision to choose an option depends upon the situation and complexity of the problem. The process of creating, maintaining and enhancing highly expressive domain model by applying objected oriented principles, design patterns is known as Domain Driven Design(DDD). One important point to understand is that DDD is not a one time activity. It is an iterative process and model evolves with the project.
We all know that the process of creating domain model by abstracting from the complexities of a domain is not an easy job. Experienced programmers/thought leaders often compare this job with that of an artist. Few would disagree with them. But, with any art, there are certain principles and practices, which make the process of identifying and representing abstractions simpler. DDD also suggests to employ certain principles and practices, which we may already be doing intuitively, to work with highly expressive domain models. Let’s have a look at some of the principles and practices of DDD.
Getting Started with DDD
There might be several questions, which may be taking shape in the mind right now. Let’s see which DDD principles and practices applies to specific question
Q: I don’t have the domain knowledge. How will I communicate effectively with the domain experts?
A: In most projects, there is an interface between the technical people and the domain experts. We may call this expert a Business Analyst, a Product Owner, or with some other name. Sometimes, this interface is not effective to transform the messages between two parties and in the process of message transformation, some relevant details are missed. This leads to a situation where WHAT takes over WHY.
To overcome this problem, DDD emphasizes to have a close relationship between the domain experts and the developers. Even when a modeler is working with domain experts(DE), he should be hands-on enough to think about design issues while brainstorming with the DE. DDD also suggests DDD developers to pick up key concepts while having conversation with the DE and also educate them about their terminology. This leads to the development of a Ubiquitous Language(UL) which forms the basis of development domain model. UL is basically a medium of communication which is used to develop a domain model. It is also used to validate a domain model periodically. The development of UL is an iterative process and is based on mutual agreement between DE and technical people.
Q: How will I represent my domain model?
A: Domain model should be represented in a way which best communicates the intent of the domain knowledge. It can be in the form of a diagram, a UML diagram, plain English, or simply code. Now, when there is freedom to represent something in multiple forms, how to maintain the sanctity of the domain model. I think that’s the job of the skilled developers or domain modelers. It is difficult to provide a rule for everything and we all know that real world is like that. Sometimes we have to break the rules and take pragmatic decisions. DDD realizes that and promotes developers to take pragmatic decisions instead of being bound by the rules.
Q: How will I layout the architecture of the application with DDD?
A: The focus of DDD is to create domain models that are rich in behavior. Typically, an application has several other issues as well which are not concerned with the domain. To work effectively with DDD, we need to isolate those issues from the domain modelling. In order to do so, we can use layered architecture to isolate and group the problems.
In a layered architecture, each layer is aware of the layers below it. In general, a layer at the lower level cannot make calls to the layer above it.
Q: How will I represent concepts in a domain model?
A: Most concepts in domain can be classified into
- Something which has an identity: Entities. Entities, which are essentially objects, identified by an identity, which does not change. The identity can be a surrogate key or a composite key.
- Something which has an important meaning in larger picture but does not have an identity of it’s own: Value Objects(VOs). VOs represent meaningful concepts and abstracts the details of those concepts but does not have their own entity. For example, a phone number is one such thing, which represent certain information, but does not make any sense if not associated with a person, place, etc.
- Something which relate various concepts with each other: Cardinality. Cardinality represents relationship between various entities. DDD advocates to have minimum cardinality between entities.
- Behavior common to various concepts: Services. Services are components which provides behavior which is not specific any particular entity. These services are different from the application service, in that, they provide services to the domain layer and not callable from the application layer.
Apart from the above, DDD also introduces the concept of Aggregates, which are essentially small group of related objects. Aggregates have a common root and act as an entry point for outer world to the constituents of the aggregate. This helps in managing the complex web of associations in a domain model.
Also, since in many cases, entities will be persisted and again constructed back, DDD advocates the use of Factories and Repositories. Factories are generally used to create complex objects and Repositories are used to reconstruct an already persisted object. Here, Factories is not something which refers to only Factory pattern. We are free to choose from Factory, Builder or any other that we are aware of based on our judgement and something which conforms to UL.
Q: How will I model behavior in domain model?
A: In domain modelling, majorly, we have following kinds of behavior
- One which validates the domain model against certain rules: Specification Pattern. Specification pattern is employed to validate domain model against certain rule. For example, The logic to check whether the project is overdue can be put in the Project object, as in the following listing
class Project { public boolean isOverdue() { … } }
or, it can be abstracted as a Specification, as shown in the following code
public interface ProjectSpecification { public boolean isSatisfiedBy(Project p); } public class ProjectIsOverdueSpecification implements ProjectSpecification { public boolean isSatisfiedBy(Project p) { … } } If (projectIsOverdueSpecification.isSatisfiedBy(theCurrentProject) { … }
public int makeBooking(Cargo cargo, Voyage voyage) { double maxBooking = voyage.capacity() * 1.1; if ((voyage.bookedCargoSize() + cargo.size()) > maxBooking) return –1; int confirmation = orderConfirmationSequence.next(); voyage.addCargo(cargo, confirmation); return confirmation; }
After applying Strategy pattern, the code might look like
public int makeBooking(Cargo cargo, Voyage voyage) { if (!overbookingPolicy.isAllowed(cargo, voyage)) return –1; int confirmation = orderConfirmationSequence.next(); voyage.addCargo(cargo, confirmation); return confirmation; } public OverBookingPolicy { public boolean isAllowed(Cargo cargo, Voyage voyage) { return (cargo.size() + voyage.bookedCargoSize()) <= (voyage.capacity() * 1.1); } }
This helps in making code/model more expressive and flexible.
Q: How will I maintain the integrity of the model in a large team with complex domain?
A: While working on large projects and large teams, it is difficult to express the intent of the domain with a single model. DDD advocates the use separate models to model the entire system. The patterns to handle the complexity of working with separate models and communicating between them are grouped as Strategic Design Patterns in DDD. Various strategic design patterns are their relationships are shown in the following diagram.
- Bounded Context: DDD suggests to separate multiple domain models based on contexts. For example, in above figure domain model expressing project model is bound by project context, where as, billing model is bound by billing context. Contexts are generally created based on team structure and domain concepts.
- Context Maps: Different models in an application cannot work in isolation. There will be some data sharing among them. DDD provides some patterns based on experience. Theses pattens have specific applicability which are explained below.
- Shared Kernel: In this pattern, another domain model is created which models the shared data. For example, in the above example, shared data can be Customer and that would be part of Shared Kernel.
- Customer/Supplier: This pattern is applied when one context has dependency on another pattern. In this scenario, customers models can discuss their concerns with suppliers and raise their concerns and get the supplier model modified.
- Conformist: This pattern is similar to above pattern but customer model has no control over supplier model and customers are forced to deal with whatever suppliers dish out.
- Anti Corruption(AC) Layer: When the supplier model is third party and legacy code, there is high probability that the legacy code is developed not using domain modelling techniques. There might be chance of theses bad practices to creep into your own domain model. To insulate your domain model, DDD advocates the use of an AC layer, which is essentially a collection of services and adapters which translate the communication between the two models.
- Separate Ways: When the cost of integration between various model becomes overwhelming, we can decide not to integrate them at all. Instead, we can decide to break the application into smaller application which have little or nothing in common from modeling perspective.
Q: How do I learn more about DDD?
A: To get started with DDD, I recommend following approach
- Download Domain Driven Design Quickly, a brief and concise guide about DDD from InfoQ to get started.
- Go through, Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans.
- You can also join Domain driven design group on Yahoo to get connected with the latest in DDD.
Conclusion
In this blog, we discussed about what is DDD and looked at the various pattens suggested by DDD. DDD is not only object orientation done right but also understanding the domain of the application. DDD does not lay down any rules and only suggests to do certain things, which have worked on various projects. Any developer can benefit from it because it is merely a thought process which has evolved based on experience and not is not a figment of anyone’s imagination. DDD, along with Agile practices like TDD, Continuous Integration and Refactoring, is a potent weapon in any designer’s armor.
As promising it may be, DDD’s applicability has major challenges. Based on my experience in IT industry, I have summarized majority of them below:
- Poor quality of requirements: As already discussed in the blog, most projects have a translation layer which translates the requirements between business and technical people. Some may call them Business Analysts, whereas some call them Product Owner. So, quality of communication, and hence the requirements, depend upon this translation layer. On top of that, if this translation layer is bureaucratic, they would not like developers to work directly with the business as it would dilute their role in the project. So, apart from skills, DDD requires people with right mindset at the top and the team.
- Simple Domain: The application/domain may be simple enough to yield any significant ROI of using DDD. The effect of DDD might be visible once the project becomes complex.
- Motivation: DDD is all about making pragmatic decisions and it requires a lot of skill, but more importantly, a lot of motivation to make those decisions.
In summary, DDD is a promising concept, which is gaining momentum in recent years. Although, it may not be applicable to every project directly, but learning these principles would certainly enhance design skills of a developer.
Hey Vikas, good to see you penning down your knowledge. Interesting post.
good illustration…
Nice post Vikas, keep it up.