Some time ago I used to work for a company that made gelatin capsules used for drug administration. The process was a tricky one: there were several machines that would mix the gelatin and then you have a to wait a cool down time before you could start using it. There were different kinds of gelatin with different mix and cooldown times. My job was to create a simulator that would calculate the optimistic use of the machines given the requirements for different kinds of gelatin. I was given access to a database that had everything I needed. So my initial domain model was based on the DB structure. As time passed by, however, it was clear that the current model was lacking a lot for my purposes. So I just dropped the whole thing and start anew. Using a repository I then mapped the domain model to the DB model. Then something funny happened: my manager could not understand my domain model since he could not reason outside of the DB one. It took me some time to figure what was confusing for him…
Not too long ago I heard something similar. I was helping a friend at work to distill a domain model that was based on a DB. I didn’t do much, just giving some pointers on how to apply OOD principles and helping him to find out how to allocate responsibilities to the right objects. As the model became more clear he came to the conclusion that some of the DB design decisions were getting in the way, so he decided to create his own domain model. Once he did that, the code became so much clear.
The fallacy of one model to rule them all
Unfortunately, a lot of people tends to start modeling the DB and then create a domain model that mimics that structure. That works for a relatively simple system but it won’t stand against a more complex one. The reason it’s simple: the DB model, serves a different purpose than solving the problem. Actually, we deal with several models on a system, each one serving a different purpose. Let’s go over them.
The persistence model
I’ll start with this because often this is the starting point when designing a system. The persistence model actually has the purpose of storing data efficiently. That’s it. We often use E/R diagrams as a tool to understand the concepts of the domain and the relationship between them. One problem with this is that often these concepts are related only on a given context and these relationships are not valid out of that scope. A very experienced developer can avoid that but I argue there are better tools for analysis than E/R diagrams. Usually, the persistence model is very granular.
The domain model
The domain model it’s the one responsible for solving a very specific problem. Hence a domain model should be very specific. Designing a domain model requires you to have an understanding of the problem. This is part of the solution and not the problem space. I believe this model should be created before any other one. If you are using OOP, this model comprises your objects and the interactions between them. Is often more coarse than the persistence model.
The presentation model
The purpose of the presentation model is to allow the user to interact with the system.
When dealing with an object-oriented system, there are 2 schools of thought regarding the user interface: task-based and object-based.
Task-based user interfaces are geared towards a task that involves several objects interacting together. It’s like a script that a set of objects has to follow to accomplish something on behalf of the user. This often results in a more coarse model that aggregate several domain objects. Objects on this model are often called view-model objects.
Object-based user interfaces are predicated on the idea that the user should be able to manipulate the objects together as he/she sees fits to accomplish anything he wants. This means exposing the underlying domain model directly to the user. Patterns and frameworks such as naked objects are examples of this idea.
Traps and tricks
One of the problems I often encounter comes from the use of ORM’s. I’m not saying that using them is bad, but you should use them carefully. They often introduce constraints from the underlying persistence mechanism, forcing us to concern with stuff other than solving the problem at hand. They also somehow promote coupling so it’s not easy to switch the underlying persistence technology, ie from a relational to a document DB.
Another problem arises when you try to expose your domain objects on a task-based UI. In my experience they become intermingled with UI logic, making them a mess that is hard to maintain. Often you end up with additional data that has nothing to do with the object original purpose.
Eric Evans figure this out long ago. That’s why on DDD he provides us with patterns to isolate the domain model from any external influence. Repositories allow the domain model to be completely independent of the persistence model whereas the application API isolates it from the UI. Unfortunately, the intent behind these patterns has been forgotten and thus misused and abused of these patterns arise.
Next time you start a new project, put mechanisms in place to keep your models separated.
Whenever you find yourself struggling to accomplish something because your model (be it persistence, domain or presentation) cannot accommodate that change without creating a ripple effect to the other models, take a look at the patterns mentioned here and look for ways to isolate the model. This may take some time in the present, but it will pay handsomely in the future.
Good luck out there!