In one of my most recent projects, I decided to design and build the application according to the principles of Domain Driven Design. One of the guidelines promoted by Domain Driven Design is the way the interface of the Repository is designed. This changed the way I look at both the design and the location of the Repository interface. It’s all gain, no pain.
Most of the applications I encounter in my work as Software Architect apply more or less the same layering. The well-known layers in an application are the web layer, application layer, persistence layer and domain layer. This layering provides some boundaries for different types of logic to keep an application maintainable in the long term. Typically, layers are placed in different modules (each with their own jar file) inside a project. However, for smaller projects it would suffice to just place each layer in its own package structure.
Almost all applications I encounter have implemented a layering as shown in the image on the left. The arrows show the direction of the dependency of each module on the others.
As you can see, the Application Layer has a dependency on the Persistence layer. The need for that dependency comes from the fact that the persistence layer contains the Repository. Both the interface (since it is good practice to develop against interfaces) and its implementation. With my recent study of the Domain Driven Design principles, I gained the insight that it doesn’t really make a lot of sense to put the interface next (or near) to its implementation.
But why would you even bother to create an interface for the Repository at all? Well, there are a few good reasons (and probably some bad ones too) to do so. One of them is that it allows easy mocking and stubbing for tests. Another is that it allows you to replace or modify the implementation without the risk of breaking interaction (as long as the interface is maintained).
However, replacing the persistence layer with another one isn’t as easy as it seems when it contains the interface. To be able to do so, you must copy the interface into the new persistence layer implementation. And as any good developers knows, when you’re copying stuff, take your hands off the keyboard, and think for a second. You’re probably doing something wrong.
Quite recently, I had a small discussion with someone who said: “How often do you expect to change the implementation of your persistence layer?”. I didn’t really have an answer back then, but right now I am spending time on exactly that in one of my projects. And you’ll have to trust me on this: correctly designing the interface is well worth the trouble. Even if you only have to change the persistence implementation once every 100 projects. Furthermore, another project I recently started actually requires the ability to “plug in” different implementations of the persistence layer (no, not at runtime, it doesn’t have to be OSGi, unfortunately).
Inspired by the DDD sample application, I decided to place the interface in the Domain Layer. By doing this, there was no longer a need to have a (compile time) dependency from the Application layer to the Persistence layer. On paper that looks a bit cleaner. But we don’t design applications to look good on paper.
A good repository interface, as described by Martin Fowler and Eric Evans, gives it’s client the perception of an in-memory repository. In fact, it should hide any implementation choices you make about how and where data is really stored. And if you want to be able to replace persistence layers, that’s exactly what you need.
If you place the interface next to an implementation, you’re tempted to just use your IDE to extract an interface from your implementation. Chances are that your interface “leaks” information of your implementation choices. Instead, try to force yourself to design the interface first and develop an implementation that conforms to that interface later. This will help you achieve the “in-memory” perception.
A colleague of mine asked me why I chose to put the interface in the domain layer (see Separated Interface Pattern), and not the application layer, which is most likely to need the interface and call its implementation.I had three reasons.
First, the interface is described based on a small selection of domain entities. This gives the interface high coupling with these domain objects. High coupled classes are good candidates to share a package. In fact, you repository interface probably doesn’t require any import statements at all.
Secondly, it is probable that more than one service, perhaps located in different packages or modules, need to use the same repository. In that case, which package is most suitable to put the implementation in? Choosing even another package will result in lots of inter-package dependencies that aren’t really necessary. Unnecessary package dependencies decrease the ability to refactor your application .
And thirdly, the repositories provide access to your “aggregate roots”. If you have an aggregate root named, for example, “Order” and call your repository “OrderRepository”, your IDE will sort these classes in such a way, that you can easily find the most important entities in a blink of an eye.
Well, I hope this can help you in your projects as it could have helped me in the past. If you have any questions or concerns, don’t hesitate to leave a comment.