DDD is an approach for software that have high complexity. This approach eliminates the complexities within the process of developing software. DDD is broken down into two categories, strategical and tactical. Strategic pattern is the main component of DDD. But we will not be talking about strategic pattern in this post. Tactical Pattern deals with architecture. It is about how classes, methods and dependencies should be. So we can call it clean architecture. Lets start then.
For all properties, we prefer the primitive types in Framework. This is called Primitive Obsession. For example; We can choose String for the phone number. There are more than 10 methods for string in .NET. Tolower, Padleft etc. But which of these methods has a meaning for a phone number? We can create a class "PhoneNumber" instead of using string data type.
A Value Object may also have its own business logics. For example; We use the last four digits of the phone number for 2FA. We can write another class and method to get these four digits from a string. But if we do so, some helper classes which are not related to each other will start to accumulate under a same folder. It is not right to do that. We can add a method to the class "PhoneNumber", instead of writing a helper class.
A Value Object may include its own rules and validations. For example, we can check on constructor whether a phone number is valid.
Value objects have no identity. If the properties of two value objects are the same, it means that they are equal.
After a value object is created, it is not possible to change its state. It means value objects are immutable. So, we need to create a new object. For example, a phone number is meaningless on its own because it has a relationship with a customer.
Value objects can't exist on their own, so they have to be present in entities or aggregates.
Value objects can be used to group multiple interrelated properties. We can take money as an example. Money has two properties, amount (ex. 100) and currency (ex. ₺). If we don't design it as a value object, then we need to add two different properties for Amount and Currency. In this case, Primitive Obsession occurs. Also, there may be a need for creating a helper class to be able to format money. I have mentioned earlier that it is not the correct way to do that.
Entities have their identity. Two entities are equal when they have the same identity. But two value objects are equal when they have the same properties.
We use constructor to get the required information for creating entities. But for the detailed information, different methods are used. Entities are mutable in general. Unlike ValueObjects, it is possible to change the properties of entities later on.
Aggregates & Aggregate Roots
Aggreates are also the objects with their identity. For that reason, they are also entities. Aggregates are clusters of entities and value objects. Therefore, they are responsible for the consistency of entities and value objects. Aggreagates do not contain entities as navigation property if those entities belong to another aggregates. Instead of this, they contain their identities.
Domain services implement domain rules. If a bank customer has been blocked, they can't draw their money from their account. This is an example of a domain rule. This rule must be managed in domain layer. So, when the Withdrawal method is called, this rule must be run. However, Customer and Account are different aggregates. Account contain Customer not as a navigation property. Then, how is it possible to run this rule? We can pass CustomerRepository to the Withdrawal method.
It is called the Impure Domain Model. Because a domain model cannot query the database. The only thing it can do is to interact with other domain models. After that, we can pass the Customer to the Withdrawal method.
Now, it has become Pure Domain Model. However, domain rules are not always as simple as it is here. They can be much more complex, and they can interact with much more domain models. So, what will be our action? In such cases, we can run these rules on a different class.
You can see the detailed examples of this outlined post in the video, and access to the sample project from my Github address.
See you later.