Recently I had posted some reasons about why I use Repository as opposed to Active Record. This post was originally spawned by some comments by Sam Gentile in regard to peole refactorring from repository to active record. In my previous post I listed a few reasons but one of those reasons requires much closer analysis …
ActiveRecord seems to defeat the entire concept of DDD, ActiveRecord promotes a database centric model
Every methodology has its foundation, for Domain Driven Design it is the Repository Pattern.
People often see the repository as nothing more than a glorified factory; a simple delegation of responsibility away from the domain object. Studied in isolation on a whiteboard or in a fancy Visio diagram this is often the case. The comments are often that it is done to ease unit testing, to allow a plugin point, or to support multiple disparate data sources. While all of these items are true; they are but side effects of a greater benefit which often goes by un-noticed as the real power of the repository pattern can only be seen in it’s native environment, a well designed domain.
The repository pattern with it’s “objects in memory“ facade allows Domain Driven Design to become truly “Domain Driven“. Domain Driven means that we have a domain centric design methodology. This at first sounds like semantic differences but in practice the difference is night and day, and it is this difference that separates Domain Driven Design from the countless generic “business layer development strategies”. We by choice model our domain to our perceived reality and then conform the dysfunctional worlds surrounding it to meet our model.
The repository serves as our point of articulation and polarity translator between our wonderfully perfect domain and the data it needs to access which is often times on a completely different frequency than our model. By following a domain first methodology we know that we can in fact work with any exterior sources, providing we can create repositories that translate the exterior world into our model
*note* it may sound as if I am suggesting to create all repositories up front, this is not the case, normal iterations still exist.
The starting point to using repositories effectively in a domain is the creation of abstract contracts for the repositories. These abstract contracts should be the only publicly visible forms of our repositories. Internally we only use the abstract contracts to refer to our repositories and in many cases we also allow such things as dependency injection of repositories into our domain, we will generally use either a service locator or a static accessor to an instance. We also at this point create our first unit tests to test the abstract contract of a repository; we can at a later point use these unit tests as integration tests with a repository that is hooked to a real database.
When developing in a domain first process we will generally create our initial concrete repositories not only as “objects in memory“ facades but actually implement them as storing all objects in memory. I personally use a generic base class to implement these items; although it saves a huge amount of code, it is not necessary in order to produce a functional set of repositories.
As we move forward with our domain, we write our unit tests to use the in memory repositories; as the repositories actually store data in memory they are ideal for unit testing purposes. We do not at this point think again about our repositories until we are ready for integration with an actual data source.
When we have nearly completed our domain and are ready for integration, we come back and implement our repositories. We can implement them either within our domain or within the host application (that then registers them with our domain as dependencies). We have already created unit tests for the abstract contracts representing our repositories and as such should have a very strong contract for their implementation; we simply reuse the original unit tests as our base integration tests and move happily along.
When we come to our next disparate data source we simply follow the same step that we used for the first data source. As we have strong contracts defined and base integration tests written, implementing our repositories should again be a very straight forward ordeal.
There are some issues that can come up with the use of in memory repositories during the development process. Most can be seen in the creation of non-performant production code which works well during the initial development process. Care should be taken to avoid common pitfalls (such as looping through every object summing up a column). Although there is no solution to this problem outside of experience, a common pattern I have used to help alleviate this is to optionally associate a cost with my “in memory” repositories (i.e. a sleep during an object fetch). These costs are used with some very loose performance tests (run nightly) to help bring such performance issues to light.
Some others have gone this route before .. you can read about a experience here http://domaindrivendesign.org/articles/archive/rainsberger_jb_2003_10.html