Layers in DDD Projects
Yazının Türkçe versiyonuna bu link ile ulaşabilirsiniz.
In projects developed with the Domain Driven Design approach, we see the layers depicted with the names of Presentation, Application, Domain and Infrastructure. I will elaborate on the responsibilities of these layers and try to explain with examples.
Through the user creation scenario, all layers will be examined and the layers will be explained through this example. You can access sample codes via this link.
This layer is the part where interaction with external systems happens. This layer is the gateway to the effects that a human, an application or a message will have on the domain. Requests will be accepted from this layer and the response will be shaped in this layer and displayed to the user.
As you can see in the sample project, the system can perceive the outside world through the Controllers classes via HTTP and the Consumer classes via AMQP protocols.
Below is a sample code piece of this layer that converts the request object received via HTTP to the request format that the Application Layer will accept and transmits the response of the application layer to the client.
It is the layer where business process flows are handled. The capabilities of the application can be observed in this layer. Domain entities are created and subject to update here. Depending on the usage scenarios, topics such as transaction management are also resolved here. In this layer, execution of work commands and reactions to domain events are coded. The code snippet for handling the CreateUser work command is given below as an example. In this example, by creating an object of User that comes from the Domain Layer and storing this object in the data storage, request for user creation is resolved.
Sometimes there are processes in which more than one domain object is affected. Let’s imagine a process where users verify their accounts using the verification code sent to their email addresses. Let’s assume that a work command named VerifyEmailCommand is included in the system. Resolution process of this request will be described as “While User’s email status is being marked as approved, Verification Code is marked as used.”. Based on this description, we can predict that in a single transaction block more than one object will be modified while the work command is being executed.
The processes defined as “While… happens,… happens” should be handled in transactional integrity. Above, we have seen an example of the scenario for this situation. Another case scenario is in the form of “… happens after … happened.”. We can talk about domain events in processes defined in this form. The integration message publishing part of “The integration message is published after the user is created.” business process is triggered by the User Created domain event and handled within the same transaction block as the Create User work command.
This will be the core of the application. It is the layer where all business rules related to the problem to be solved are included. In this layer; entities, value objects, aggregates, factories and interfaces will take place. This layer should be kept away from dependencies as much as possible. Third party libraries should not be added as much as possible, as it should not take other layers as a reference.
Below we can see some code snippets belonging to the User domain object. Create method that is in this code snippet performs important processes for DDD concept. With this Create method, business rules belonging to the domain are run. As a result, creating an inconsistent user object with invalid information is prevented. With the Create method, domain event message — User Created Event — is also generated.
In the domain layer, the focus is on simulating business processes. This layer is not concerned with data storage (Persistance Ignorance). On the other hand, since this layer is the layer where abstractions are made, the design of interfaces such as IUserRepository that will perform registration operations is included in the domain layer.
This layer will be the layer that accesses external services such as database, messaging systems and email services. The IUserRepository interface designed in the domain layer and used in the application layer will be implemented in this layer and gain an identity. Similarly, the object that is used through the IIntegrationMessageBroker interface will have an implementation on this layer. Access to RabbitMq platform using AMQP protocol can be considered as an option.
Pieces of code that will be executed to communicate with the outside world such as network and file system are located in this layer.
The reference relationship between projects in our sample application can be seen above.
I have mentioned the 4 layers that are frequently talked about in the Domain Driven Design concept and the responsibilities of these layers. I hope it has been a useful post. You can click on this link to browse my other articles.