Pros and cons of DDD Repositories

2019-03-25 03:05发布

问题:

Pros:

  • Repositories hide complex queries.
  • Repository methods can be used as transaction boundaries.
  • ORM can easily be mocked

Cons:

  • ORM frameworks offer already a collection like interface to persistent objects, what is the intention of repositories. So repositories add extra complexity to the system.
  • combinatorial explosion when using findBy methods. These methods can be avoided with Criteria objects, queries or example objects. But to do that no repository is needed because a ORM already supports these ways to find objects.
  • Since repositories are a collection of aggregate roots (in the sense of DDD), one have to create and pass around aggregate roots even if only a child object is modified.

Questions:

  • What pros and cons do you know?
  • Would you recommend to use repositories? (Why or why not?)

回答1:

The main point of a repository (as in Single Responsibility Principle) is to abstract the concept of getting objects that have identity. As I've become more comfortable with DDD, I haven't found it useful to think about repositories as being mainly focused on data persistence but instead as factories that instantiate objects and persist their identity.

When you're using an ORM you should be using their API in as limited a way as possible, giving yourself a facade perhaps that is domain specific. So regardless your domain would still just see a repository. The fact that it has an ORM on the other side is an "implementation detail".



回答2:

Repository brings domain model into focus by hiding data access details behind an interface that is based on ubiquitous language. When designing repository you concentrate on domain concepts, not on data access. From the DDD perspective, using ORM API directly is equivalent to using SQL directly.

This is how repository may look like in the order processing application:

List<Order> myOrders = Orders.FindPending()

Note that there are no data access terms like 'Criteria' or 'Query'. Internally 'FindPending' method may be implemented using Hibernate Criteria or HQL but this has nothing to do with DDD.

Method explosion is a valid concern. For example you may end up with multiple methods like:

    Orders.FindPending()
    Orders.FindPendingByDate(DateTime from, DateTime to)
    Orders.FindPendingByAmount(Money amount)
    Orders.FindShipped()
    Orders.FindShippedOn(DateTime shippedDate)
    etc

This can improved by using Specification pattern. For example you can have a class

class PendingOrderSpecification{
    PendingOrderSpecification WithAmount(Money amount);
    PendingOrderSpecification WithDate(DateTime from, DateTime to)
    ...
}

So that repository will look like this:

Orders.FindSatisfying(PendingOrderSpecification pendingSpec)
Orders.FindSatisfying(ShippedOrderSpecification shippedSpec)

Another option is to have separate repository for Pending and Shipped orders.



回答3:

A repository is really just a layer of abstraction, like an interface. You use it when you want to decouple your data persistence implementation (i.e. your database).

I suppose if you don't want to decouple your DAL, then you don't need a repository. But there are many benefits to doing so, such as testability.

Regarding the combinatorial explosion of "Find" methods: in .NET you can return an IQueryable instead of an IEnumerable, and allow the calling client to run a Linq query on it, instead of using a Find method. This provides flexibility for the client, but sacrifices the ability to provide a well-defined, testable interface. Essentially, you trade off one set of benefits for another.