5

Sorry about the many abbreviations in the title... My observation is that applications built with an object-relational mapping like Hibernate tend to follow a service-oriented architecture instead of an object-oriented one.

Some people (e.g. here) say the Single Responsibility Principle suggests that dealing with reading/writing attributes of persisted objects as well as creating and finding these objects is enough responsibility for one class. Any business logic using such an object should go to separate classes. That leads us to a design with two separate types of classes: state-full but dumb record keeping ones, and logic bearing but state-less ones.

Here's why I don't like this kind of design:

(1) To me, this separation of data and code is not a goal of object-oriented but is the design of service-oriented architecture. OOD says that operations should go to the classes where the attributes it uses are defined at.

(2) Also, it's a bogus solution: whenever the structure of one of the state-full classes changes, I'll have to change all the service classes that use it, too. If I had the logic inside those classes, the change would stay in one class.

(3) I'm using an ORM framework which pretty much generates all the code necessary for accessing the persisted data for me into a class. If I wasn't adding the business logic to it, the class would stay rather "empty", i.e. it would contain the generated code only.

I know that many programmers follow the service-oriented design, especially when using frameworks that suggest this, like Spring. If I were using such a framework, I'd go with the separation of code and data, too.

I don't want to provoke a discussion whether SOA is good or not. I'm interested in the question whether it's good OOD (as per SRP) to separate business logic from classes representing entities.

2 Answers 2

4

TL;DR:

There is no silver bullet

Long version:

The background regarding SOA and ORMs seems relatively unnecessary, so I'll just focus on Is it good object-oriented design to separate business logic from classes representing entities?

I'll just try to reason about a architectural situation where I personally found it useful to have 'thin' entity classes.

Situation:

In a program I am currently, privately building I am designing an NHibernate modeler; you make a visual diagram with boxes and lines and stuff and in the end it is translated into some form of output recognizable by NHibernate.

Core system:

  • Model elements such as mapped values, has-many, has-one, many-to-many etc.
  • Output these into POCO classes, NHibernate xmlfiles and/or Fluent NHibernate mapping classes.

So, what should go into for example ManyToManyRelation (i.e symmetrical relationship with another entity)?

I think it is obviously not feasible to put both display logic, output logic for POCO, output logic for Fluent and output logic for XML in ManyToManyRelation.

Display data for an element (i.e render it on the screen at x,y etc) is orthogonal to the relational data. It must be persistent, but not in the same files as the relational data. This makes it natural for me to create some form of external 'attribute' classes which maps to the elements, that is persistable but entirely separate. So display data and logic does not go into entity classes.

We have three different output formats, at least. Since we are likely only interested in one type of output (XML vs Fluent) at one time, it makes a lot of sense to separate this out to separate 'service' classes with some form of common interface.

Furthermore, if we represent the model as some form of graph and consider ManyToManyRelation, we realize that it is symmetrical regarding the entity classes - it belongs just as much to Entity A as Entity B. One way to model this is that both Entity A and Entity B 'contains' the ManyToManyRelation. But then, which of them actually draws and outputs these 'shared-ownership' objects? By delegating out to a third 'service' class this becomes a non-issue. So output logic does not go in the entity classes

I realize much of these issues can be solved in other ways - that's not the focus of my reasoning. I think it is entirely reasonable to have thin 'data' classes and then build an application that acts on this data. It is also entirely reasonable to put at least some core logic in these classes. It all depends on the domain.

If you have read this far, congratulations, thank you and have a cookie :)

2
  • I think your example shows the need for separate classes because there are 1+n separate "modules": one business/core model, and n output models.
    – Wolfgang
    Commented Mar 26, 2012 at 12:21
  • @wolfgang Well, please note that everything that 'happens' in that system happens in decoupled modules, not just output. The thing those domain classes do is containing and enforcing a correct graph of relations, as defined by NHibernate. You asked whether or not it can be good OO to do this - I think I've shown a few cases where it is a good approach. There's definitely others out there though.
    – Max
    Commented Mar 26, 2012 at 12:43
0

Is it a good design to have save and load methods on a data class? Yeah, I don't see why not. Is it a good design for the data object to know HOW to persist itself? No, I don't think so.

I always like Robert Martin's definition of the SRP:

There should never be more than one reason for a class to change.

This is much clearer than talking in terms of responsibility, which really doesn't mean anything in programming terms.

So, if we change the properties of a class, we should go to that class to change it. Thus there should be no other reasons to change that class. If we decide that XML files just aren't cutting it any more and we need to move to a database, we should go to another class. If we change the validation rules for an object, we should go to another class.

Does that mean we cannot have a save or validate method on a class, passing the request on to a repository or validator class? Not at all.

One of Martin Fowler's famous Bad Smells in Code (see Refactoring, 1999) is "Data Class". He suggests that, where there is an excess of getters and setters on a class, we should endeavour to move the methods that call these getters and setters into the class itself - the intent being to eventually remove access to the data and only allow operations on an object.

But that does not mean that Fowler believes the single-responsibility principle to be worthless. It just means that there are sensible lines to be drawn.

In the same way that we have said "There should never be more than one reason for a class to change," we should also avoid having a spaghetti of code where a single change requires changes to many, many classes.

In our earlier example of persistence, we could argue that when I add a property to the class, I also have to change the way it is persisted. In that case, many years of combined experience tells us that this is fair enough. It is basically two changes (how it is perceived by the application and how it is persisted) so changing two classes is about right.

But it's all pretty subjective. We have to consider every case on its own merits.

ORMs really have little to do with this, except that they do reduce the boilerplate code in between data and storage -- this should suggest to us that we were right to choose this as the line.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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