Forget about the ORM when modeling the domain
What is an ORM exactly? It is not clear. Ask around you, you won’t always get the same answer.
Some would simply say that it is for abstracting database operations. Other that it is for designing the database with an object oriented approach.
These definitions are often incomplete, but also, the database is really centric in them, and my opinion is that this is an issue.
ORM exists, I think, for letting the developer designing his models the way he wants, without being preoccupied of how it would be persisted.
Is it really the case?
My answer is no.
When it comes to designing complex domain models, the ORM becomes an issue, because it tries too hard to map your object members to a relational database. So you often need to introduce some complexity in order to get what you want.
Why exactly do we need ORMs for?
My experience is that we need them for exactly two reasons:
- Automagically resolving object relationships for persisting data in a traditional relational database;
- Querying data.
But, my experience also is that the first reason exists only because of the second reason.
Write operations in a database are simple, really. All the complexity resides in querying for the data.
Why is it complex?
Well, it shouldn’t. It is complex because many developers want to do everything with the same model: implementing business rules, persisting data in a way they can easily query for them later, mapping them to UI operations, … Is it a misinterpretation of the DRY principle? ;-)
That is for sure a great challenge to get a clean domain model which can do all of it! And my opinion is that we simply can’t.
Some of these features force the developer to open their models to the world and then to introduce potential inconsistencies. Plus, for pleasing the ORM we often have to follow implementation rules which are totally closing our mind on the real life domain issues because we focus on getting things to work.
So, my advice is that when you need to design a complex domain model, with strong rules and need to protect it against inconsistencies, DO NOT use the same model everywhere in your application. Separate domain concerns, like handling write operations and protecting your invariants, from UI concerns, like querying data and formatting them for the client.
You will be able to unleash all the power of Object Oriented Programming, and then focus on the real stuff. You will think about how to show information to the user later, this is an entire different aspect of your application that should be worked separately.
How to do it?
Here I won’t give information that you already can find everywhere on the web. This approach is what CQRS (Command Query Responsibility Segregation) is about, a pattern that is often used in Domain Driven Design.
By searching cqrs in Google, you will find a myriad of interesting resources.
Now that you concentrate only on write operations, you can play with OOP well and easily follow SOLID principles, especially the Single responsibility and Open/Closed ones which can really help you protecting your model against inconsistencies.
You won’t need complex queries for hydrating your domain models anymore, you can simply fetch them entirely, handle some behavior and then persist them as they are, no more no less. A basic key/value store would do the job ;-)
And as for the query layer, you are now free to “normalize” your data the way you want in order to fit exactly the UI needs.
Is the ORM still useful then?
I would say it depends on the complexity of the application and the performance you need to get. I won’t lie, I like ORMs. I don’t like handling database operation nor managing database schemas, I prefer focusing on modeling the domain which is way more fun.
Automatic mapping/hydratation of the models still is really convenient. But if you separate concerns correctly, you don’t really need this anymore. The write models can be written as they are, and for the read models, a simple DBAL would perform much better since your database now can be structured exactly as the UI needs it.
So I would go with DBAL but I’d forget about the ORM in most cases. But again, don’t take this as an universal answer, it really depends of the application needs.
Note that depending on the UI needs, you won’t necessarily use a relational database, in many cases, dedicated technologies would be more efficient, like Elastic search if you need a search engine for instance.
Also note that when you use a dedicated search engine, you already are separating writes from reads, just extrapolate the same logic to your entire application and you will be released from a lot of frustration ;-)