天天看点

Rich Domain Model

The discussion started with Martin's post:

http://www.martinfowler.com/bliki/AnemicDomainModel.html.

The common reasons I've seen why we have anemic model are:

  1. Most cases are simple db-to-web, with little domain logic.
  2. Books are misleading, people are ignorant. It's hard to find a proper example for rich domain models. The majority cases are either too trivial or too complex to present.
  3. In almost all cases, we need to work with a collection of domain objects, e.g., a search result. Since we need to build a separate class to handle collections most of the time anyway(this class is one level above the domain objects), it's natural to combine this class with DAO classes.
  4. In some cases, we need batch loading for performance reasons, and the general purpose ORM tools can't meet the requirements. So we separate out the loading from the domain objects.
  5. It was not trivial to wire DAO implementations to the domain objects, without side effects.

The first problem with RDM is with DAO implementations. The reason we have to isolate DAOs is because they could be the bottleneck for the entire system if we don't pay attention to them, e.g., load records from db one by one. We could inject DAO classes into the domain objects, the problem is that it would have dependencies on the underlying DAO implementations. Furthermore, the operations with collections normally involve other domain objects and it requires more energy to figure out where these operations should be.

The second problem is almost the same as the first one, but in the distributed environment - we need to retrieve data from other services. If we inject the DAO classes to the domain objects, which could be Serializable, it would require the DAO classes to be Serializable too, unless we make them transient and regenerate them once we cross the wires.

To avoid these problems, the current solution is from Spring 2 and AspectJ. The problem with Spring 1 is that it can't inject DAO classes into the domain objects because domain objects are most likely not generated from Spring containers. With Spring 2, we can inject the DAO classes into domain objects even if they are not generated from Spring containers. If the domain objects need to cross wires in a distributed environment, we need to make sure the transient DAO classes get regenerated as well. This is the entanglement I don't like because being transient is more of a system concern, not an application concern, and thus it shouldn't be a concern in the domain objects at all.

One concern with RDM is that it doesn't scale well because of dependencies on implementations that are potentially slow, such as database or network bottlenecks. It's almost certain that in complex cases we need to go with batch mode. In my current project, the performance benchmark is to load a portfolio with a quarter of a million financial transactions(such as buy/sell) under 4 seconds. Each transaction has a financial instrument, e.g., bonds/stocks, that is also from databases. One way to improve the performance is through caching with prefetched data. However, if the data size is huge, it's just getting worse, not as clean as the anemic way. This is because, when the data size is huge and the data structure is complex, the data loading is getting really twisted for performance reasons. However, we really don't want this twisted implementation penetrates too much into upper levels. The DAO interfaces can stop this well in the old way, while in the new way it gets very ugly right in the domain objects. While we could argue this is a design/implementation problem, and I don't totally disagree, I still think there is more leeway in the old way in this case.

继续阅读