I was replying the Gavin King’s question about Repositories and DDD, but the comment started to become really big and I wasn’t sure if the code snippets would be well formatted. So, I decided to reply it here.
I had similar questions about Repositories. I’m from Brazil and we have discussed it many times here (see at GUJ and at my post in the Caelum Blog – unfortunately – in pt-BR; perhaps, translation tools can help). I have a personal and pragmatic conclusion that may help.
I won’t discuss if DDD is good or not, but I will suppose it is. The root problem is the way that DAOs are being used. In the classic Client --@OneToMany--> Order, if it is given a client (id=1) how could we get his orders since 10/10/2006?
Almost everyone would do dao.findOrdersFor(client, since), but that is clearly procedural (actually, not always a bad thing). What I wanted to do is client.getOrdersSince(date).
Now, suppose I love DDD and really want to do client.getOrdersSince(date). The client should be able to give its orders, that’s the “DDD-way”. How could I implement it? Load all orders in memory (maybe a regular @OneToMany mapping) and then filter what I want (bleh!) isn’t an option. One option would be as below:
class Client {
private final ClientDao dao;
Client(ClientDao dao) {// ioc here...}
public List getOrdersSince(Date date) {
return this.dao.findClientOrdersSince(this, date);
}
}
Hmm… what about separation of concerns? DAOs are related to persistence, and persistence is infrastructure, not domain (or business related).
This is what repositories try to solve. They are a domain concept, from where we can get other domain objects. To be “DDD-compliant”, I would do:
class Client {
private final OrderRepository orderRepository;
Client(OrderRepository repository) {// ioc here...}
public List getOrdersSince(Date date) {
return orderRepository.findForClientSince(this, date);
}
}
But err… what’s the difference? Just the name? YES! But the names are important, right? π
Actually, some people would rather Repositories as interfaces, and Daos might be their implementations. What really matters is that domain objects shouldn’t have to deal with infrastructure things like persistence. A Repository has nothing to do with persistence, it’s a domain concept. Lists and Maps (any container) are repositories too.
I also rate the idea to have more layers (completely agreed with you):
Client -> OrderRepository(just an interface) -> OrderDao -> Hibernate -> ...
I would just drop the indirection and make the Repository concrete:
Client -> OrderRepository -> Hibernate -> ...
Duh. You can ask: “have you just renamed the Dao?” I would say: “yes, but aren’t the names important?” π
Remember why I did it. I wanted to do client.getOrdersSince(date) and the client shouldn’t know anything about persistence. He doesn’t care if the repository is just a plain list or use hibernate. Repositories are domain objects, daos aren’t.