ORM – Thick Models vs. Business Logic: Where to Draw the Line?

abstractionbusiness-logicorm

Today I got into a heated debate with another developer at my organization about where and how to add methods to database mapped classes. We use sqlalchemy, and a major part of the existing code base in our database models is little more than a bag of mapped properties with a class name, a nearly mechanical translation from database tables to python objects.

In the argument, my position was that that the primary value of using an ORM was that you can attach low level behaviors and algorithms to the mapped classes. Models are classes first, and secondarily persistent (they could be persistent using xml in a filesystem, you don't need to care). His view was that any behavior at all is "business logic", and necessarily belongs anywhere but in the persistent model, which are to be used for database persistence only.

I certainly do think that there is a distinction between what is business logic, and should be separated, since it has some isolation from the lower level of how that gets implemented, and domain logic, which I believe is the abstraction provided by the model classes argued about in the previous paragraph, but I'm having a hard time putting my finger on what that is. I have a better sense of what might be the API (which, in our case, is HTTP "ReSTful"), in that users invoke the API with what they want to do, distinct from what they are allowed to do, and how it gets done.


tl;dr: What kinds of things can or should go in a method in a mapped class when using an ORM, and what should be left out, to live in another layer of abstraction?

Best Answer

I'm mostly with you; your colleague seems to be arguing either for the anemic domain model antipattern or for duplicating the model in a "persistence model" with no obvious benefit (I'm working on a Java project where this was done, and it's a massive maintainability headache, as it means three times the work whenever anything changes in the model).

What kinds of things can or should go in a method in a mapped class when using an ORM, and what should be left out, to live in another layer of abstraction?

Rule of thumb: the class should contain logic that describes basic facts about the data which are true under all circumstances. Logic that is specific to a use case should be somewhere else. An example is validation, there's an interesting article from Martin Fowler where he makes the point that it should be considered context-dependant.