Monday, January 21, 2008

Domain Driven Design in Java: Repositories and DAOs part 3

In the previous posts on the topic (part1 and part2) I've highlighted common characteristics and differences between the DAO and Repository patterns. In situations where the modeled domain is simple, a traditional DAO approach (backed up by frameworks) is probably good enough. If your domain is more complex, or if complexity is growing, differences between DAOs and Repositories become more important.

  • A larger domain calls for a higher level of abstraction: Repositories could help implementing new functionalities because they hide more of the underlying layers.
  • Complex systems cannot always be modeled with a one-database strategy: whether a Model-DAO-DB model makes sense for most of the normal application, this is a "reasonable assumption". There are anyway situation where a Repository should hide more complexity than a simple database call.
  • Simply stating that "access to the database should always happen through Aggregate Roots" could be not enough to preserve your architecture's integrity.

So, given that DAOs come almost for free in a Spring plus Hibernate environment, the question now is understand if we need something more than that. To put in another way, if DAOs drawbacks (tied to the database representation, more data-oriented than model-oriented, not enforcing access only via aggregates but a one-dao-per-entity approach) are something we can live with or a call for a targeted solution. To be honest, there's also one limitation with DAOs, which is related to the layer they belong to (the persistence layer or whatever you want to call it), while it is been said that Repositories belong to the domain layer. This is a controversial issue… I'll leave it for later.

Ok, the proposed approach with Repositories and DAOs is to have Repositories on top of the persistence layer, and have Repositories call specific DAOs. Something like

Which is quite similar to Debasish's proposal on this post. Repositories expose a more business-oriented interface, compared to DAOs and could enforce access only via Aggregate Roots. Repositories should belong to the domain layer, for a couple of reasons:

  • Data access isn't conceptually a dirty thing. A pure OOP approach made up by only traversing associations (and have am ORM framework doing the dirty job behind the scenes) could impact performance.
  • They should not be tied to any implementation issue. Repositories expose abstract store and retrieval operations but no implementation details.
  • They could contain business-oriented logic related to searches: getUnreconciledOperations(BankAccount ba) could be used instead of getOperationByAccountAndDateRange(BankAccount ba, Date from, Date to).

Personally, I like the proposed solution, which is also implemented via Spring dependency Injection. But I can't help feeling somewhat weak when it comes to explain the advantages. I mean "speaking the language of the domain" is a good thing to me. But is quite far to be a compelling principle when it comes to "sell" an architecture proposal to a team. They have established practices with DAOs, and we're suggesting to add another layer on top of it. If you are lucky enough to have a common understanding of DDD principles and values in your team, then you're probably in a sort of positive loop, and one DDD practice enforces another one and the whole result is a good thing. If this is not the case, this approach might look like it provides marginal value at the price of an increased complexity.

One more thing that could get in the way is code-generation. It is often possible to have some sort of code generation applied to DAOs. Such DAOs are good but flat, and in many cases they call for a business-oriented refinement, while hand-coded DAOs are generally somewhere in the middle. But if adding a Repository layer breaks the code-generation cycle, it could (one more time) be not worth the effort.



5 comments:

  1. hi Alberto,

    very nice article series about repositories and daos. Last year
    i attended one of Eric Evans's courses on DDD and asked him
    the question:
    What's the difference between a
    repo and a dao? He answered
    (word-by-word quotation):
    "Repos can be implemented in many ways, one way is a DAO"
    :)

    Best Regards
    Phatthana

    ReplyDelete
  2. hi Alberto,

    very nice article series about repositories and daos. Last year
    i attended one of Eric Evans's courses on DDD and asked him
    the question:
    What's the difference between a
    repo and a dao? He answered
    (word-by-word quotation):
    "Repos can be implemented in many ways, one way is a DAO"
    :)

    Best Regards
    Phatthana

    ReplyDelete
  3. Hi Phatthana,

    I've had the luck to follow one of Eric's seminars too. And the feeling I've got is that the principle is more important than the implementation. Put in another way, you must ask yourself if an implementation strategy brings you some real advantage or not.

    From my point of view, what arose as a mainstream model, the Spring + Hibernate couple, makes a little bit of nonsense to put 2 separate layers, for many applications. Just because having only one is SO easy. When DAOs were to be coded by hand that was a different story.

    However, the argument for a 2 layered solution does not come only from DDD zealots. I've been following a seminar from POSA authors Henney and Buschmann, and they were proposing a 2-layered solution for DAOs to decouple logical and phisical representation of data, without involving any DDD concept.

    I think the key argument is the scope your application is supposed to have. Follow your frameworks for simple or short-living apps, go for some more refined solution if your application is going to last or evolve for a longer time.

    Best Regards
    Alberto

    ReplyDelete
  4. Nice article Alberto,

    When I first read the concept of "Repository" in the Eric Evan's book, I told to myself "that is a DAO". But then reading elsewhere, I saw that people still restrict DAOs to the persistence layer and hence, make one DAO per Entity.

    I think that "one-DAO-per-entity" pattern is an anti-pattern. It is true that your persistence layer framework may change, but this does not validate the whole idea of hiding access to persistence layer in a dao. Hibernate allow you to define the way your object should be written and read from a database in a mapping file. So for me, that is how the persistence layer is separated from the domain layer. Modifying a configuration file or a java class to integrate a new persistence layer is the same thing for me -the same effort- at this point.

    DAO or Repository in that sense are the same things, they allow you to manipulate aggregate roots from a domain perspective.

    Here is a comment of Christian from the Hibernate team (and He didn't knew about DDD and Eric Evan's book at that time):
    -----------
    Christian said:The DAO interface for a particular entity, that's ok
    but can sometimes think in term of package.

    Just one word about granularity, for big projects based on more than
    100 persistent classes, if your design is well done, you'll have
    different packages of 10-30 classes for example.

    Use cases should be "driven" by a root entity for each package, so you
    can define one DAO interface per package.

    Example: what if you have Order * -- 1 Client and you need to get the
    orders of a particular client? One use case needs only the orders, one
    other also need the client to be fetched. Do you code this in
    ClientDAO or OrderDAO knowing that client is the best candidate to be
    a root entity...
    This one is very simple but think about complex HQL queries on a 4 or
    6 levels object graph. The code is not so easy to add and if you have
    a big development team, there is risk to duplicate the code.

    But you need to be carefull when designing your packages...
    --------------

    source:http://www.hibernate.org/328.html

    ReplyDelete
  5. Thanks letrait, I pretty much agree:
    "one-DAO-per-entity" is not necessarily an antipattern. Many CRUD applications are designed that way. I don't like them (they're boring) but it's a reasonable way to deal with a small complexity.

    Unfortunately this approach does not scale, so it becomes an antipattern, with increasing domain complexity (and Christian is getting to the same conclusion following another path). to master complex domains you might need Aggregates and this type of repository managed strategy.

    The good surprise was that the aggregate based approach really simplified our model helping us managing intricate situations and also streamlined Hibernate configuration in caching, cascading, lazy loading...

    best regards

    Alberto

    ReplyDelete