Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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?

share|improve this question
    
It seems to me that it was two issues discussed at the same time, the issue of persistance Models are classes first, and secondarily persistent (they could be persistent using xml in a filesystem, you don't need to care). and the reason for the code. Usually the things clears, at least for me, when I ask myself why the code is written, what requirement forces this code. Is it the customers requirement on how the program will work or is it from in which manner we choose to implement it. For me the first is business logic and second what you call domain logic. How this helps. –  user1041 Mar 29 '12 at 6:11

3 Answers 3

up vote 5 down vote accepted

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.

share|improve this answer
    
+1, for the second part of your answer. As for the first part, I am sure why you say that anemic domain model requires that much 'extra' work in case of change. My understanding is the change will occur any way but in several different classes (which is kind of bad) but it is almost the same amount of change; I guess? –  Emmad Kareem Mar 29 '12 at 10:23
1  
@Emmad Kareem: The comment was about having spearate persistence and domain models. Adding a property to the model then requires adding it to two model classes (rather than one) as well as to whatever maps between them (that could in theory be automatic, but usually the asshat who thought it was a good idea to have a separate "persistence model" decides to justify that separation by making them different, e.g. have datatypes that more closely match the DB type model) so that's 2+X times the amount of change, with X varying between 0 and hours of lost productivity due to obscure mapping issues. –  Michael Borgwardt Mar 29 '12 at 10:36
    
Thank you for the detailed explanation. –  Emmad Kareem Mar 29 '12 at 10:53

This is a judgement call that really depends your anticipated size and scale of what you are developing. The most rigid approach is to limit the ORM types to a data access component and use POCOs in a common library as types referenced and used by all layers. This would allow for future physical separation as well as logical separation. You could also decide that an additional layer should exist between the UI and the business logic layer. This is usually called a Facade or Business Interface layer. This additional layer is where your "use-case code" lives. The individual loosely coupled code is called by the Facade/BI layer (e.g. Facade has a ProcessOrder() function which calls into the business logic 1:M times to perform all of the steps necessary to actually process the order).

However, all of that being said: many times this amount of architecting is simply unnecessary overkill. For example, code specifically for a simple Web site where you have no intention of packaging its components for re-use. It is perfectly valid to create an MVC Web site and use EF objects for this type of solution. If the site needs to scale out later, you can look into clustering or a process often lost fray called "refactoring."

share|improve this answer

Just remind your colleague that you don't need to overarchitect the models as if this was a Java project. I mean, comparing two persisted objects is behavior, but it's none specified by the persistence layer. So the 6 beer question is: why have completely unrelated classes describing something about the same thing? Sure, persistance is a big aspect enough of a model to be treated separately, but not enough to warrant for it to be treated distinct of everything else. If you drive your car, wash it or bust it, your manipulating your car the whole time.

So why not just compose all these different aspects into a single model class? You need a bunch of class methods dealing with persisted objects--put them in one class; you have a bunch of instance methods dealing with validation--put them in another one. Finally, mix the two in and voila! You got yourself a smart, self-aware and fully contained model representation right there.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.