Domain entities shouldn’t contain code related to persistence, thus they should be Persistence Ignorant PI
Data that the domain model DM is interested in can be delivered to DM either through domain entities‘s navigation properties or by upper layers ( ie UI layer or service layer).
But I also assumed that in scenarios where particular domain entity must dynamically decide what data it requires, it is perfectly acceptable for that entity to request that data via component such as Repository.
If this Repository is completely decoupled from the persistence layer, then our entity is not violating PI, since it still doesn’t know how it gets that data, it only knows it gets the data by requesting it from the Repository:
class Customer
{
public string InterestedWhatOtherCustomerOrdered( ... )
{
...
var orders = repository.Find...;
...
}
...
}
As such, why is it considered a bad practice for domain code to also be able to request the data it needs from Repository instead of just receiving it from either upper layers or from navigation properties?
Namely, even according to Fowler ( PEAA chapter on Data Mapper), it is ok to extract from Data Mapper any methods needed by the domain code into an interface class, which domain code can then use.
REPLYING TO Sebastian Good:
1)
The idea is that your domain model shouldn’t be concerned with details
about where that data came from.
But if domain entities adhere to PI rule, then we could argue they don’t know the details about where the data actually came from.
2) You do still have to decide how to load that data, but you make
your “application services” (typically) worry about it.
a) assuming the real world entity does have the functionality of searching for particular data, would you still consider the domain entity requesting data as being problematic ( I apologize, I’m aware that it’s hard to answer such general questions )?
b) Most importantly, I’m having hard time understanding how application service layer could possibly foresee all the different kinds of data that domain entities could require for processing.
Namely, wouldn’t having application layer services be solely responsible for loading the data mean that anytime we change the internal logic of domain entity ( such that now this entity requires different type of data ) also mean we’d have to change the application services accordingly, so that they would now supply to entity the new type of data instead of the old one?!
REPLYING TO Eulerfx:
1)
a) The application service can provide not only data, but a mechanism for retrieving data as well, in cases where it is better to place logic for determining the exact instance of data needed in the domain
So in cases where it is better to place logic for determining the exact instance of data needed in the domain, I should encapsulate an access to a repository inside service S and then pass S as an argument to a method of a domain entity? Thus, in our example I should encapsulate an access to OrderRepository inside ordersSelectorService service and then pass ordersSelectorService as an argument to Customer.InterestedWhatOtherCustomerOrdered:
class Customer
{
public string InterestedWhatOtherCustomerOrdered(OrdersSelectorService ordersSelectorService)
{
...
var orders = ordersSelectorService.Select...;
...
}
...
}
class CustomerService
{
OrdersSelectorService ordersSelectorService;
CustomerRepository customerRepository;
public void ()
{
var customer = this.customerRepository.Get...;
...
customer.InterestedWhatOtherCustomerOrdered(ordersSelectorService);
...
}
}
b) If that is indeed what you are suggesting, are there any other benefits ( besides those you’ve already mentioned ) over simply passing OrderRepository as an argument to Customer.InterestedWhatOtherCustomerOrdered:
class Customer
{
public string InterestedWhatOtherCustomerOrdered(CustomerRepository orderRepository)
{
...
var orders = orderRepository.Select...;
...
}
...
}
2) Following question are just so I can be sure I’ve correctly understood your post in its entirecy correctly:
So if a specific behavior requires access to some service, have the application service provide an abstraction of that service as an argument to the corresponding behavior method. This way, the dependency upon the service is explicitly stated in the method signature.
a) By “specific behavior” you are referring to domain entity ( ie Customer )?!
b) I’m not exactly sure what you mean by “app service providing abstraction of that service as an argument“. Perhaps that instead of providing the service S itself ( ie OrderRepository ) as an argument to a method ( ie Customer.InterestedWhatOtherCustomerOrdered ), we should have some class C ( ie OrdersSelectorService ) encapsulate S and then pass C as an argument to a method?
c) I assume C ( class which encapsulates S <– see b) question) ) should always be an application service and S should always be encapsulated by C ( unless S is already an application service )? If yes, why?
d)
This way, the dependency upon the service is explicitly stated in the
method signature.
What benefits do we get by having dependency upon the service being explicitly stated in the method signature? Only that we immediately can tell what the method is doing without the need to inspect code of the method?
3) A bit off topic, but it appears when we inject behavior B into class C as an argument to a method M ( C.M(B b); ), then we don’t call it dependency injection, but if instead B was injected into C via constructor or setter ( B b=new B();C c=new C(b); ), then we call it a dependency injection. Why is that?
SECOND REPLY TO Eulerfx:
1)
1ab) … Another option is to use a lambda instead of
OrdersSelectorService.
I assume you mean that instead of passing to OrdersSelectorService to Customer.InterestedWhatOtherCustomerOrdered we should instead use Linq-to-Entities ( which relies heavily on lambda ) within Customer.InterestedWhatOtherCustomerOrdered? But as far as I can tell, this would violate Persistence Ignorance rule ( see my previous thread)
2)
2c) No, C should just be an interface that contains the required
method. The service S could either implement that interface, or an
implementation could be provided on the fly.
Aha, I mistakenly thought that you were suggesting that C should be an Application service. Anyways, where should C live? Should it be packed inside Application Services assembly or within Domain model Assembly?
3)
2d) … A benefit of declaring the dependency in the method signature
as opposed to the constructor of the class itself is … Another
benefit is that your domain class doesn’t need to be part of
dependency graph from IoC container – makes things simpler.
Don’t yet know much about IoC, thus I must ask how exactly does domain class become a part of an IoC’s dependency graph? In other words, must this domain class be specified within IoC’s configuration layer ( I thought this layer is used only to specify the mapping between the interface of a dependency and an actual implementation of a dependency, thus I assumed the dependent class isn’t even mentioned inside this layer ) or…?
4) I don’t mean to cause any troubles or imply one of you guys is wrong ( both of you already reasoned why you prefer your design ), but I’d just like to be sure that I understood your post completely. You are in fact recommending just the opposite of what nwang0 is suggesting ( namely, if both of you guys are recommending the same thing, then my comprehension skills are in need of some repair 😮 )?!
thank you
It isn’t bad practice for domain object to request data they need, however it is usually considered bad practice to inject a repository dependencies directly into entities. One reason for this is that now your domain objects become part of a dependency graph which is a needless complexity. Furthermore, a repository typically carries with it ambient dependencies such as transactions and a unit of work. This adds complexity and makes reasoning about domain logic more difficult.
Instead, as specified by Sebastian Good, it is best to have application services provide the data that an entity needs. An application service is a great place to inject repositories and other gateways. The application service can provide not only data, but a mechanism for retrieving data as well, in cases where it is better to place logic for determining the exact instance of data needed in the domain. For an example, take a look at this question. So if a specific behavior requires access to some service, have the application service provide an abstraction of that service as an argument to the corresponding behavior method. This way, the dependency upon the service is explicitly stated in the method signature.
UPDATE
1ab) Yes that is correct. Another option is to use a lambda instead of
OrdersSelectorService. If lambdas aren’t available in your language then it should be an interface. The benefit over passingOrderRepositoryis based on the interface segregation principle the goal of which is to reduce needless coupling. It is unlikely that a behavior on Customer needs all the methods on OrderRepository, instead it needs a specific function, so make that explicit.2a) Yes, the behavior I’m referring to is a behavior on the
Customerentity, which is just one of the methods on the class.2b) Yes for reasons stated in 1ab.
2c) No, C should just be an interface that contains the required method. The service S could either implement that interface, or an implementation could be provided on the fly.
2d) Yes. This is the part of the argument favoring dependency injection over service location. A benefit of declaring the dependency in the method signature as opposed to the constructor of the class itself is because that service is typically needed for only a single method and it is wasteful to make it an member of the class. Another benefit is that your domain class doesn’t need to be part of dependency graph from IoC container – makes things simpler.
3) I would call both dependency injection (DI). DI is meant to contrast service location wherein the class constructor or method would be responsible for obtaining required services via service locator.
UPDATE 2
1) Here’s a C# code sample:
This does not violate persistence ignorance and is very decoupled. The lambda parameter on the
InterestedWhatOtherCustomerOrderedmethod specifies exactly what the method needs – nothing less nothing more. And it doesn’t care how that functionality is provided, just that it is.2) In the case of a lamda, C doesn’t really exist anywhere because it is specified in its entirety by the lambda. If however you were to use an interface, for example
IOrderSelector, that interface needs to be declared where the Customer aggregate exists. It could be implemented directly by theOrderRepository, or you could have an adapter class.3) The reason I mention IoC is because another approach would be to declare the dependency on an order selector in the constructor of the
Customerclass. Then, whenever a new instance of the class is created, that dependency (the order selector) would need to be injected. One way to do that would be to use an IoC container in places where theCustomerclass is instantiated. The reason this is problematic is because now you have to make sure to have access to the IoC container wherever you instantiate theCustomerclass. It is also a misalignment of responsibility, since creating a customer has nothing to do with an order selector, only one behavior needs it.4) It is a difference of philosophy I suppose. I don’t like to have domain objects reference repositories for reasons stated above and other reasons as well. Overall, it is typically frowned upon if you browser around SO or blogs, etc. It is true that repository interfaces are declared in the domain, but it doesn’t mean that they should be referenced from domain entities directly.