Search code examples
domain-driven-designddd-repositoriesclean-architecture

Should a Domain Entity call a repository?


I’m designing a shipping application and trying to use Clean Architecture and DDD. Deep in the core of the domain layer we have many configurable business rules. For example, there are business rules for determining the optimal carrier of a shipment, determining shipping mode, determining the payment type, etc. Each business rule selects data from the database so I plan on using a BizRule Repository. The problem is that according to my understanding of DDD principles, Domain Entities (e.g. Shipment) should not call repositories(e.g. BizRuleRepository). The Use Case layer should be the one that calls repositories. If I take this approach then I will have to move many complex business rules to the Use Case layer and I'm not sure if that is the best approach. In this case, does it make sense to make an exception and have the domain entity call a repository? Thank you in advance.


Solution

  • Should a Domain Entity call a repository?

    Generally speaking, no; it doesn't make sense for an entity (which is a domain concern) to be communicating directly with a repository (which is plumbing).

    Evans, when organizing his book, assigned these ideas to different chapters

    • A Model Expressed in Software -- describes Entities
    • The Life Cycle of a Domain Object -- describes Repositories

    It's a problem of language; Repositories normally have collection or persistence semantics, which are not (typically) part of the ubiquitous language of the domain.

    That said, there is a loop hole; domain services can describe data retrieval using the ubiquitous language, and delegate that work to application or infrastructure services.

    So (assuming for the moment that the business rules are a domain concept), you would have a domain entity that knows which business rule it needs, and a domain service that knows how to retrieve a business rule, and then the entity that knows how to use it.

    If business rules are not a domain concept, then some of the work shifts from the entity into the domain service, but the core of the pattern remains the same -- the entity passes arguments to the service, the service returns a domain value the entity understands, the entity decides how to apply that value in its current processing.

    We can solve any problem by introducing an extra level of indirection

    It's a bit of a shell game; under the covers, we're still using the plumbing; but the domain model only sees the porcelain.

    That extra layer of indirection can be really handy when you want to unit test the domain logic without dragging in the entire world of plumbing dependencies: you replace the domain service with a test double.