“EAV fallacy” – assumption, that you can model complex problem with an Entity-Attribute-Value solution
I’ve been involved in a few projects which tried to use the similar EAV structure (SQL or JSON replacement) to embrace difficult logic inside of the system. Mostly because we wanted to handle “unknown need” from a business perspective. For example, we wanted to use a similar structure for modeling:
etc. The client naturally couldn’t predict all the future possible uses of the application. So the best option to prevent from the rebuilding it was to add dynamic structure. With entities and entities types, like the above ones.
On paper, it would allow us to use this structure to map new requirement in the same application. We wouldn’t need to think about changing schema – only to add a new entity type to our application. The application could work without any code change or deployment.
On paper / in reality
There is this presentation on DDD Europe where Avraham Poupko talks about different perspectives on software modeling. He says that:
“The complexity does not lie in relationships between objects. The complexity lies in:
- Why there is a relationship?
- Why it the domain the way it is?
- What objectives does the domain want to achieve?”
and it is very applicable to our solution.
Use of EAV model hides all purpose from an entity to its attributes. We can model data ownership. We cannot model entity behavior, how it acts and relates to its parts.
It’s not a problem when we use such dynamic structure just to show data on the page (e.g. WordPress does with its dynamic posts types). It is an enormous problem when we want to handle additional business logic in this kind of structure.
Let’s assume that you can rent a Car, Bike and Apartment entities, but not Restaurant entity. You need to handle this logic somewhere in the application. But your entities are dynamic, so you need to create an additional column like IsRentable and add it to EntityType. And implement handling this restriction in your application.
Then you find out that you rent your Car and Bike entities differently than Apartment entity – you need to add some additional fields in the UI form to provide information needed for settling legal formalities. So how to show it dynamically? Another dynamic structure to handle this situation like RentFormField, RentFormFieldConfiguration etc. with dynamic form generation mechanism.
After it, you want to review your rent. And more variations. You can review only one parameter in Bike entity, but multiple in Car entity, like condition, cleanness, customer service. So RentReviewField, RentReviewFieldValue and views generators for every case.
And so on and so forth… Dynamic structure spreads like cancer.
This solution has even more damaging drawback – performance. This works only with a small set of data. And completely collapses when data sets reach numbers of millions or more.
You cannot achieve sufficient response time with querying this structure when you want, for example, get cars’ average customer service ratings in last week. It requires to go through this deep and complicated architecture to bring out single value and then process it.
Achieving proper performance in such dynamic structure requires to create dynamically read model structure with proper data gathering from the EAV data model. Creating a mechanism to do it on demand, during adding new entity type, is a challenge which I’ve never seen to been accomplished. You would need to automatically use almost all services from data & analytics stack of your environment (e.g. Azure)
The fallacy is that you can model complex business models with such solution. You cannot. Complex problems require complex solutions. You cannot jump over it. It will kick you back when you’ll try to handle it the easy way. And EAV is the easiest way. So it doubles the kick.
From software perspective models always reduces the complexity of a problem to some proper extent. But if you reduce it over a point, your model won’t be able to handle all needed requirements. So the logic will leak which leads to accidental complexity – not the problem’s one but the solution’s one.
You add complexity to your solution, not reduce it, by using EAV in not trivial problems. In other words, EAV gives you enough rope to hang yourself.