Jerusalem is the first qibla of Muslims and the capital of Palestine.

Domain Driven Design - Tactical Patterns

27.10.2022 | min read

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.

Value Objects

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.

Primitive Obsession
Value Objects

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.

Helper Classes
Value Objects - Their own business

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 - Validity

Value objects have no identity. If the properties of two value objects are the same, it means that they are equal.

Value Objects - Equality

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 - Immutability

Value objects can't exist on their own, so they have to be present in entities or aggregates.

Value Objects - Belonging to an entity

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.

Value Objects - Grouper
Money has a serial number. This number is its identity. However, while this identity doesn't mean anything in an e-commerce domain, it may be very important in a central bank domain. For this reason, money may not be a value object in a central bank domain.

Entities

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.

Entities - Equality

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.

Entities - Mutability

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.

Aggregates

Domain Services

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.

Domain Services - Impure

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.

Domain Services - Pure

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.

Domain Services

You can see the detailed examples of this outlined post in the video, and access to the sample project from my Github address.

ahmetkucukoglu/ddd-bank-app

Bank App with DDD

C#
4
0

See you later.

Share This Post

Leave a comment

Reply to

Cancel reply
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply. Your comment has been sent successfully reCaptcha couldn't be verified
Made with ASP.NET Core