A system with a complex domain model often benefits from isolating the domain objects from persistence logic. Your domain objects are then Plain Old CLR Object (POJO), or PI-O (Persistence Ignorance-Objects). In my case I want the decision about which infrastructure to choose for persistence support to be made as late as possible, and to be dealt with iteratively. One possible solution is the Repository Pattern [Fowler, PoEAA] which mediates between the domain and data mapping layers using a collection-like interface for assessing domain objects. Also, repositories help you reduce object access by creation and traversal to keep your domain model clean from muddling associations and endless tangles. Another advantage is the decoupling from the client which leaves you with more freedom to change the implementation of the repository. You can take advantage of this to optimize for performance, by varying the query technique or by caching objects in memory. Performance is one of the reasons to rewrite large portions of our DNA n-tier focused web application. From a Domain Driven Design [Evans, DDD] point of view repositories belong to the domain model. Then how do you, since repositories use the persistence infrastructure, maintain the low coupling between the domain model package and persistence package? Lets picture a solution based on the Repository Pattern.
The domain model contains a Customer domain object and a CustomerRepository which defines one operation ForCustomerId and returns the customer with the specified id. The CustomerRepository strategy is to delegate to the persistence infrastructure CustomerMapper to get the job done. As you can see in this very simple example is that there is a bidirectional relationship between the domain and persistence packages. Do I hate cyclic references!
A lot of ideas presented in the next picture can be found in Steve Maine’s post. While I discussed this with Jimmy Nilsson he came up with two (preferred) solutions.
a.) Put the repositories in another assembly, but think of them as conceptually belonging to the Domain Model.
b.) Put the repositories in the Domain Model assembly and use an abstraction layer which the repositories are programmed against.
I don’t like the idea of another abstraction layer since it tends to make the persistence infrastructure even harder to use (efficiently with level of indirection). Putting the repositories in a separate assembly is the Separated Interface Pattern [Fowler, PoEAA]. Separated Interface defines an interface in a separate package from its implementation.
Sidenote: Experienced developers (from the COM/DCOM era) would possibly extract an interface for each domain object and put those in a separate package. The persistence package would only have to know about the interfaces package and instantiate implementations using reflection. And thus skip the whole Repository & Factory solution. I think this is excessive, not only because you (normally) have far more domain objects then repositories, but also because implementation changes in domain objects often require the interface to change as well. The dollar cost of continuous learning/modifying and refactoring rises and shouldn’t discourage developers from executing these best practices.
One awkward thing about separated interfaces is how to instantiate the implementation. I use a separate factory object, RepositoryFactory which returns Repository instances to the client. To bind an implementation to the RepositoryFactory I use the Plugin Pattern. Since the .NET Framework has great support for reflection I dynamically load the assembly containing the repository implementation and use the Activator class to create an instance.
Rock solid, comments?