DDD – the rule that Entities can’t access Repositories directly

domain-driven-designooprepository-patterns#arp-architecture

In Domain Driven Design, there seems to be lots of agreement that Entities should not access Repositories directly.

Did this come from Eric Evans Domain Driven Design book, or did it come from elsewhere?

Where are there some good explanations for the reasoning behind it?

edit: To clarify: I'm not talking about the classic OO practice of separating data access off into a separate layer from the business logic – I'm talking about the specific arrangement whereby in DDD, Entities are not supposed to talk to the data access layer at all (i.e. they are not supposed to hold references to Repository objects)

update: I gave the bounty to BacceSR because his answer seemed closest, but I'm still pretty in the dark about this. If its such an important principle, there should be some good articles about it online somewhere, surely?

update: March 2013, the upvotes on the question imply there's a lot of interest in this, and even though there's been lots of answers, I still think there's room for more if people have ideas about this.

Best Answer

There's a bit of a confusion here. Repositories access aggregate roots. Aggregate roots are entities. The reason for this is separation of concerns and good layering. This doesn't make sense on small projects, but if you're on a large team you want to say, "You access a product through the Product Repository. Product is an aggregate root for a collection of entities, including the ProductCatalog object. If you want to update the ProductCatalog you must go through the ProductRepository."

In this way you have very, very clear separation on the business logic and where things get updated. You don't have some kid who is off by himself and writes this entire program that does all these complicated things to the product catalog and when it comes to integrate it to the upstream project, you're sitting there looking at it and realize it all has to be ditched. It also means when people join the team, add new features, they know where to go and how to structure the program.

But wait! Repository also refers to the persistence layer, as in the Repository Pattern. In a better world an Eric Evans' Repository and the Repository Pattern would have separate names, because they tend to overlap quite a bit. To get the repository pattern you have contrast with other ways in which data is accessed, with a service bus or an event model system. Usually when you get to this level, the Eric Evans' Repository definition goes by the way side and you start talking about a bounded context. Each bounded context is essentially its own application. You might have a sophisticated approval system for getting things into the product catalog. In your original design the product was the center piece but in this bounded context the product catalog is. You still might access product information and update product via a service bus, but you must realize that a product catalog outside the bounded context might mean something completely different.

Back to your original question. If you're accessing a repository from within an entity it means the entity is really not a business entity but probably something that should exist in a service layer. This is because entities are business object and should concern themselves with being as much like a DSL (domain specific language) as possible. Only have business information in this layer. If you're troubleshooting a performance issue, you'll know to look elsewhere since only business information should be here. If suddenly, you have application issues here, you're making it very hard to extend and maintain an application, which is really the heart of DDD: making maintainable software.

Response to Comment 1: Right, good question. So not all validation occurs in the domain layer. Sharp has an attribute "DomainSignature" that does what you want. It is persistence aware, but being an attribute keeps the domain layer clean. It ensures that you don't have a duplicate entity with, in your example the same name.

But let's talk about more complicated validation rules. Let's say you're Amazon.com. Have you ever ordered something with an expired credit card? I have, where I haven't updated the card and bought something. It accepts the order and the UI informs me that everything is peachy. About 15 minutes later, I'll get an e-mail saying there's a problem with my order, my credit card is invalid. What's happening here is that, ideally, there's some regex validation in the domain layer. Is this a correct credit card number? If yes, persist the order. However, there's additional validation at the application tasks layer, where an external service is queried to see if payment can be made on the credit card. If not, don't actually ship anything, suspend the order and wait for the customer. This should all take place in a service layer.

Don't be afraid to create validation objects at the service layer that can access repositories. Just keep it out of the domain layer.

Related Topic