Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement DDD using Spring Crud/Jpa Repository

I want to create an app by implementing DDD using Spring. Let's say I have a business entity Customer and an interface CustomerRepository.

Since spring provides CrudRepository and JpaRepository to perform basic CRUD operations and other operations like finder methods by default I want to use them. So my interface becomes

 @Repository
public interface CustomerRepository extends JpaRepository<Customer, Long>{

}

But according to DDD, interfaces should be in domain layer and the implementation should be in Infrastructure layer.

Now my question is, which layer the CustomerRepository belongs to?

like image 745
user1188867 Avatar asked Jan 29 '23 06:01

user1188867


1 Answers

Short answer: although it should be any dependencies to Infrastructure in the Domain layer, for the sake of KISS, you may to do so. If you want to be a DDD purist, you define a CustomerRepository interface AND an implementation in the Infrastructure that implements both the interfaces.

Long and boring answer: In general, the Domain should not care or know about infrastructure, as in, it should not have dependencies to other layers (Infrastructure, Application, Presentation or whatever architecture you are using). Following this rule leads to a cleaner architecture.

In particular, the domain should not care about the persistence, it should behave as it runs in memory. From the Domain point's of view, the Entities mutate and that's all, no persistence is needed.

The Write side of the Domain code doesn't in fact need persistence. When the Aggregates execute commands, they are already fully loaded. And after the command is executed, the Aggregates just return the changes or the new state. The Aggregates don't persist the changes themselves. They are pure, with no observable side effects.

We, the architects, need persistence because we need to ensure that the data persist between restarts and that we can run the same code on multiple machines on the same time.

There is however, another need that the Domain code, in particular the Read and the Reactive side of the Domain (Sagas/Process managers). These components of the Domain need to query and filter the Domain Entities. The Readmodels need to return the Entities to the caller and the Sagas/Process managers need to correctly identify the right Aggregates to whom to send the Commands.

The solution is to define only the Interfaces in the Domain layer and to have implementations in the Infrastructure. In this way the Domain owns the Interface so, according to the Dependency Inversion Principle, it does not depend on the Infrastructure.

In your case, although the Domain layer depends on something from the Infrastructure part of the Spring Framework, that something is only an Interface. It is still a depency to JPA because your domain will use methods that it doesn't own but KISS could more important in this case.

The alternative would be do define an Interface that does not extend the JpaRepository with an implementation in the Infrastructure that implements this Interface and the JpaRepository Interface.

Which solution depends on you: more code duplication but less dependency or less code duplication and more dependency to JPA.

like image 189
Constantin Galbenu Avatar answered Jan 31 '23 08:01

Constantin Galbenu