Definition of behaviour

Definition of behaviour

Old forum URL: forums.lhotka.net/forums/t/2577.aspx


gderoeck posted on Thursday, March 22, 2007

Hello!

I've been reading the forum and have thumbed through the book to find a clear definition of behaviour, but haven't found one.  I understand the mantra of "classes are defined by behaviour" and agree that this is vital to correct design.  I've heard Rocky state that a class should only have one responsibility/behaviour.  Question I have is, how broad is the term "behaviour" supposed to be?

In EditableRoot objects, there are methods such as Create, Update, Fetch and Delete.  Could these methods not be considered individual behaviours?  Or, should behaviour be defined in CSLA in a more general sense, like "Maintain an Invoice"?

My whole reasoning behind asking this question is, number one, I'm new to CSLA - have written only one application using the framework so far.  Our BA has put together a Use Case model for another, larger application and I'm trying to define and design the objects around the model, as stated here and in the book.

She has steps in the use case such as "Create the chart", "Save the chart" and "Delete the chart".  (This is a medical application.)  Now, I understand that "Display the chart" could be (and probably should be) a readonly object - that's not difficult to understand.  But, the use case model I'm looking at has these three steps mentioned earlier that, I think, could fall under a more general category of "Maintain a chart", or something to that effect.

Am I off on this?  Is my thinking correct?  I guess the only trap I would need to watch out for is to make sure "Maintain a chart" doesn't become so broad that it loses its responsiblity.

Thank you in advance for any input - I just want to make sure I am on the right track in my design.

-Greg

malloc1024 replied on Thursday, March 22, 2007

Responsibility and behavior are not interchangeable terms.  Behavior is what the class does while a responsibility is a reason for change. 

 

Rocky is referring to the single-responsibility principle which states that a class should have only one responsibility (reason for change).  The business object’s responsibly is to enforce business rules for an entity.  This should be its only responsibility.  Once you add database code to the BO, you introduce another reason for change.  The BO will change if the business rules change and when the persistence logic changes.  This violates the single-responsibility principle.

 

If the business rules state the chart can be added, updated and deleted, then these functions belong in the chart object.  This satisfies the single-responsibility because they fall under the category of business rules.  However, the actual code that interacts with the database is another responsibility and should probably be separated. 

Keep in mind the single- responsibility principle is a guideline and not a rule.

SonOfPirate replied on Thursday, March 22, 2007

To expound on what malloc said, you are correct that creating, updating, deleting, etc. ARE different behaviors but, as malloc said, they fall within the single-responsibility principal for the object.  Where behavior is important is when looking at inheritance, encapsulation, collaboration, etc.  The goal of the framework is to inherit behavior.  This is supported, for example, by having the data portal CRUD operations in a base class.

 

gderoeck replied on Thursday, March 22, 2007

Wonderful, that's the clarification I was looking for.  Just so I can make sure I understand....

It would be accurate to say that a class, in a well defined model, would have one responsibility.  The behavior(s) of the class is/are directly related to that responsibility.  So, in a class, the word "behaviour" could be interchangeable with the word "action".  (Stop me if I'm off on this...)

So, take my example.  I have a Chart object that has the responsibility of maintaining chart data, meaning it has behaviors of creating the object with default values, retrieving, adding, updating, or deleting chart data.  Now, I have another class, named ChartDisplay that has the responsiblity of retrieving certain fields for readonly display (for a print preview, for example).  This class has the behaviours of creating the object and retrieving data.

This next part is where I may be off.............

Now, since the Create behaviour is common among these two classes (meaning, they both return an object with the same default property), would it be correct to assume that this could be a candidate for normalization?  If a Create method returns an object of either type with a common default property (say, a User object that contains the UserID, FirstName, LastName, etc), I would think this is correct.  All I would have to do is designate which type of object to create.  Meaning, the Create() method could become either it's own class or part of a module that contains common behaviours, thus normalizing the behaviour.  (Much like the Assignment module in PT).

The Retrieve, or Fetch behaviour isn't common between the two because they don't return the same set of data.

So, am I getting this or am I still confused?

Thank you both for the responses - I'm trying to make sure I start down the right path.

-Greg

ajj3085 replied on Friday, March 23, 2007

Greg,

I don't see how the create is common to both the editable and read-only objects.  Actually, I would think that the read-only object would only have fetch behaviors.

Regarding the definition of behavior, the other posters are correct.  I think someone said at one point that technically having the data access in the code does violate the SRP, but that there really is no good way to help overcome this, so we must accept that we violate the prinicpal.  That's ok, because SRP is a guideline... we should follow it, unless we have very carefully considered the reasons that we need to.

malloc1024 replied on Friday, March 23, 2007

If the creation of a business object has behavior that does not fit the responsibility of the business object, it should be separated into another class.  This is typically done with a factory. 

 

If ChartDisplay is a read-only version of Chart, you could create a factory class that sets the defaults and returns a common interface.  You would need to create an interface that would contain the properties and methods that are common to both.  However, ChartDisplay and Chart really don’t have any behavior in common and you would end up casting to its concrete classes in most cases.  This makes the factory in this case less useful and probably unnecessary. 

SonOfPirate replied on Friday, March 23, 2007

Greg,

I think you hit the nail on the head when you said that your Chart object is responsible for managing chart DATA and your ChartDisplay object is responsible for providing the data to the UI for presentation.

I understand the inclination that both of these objects share the same creation process but I caution you to think a little deeper and examine how common they really are.  For instance, will they both use the same SQL statement / stored procedure?  If you define a common ChartBase class, would you have to override the create method in each of your derived classes in order to make them work?

Remember, just because two objects may work on the same data and may share some properties does not mean they are good candidates for inheritance.  All objects have some form of a creation/instantiation behavior but unless the implementation of that behavior is common, inheritance may not be appropriate.  Of course, an abstract (MustInherit in VB) base class which forces you to implement the method in your derived class is an acceptable way to implement common properties, etc. if you are concerned about code reuse.  But, I caution you that once you create an object graph such as this, you are also introducing possible issues with polymorphism.  Ask yourself if you really want to accidentally use a ChartDisplay object when you want a Chart object.  Having an abstract base class or interface common between the objects and used as the return type from a factory method, for example, means that you have to be aware that either object could be returned.

This last point is a significant reason why you should always program to interfaces - because of the extensibility, etc. of the approach.  However, you need to do so with awareness of the flip-side and that is the unwanted risk that an unintended object that also implements the interface is returned.

Because you have two clearly defined responsibilities, I do believe that you need two classes: Chart and ChartDisplay.  However, thinking through how their behaviors are implemented, it seems to be that they don't have much in common other than the data that they work on.  And this is not enough basis for inheritance.  At least, IMO.

HTH

 

gderoeck replied on Friday, March 23, 2007

This is all great information, thank you to everyone for your input.

I'm thinking that the Create method I referred to may have been a bad example.  In actuality, the reason I used it is because both the Chart and the ChartDisplay object will be used at the same time. 

The idea is that a Chart will be have various sections, or properties, that will be child objects.  At the beginning, the Chart(editable root) and the ChartDisplay(readonly root) will be created exactly the same way every time - by passing an existing User object to an identical child property in both classes.  This object will already exist because it would have been created when the user logged into the application.  So, both objects will be created the same way. 

The Chart object will be updated by filling child objects through the individual screens in the application.  For example, the user logs in and creates a chart.  At this point, the ChartDisplay object would contain only the data from the User object and nothing else, since nothing has been filled in yet.  At the same time, the Chart object will contain the exact same User object and nothing else as well.  As the user fills in sections of the application, or Chart (such as Cardiac, NeoNatal, Burn) and saves them, the associated child object is populated with data.  The Chart object is responsible for Updating, Saving and Deleting the core data within the object.  As well, it encapsulates the data within the child objects so that no manipulation of that data is done outside of the Chart object itself.

The ChartDisplay object is responsible for providing a "View", or Fetch of the actual description fields of the data.  This data is then displayed in the UI and refreshed every time the user completes or cancels out of a section.  The ChartDisplay object would also have ReadOnly children representing the individual sections that mirror the Chart object's children. 

When a chart is complete, it needs to be either FAXed or printed.  There will be another object that will be responsible for this as well that will be passed the ChartDisplay object for processing.

I hope I explained that well enough.  In what I have so far, there's no inheritance used really.

Again, I'm still in the design mode of this, so nothing's in stone yet. :)  Again, thank you all for your comments.  I appreciate the help!

-Greg

RockfordLhotka replied on Friday, March 23, 2007

This is why responsibilities and behaviors should both be described by short phrases. Single words can imply similarity where there is no real similarity.

Order has "create"

Customer has "create"

But "Create an order" and "Create a customer" are clearly not the same behavior.

Of course, once you dig into how to implement both those behaviors you may find some commonality. Certainly that's what CSLA is all about - defining and implementing commonality across data binding, n-tier behaviors, persistence and so forth.

But remember that reuse is a side-effect of good OO design; not a goal.

malloc1024 replied on Friday, March 23, 2007

Greg,


I am not exactly sure if you need a ChartDisplay class here.  The Chart class can be used to display the information to the UI.  However, if you want to present the Chart data to the UI in a different way, you could create a ChartDisplay class that would accept a Chart object and wrap it.  This would create another view of your data.  You could also flatten your object model and make it read-only with the wrapper class if you like.

gderoeck replied on Monday, March 26, 2007

Thanks again to everyone.  Great discussion!

Malloc - the reason I'm thinking of two classes is because there will be a difference in the data in the sense that the actual values of the fields will be the ones updated, saved, etc, whereas the description of these values will be the display fields.  Much of the data in the UI will be displayed in drop downs, list boxes and check box fields and each of these will have values associated with them that will be saved as opposed to the descriptions.  The backend data will be foreign keys associated to data tables for the majority of the application.  So, you can see that the store procs to retrieve the data will be different because, in the Chart object, the fields will be the values whereas the ChartDisp class will be the actual descriptions.  To combine the two would result in one big bad class and would violate the "one responsibility" thought.

Rocky - I see your point where you say responsibilities and behaviours should be described in short phrases.  That makes it much easier to define the responsibility, obviously.  I forgot about that section of the book where you covered that - I need to go back and read it more carefully.  It probably was a stretch to think that the Create method could be combined for both classes.  I'll take another look at that as well.  Thank you!

-Greg

Jimbo replied on Tuesday, March 27, 2007

I notice that malloc used the word "Entity". What is an Entity in the csla world? It's not a common word in Rocky's terms. Is it a BO, a representation of a data relation, a DTO, or what?

ajj3085 replied on Tuesday, March 27, 2007

I don't think it's normally used in the Csla world, unless you're talking about entity in the relational db context.  I think malloc's use of entity would best be replaced by 'use case'

Copyright (c) Marimer LLC