views:

296

answers:

7

Where I work, we've gone back and forth on this subject a number of times and are looking for a sanity check. Here's the question: Should Business Objects be data containers (more like DTOs) or should they also contain logic that can perform some functionality on that object.

Example - Take a customer object, it probably contains some common properties (Name, Id, etc), should that customer object also include functions (Save, Calc, etc.)?

One line of reasoning says separate the object from the functionality (single responsibility principal) and put the functionality in a Business Logic layer or object.

The other line of reasoning says, no, if I have a customer object I just want to call Customer.Save and be done with it. Why do I need to know about how to save a customer if I'm consuming the object?

Our last two projects have had the objects separated from the functionality, but the debate has been raised again on a new project. Which makes more sense?

EDIT

These results are very similar to our debates. One vote to one side or another completely changes the direction. Does anyone else want to add their 2 cents?

EDIT

Eventhough the answer sampling is small, it appears that the majority believe that functionality in a business object is acceptable as long as it is simple but persistence is best placed in a separate class/layer. We'll give this a try. Thanks for everyone's input...

+2  A: 

I think it makes more sense for business objects to know how to "handle" themselves, then to have to put that burden elsewhere in the system. In your example, the most logical place to deal with how to "save" customer data would be, to me, in the Customer object.

This may be because I consider the database to be the "data container", so I'm in favor of "business objects" being the higher level that protects the data container from direct access AND enforces standard "business rules" about how that data is accessed/manipulated.

Chirael
I'd say rather than the Customer object should know how to create a "saveable" representation (e.g. which attributes need to be saved and restored later); the details of *actually* persisting that representation (e.g. in a database) should be passed off to another class altogether.
Andrzej Doyle
Since the BO could be used by a dozen systems all with different languages and data stores, I'd love to see that work.
Stephanie Page
+6  A: 

Objects are state and behavior together. If an object has sensible behavior (e.g., calculating age for a Person from their birth date, or a total tax for an Invoice), by all means add it. Business objects that are nothing more than DTOs are termed an "anemic domain model." I don't think it's a design requirement.

Persistence is a special kind of behavior. What I'm calling "sensible" is business behavior. A business object need not know that it's persistent. I'd say that a DAO can keep persistence separate from business behavior. I don't put "save" in the "sensible" category.

duffymo
Just clarifying... your thought is calculations and other simple functions should reside in the object, but persistence (ie. db transactions) should reside elsewhere. Do I have that right?
Walter
Yes, that's what I'm saying. Not the only way to do it, of course. Some people like having objects persist themselves. I usually don't.
duffymo
We had always discussed All functionality in the business object or None. This is a good possible compromise we had never thought of.
Walter
@DuffyMo, honest question: So let's I'm designing a BO which is just a DTO atm. Your point is that it doesn't become a BO until I add behavior? But my BO should be an enterprise 'thing', usable by any system with a variety of languages... what language would I pick to enable behavior? or is it enough to define the behavior in terms of business rules which (sort of like an interface) provide the stubs that are to be implemented by project teams?
Stephanie Page
Hi Stephanie, just my opinion of course. If you want to call your DTO a business object, be my guest. I'm just arguing that objects without behavior feel like C structs to me and barely deserve the moniker "object". All state, no behavior. Some people separate all business behavior into services and have them manipulate simple DTOs. It's a more functional style of doing things and less object-oriented. But they're all labels, and just my opinion.
duffymo
Thanks Duffy. I'm just trying to compare and contrast modeling BO/DTO/Domain objects in the OO world to conceptual data modeling in the database world. I know the later very well, so I'm looking for insight/opinions from y'all. I've really learned from each opinion on this page. I agree with your labels. and as I watch my corp go the functional style route, I think the guys building the BO's should use the label DTO. That's all they'll do... transfer data from system to service and onward or backward.
Stephanie Page
+7  A: 

Business objects CAN have business functionality.

Persistence is not a business functionality , but is technical implementation.

Long story short:

  1. Save/Update/Delete/Find etc - keep away from the business objects in a persistence layer.
  2. CalculateSalary, ApplyDiscount etc are business related methods and can be:
    1. methods of the business objects (so BO is self contained representation of entity) or;
    2. separate services implementing particular functionality (so BOs are acting more like DTOs).

As for the point 2.
I should mention that the approach 2.1 tends to make the BOs too bloated and violate SRP. While 2.2 introduces more maintenance complexity.

I usually balance in between 2.1 and 2.2 so that I put trivial things related to the data into Business Objects and create services for a bit more complex scenarious (if there are more than 4 lines of code - make it a service).

This shifts the paradigm of Business Objects to be more Data Transfer Objects instead.

But this all makes project easier to develop, test and maintain.

Dmytrii Nagirniak
I acutally split 2.1 and 2.2 with the amount of stuff needed. Functions needing the business object or only related objects of the same functional group - go into the object (CalculateAge on Person). Processes using more unrelated objects (CalculateDiscount when it takes into account residence, delivery etc.) is a separate service, most likely even a separate module / assembly. Very complex logic is a separate class, too (PaymentPlanCalculator on a credit), but using C# exposed as extension method (used on the class, but technocally not on it).
TomTom
Thanks for making me read up on SRP. Doesn't that tend to bloat the number of classes, making knowing where to DO the maintenance harder?I know, should be a whole new question.
Stephanie Page
+1  A: 

Business objects should be about encapsulating data and associated behaviors of the business entity modeled by that object. Think of it like this: one of the major tenets of object-oriented programming is encapsulating data and associated behaviors on that data.

Persistence is not a behavior of the modeled object. I find development progresses more smoothly if business objects are persistence ignornant. Developing new code and unit testing new code happen more quickly and more smoother if the business objects are not specifically tied to the underlying plumbing. This is because I can mock those aspects and forget about having to go through hoops to get to the database, etc. My unit tests will execute more quickly (a huge plus if you have thousands of automated tests that run with each build) and I will have less stress because I won't have tests failing because of database connection issues (great if you often work offline or remotely and can't always access your database and oh, by the way, those aspects (database connectivity etc.) should be tested elsewhere!).

The other line of reasoning says, no, if I have a customer object I just want to call Customer.Save and be done with it. Why do I need to know about how to save a customer if I'm consuming the object?

Knowing that Customer has a Save method is already knowing how to save a customer object. You haven't avoided the problem by embedding that logic in your business object. Instead, you've made your code base more tightly coupled and therefore harder to maintain and test. Push off the responsibility of persisting the object to someone else.

Jason
Seems most of the answers here are taking a very unilateral approach. There is only one language, and so you can conflate a 'code' object with a business object. Am I naive to take a wider view, that my business object's methods aren't implemented in the design of the BO itself but rather in each solution that seeks to use that BO?
Stephanie Page
@Stephanie Page: It has less to do with the language and more to do with the potential pattern. The problem comes when the focus of the objects behavior crosses from domain to the environment. If objects are being saved to a database, do we need to include the database logic in each domain/business object, i.e. connection strings and field/column mappings or SQL statements? This approach quickly becomes unmanageable unless the DB logic is factored out into its own layer. Few languages can handle this situation and keep it from being a source of bloated or redundant code.
Kelly French
I like that: Crosses from the Domain to the Environment... that's a nice metaphor.
Stephanie Page
+1  A: 

The answer is the same regardless of platform or language. The key to this question is whether an object should be able to be autonomous or whether it is better for any given behavior to be spread out among objects with more focused responsibility.

For each class the answer might be different. We end up with a spectrum along which we can place classes based upon the Density of Responsibility.

                          (Level of responsibility for behavior)
         Autonomy - - - - - - - - - - - - - - - - - - - Dependence  
      High
  C      -   <<GOD object>>                            <<Spaghetti code>>
  l      -
  a      -  
  s      -                                      
  s      -                 
         -                        
  s      -  
  i      -  
  z      -
  e      -  <<Template>>                                <<Framework>>
       low

Let's say you favor letting the class perform all the behaviours itself, or as many as you can. Starting on the left side of this graph, when you make your class more autonomous, the size of the class will grow unless you continuously refactor it to make it more generic. This leads to a template. If no refactoring is done, the temdency is for the class to become more "god-like" because if there is some behavior it needs, it has a method for that. The number of fields and methods grow and soon become both unmanageable and unavoidable. Since the class already does so much, coders would rather add to the monstrosity than try to piece it apart and cut the Gordian knot.

The right side of the graph has classes that depend on other classes to a large degree. If the dependency level is high but the individual class is small, that is a sign of a framework; each class doesn't do much and requires lots of dependent classes to accomplish some function. On the other hand, a highly-dependent class that also has a large amount of code is a sign that the class is full of Spaghetti.

The key to this question is to determine where you feel more comfortable on the graph. In any event, individual classes will end up spread out on the graph unless some organizational principle is applied, which is how you can achieve the results of Template or Framework.

Having just written that, I would say that there is a correlation between class size and degree of organization. Robert C. Martin (or "Uncle Bob") covers similar ground with package dependencies in his very thorough paper on Design Principles and Design Patterns. JDepend is an implementation of the ideas behind the graph on page 26 and complements static analysis tools such as Checkstyle and PMD.

Kelly French
+1 Nice breakdown. This will add a lot to our debates. Thanks.
Walter
How long did it take to get the graph to work? Very nice answer... one of the best Q/A on the site.
Stephanie Page
@Stephanie: It took a lot of trial and error. This answer is one of the reasons I submitted a feature request on Meta for table support in Markdown. http://meta.stackoverflow.com/questions/16356/why-cant-table-markup-elements-be-used/29368#29368
Kelly French
This page is what SO should be. Too many <tags> are full of posers, well meaning, but completely misinformed script kiddies. I guess the subject matter here isn't interesting for the kid that wants to make an app that manages their Pokemon cards. Only serious - enterprise minded - real IT'ers need apply here.
Stephanie Page
A: 

The Business objects, as they are named, should obviously coutain their own business logic, the dynamic of the business logic among the domain being in the service layer.

On the other side, could the BO be a data container (DTO?) composition and methods; meaning BO are pure functionnal? That could avoid all the conversions between BO and DTO.

A: 

In an MVC architecture,

Can we say that Model contains business objects.

Ramesh