Greetings all ...
I'm doing another iteration of a domain model in C# -- a part of which has an object model of:
1.0.0.0 Actor
1.1.0 Individual
1.1.1 Employee
1.1.2 Contact
1.2.0 Organization
1.2.1 Internal Organization
1.2.2 External Organization
1.2.2.1 Vendor
1.2.2.2 Customer
I've implemented something similar using CSLA and found the Forum theread on
to be quite helpful.
Yet I'm concerned that I am still stuck in a data-centric design view.
I just dont feel confident that I "get" the behavior-centric thing and certainly don't see how I might be able to avoid creating too much complexity by using containment instead of inheritance.
I've browsed GOF concepts and other best practices guides and still don't feel confident that I have wrapped my head around a convincing alternative design.
What I'd really like to see ( if indeed there is a "better practice alternative" to my hierarchical inheritance tree ) is some views on re-factoring my Actor object graf that takes advantage of containment and behavior-centric design.
Any pointers to literature that focuses on these issues will be a big help ... but of course, I'm hoping that this note will trigger a stimulating discussion.
Thanks again,
Steve
Hi Steve
I'll have a go at helping you, though I'm no expert or anything so you may want
to do some more reading around. I thought I had a good understand of OO before
I came across CSLA, it really through the spanner in the works. I think I've
got my head around the problem now, basically in framework level code there
is lots of behaviour going on so inheritance is common place this does not
translate into business applications. Meaning many BO don't deal with much behaviour,
well not really ballsy behaviour like you find at lower levels. Remember you
should inherit behaviour not data. Any behaviour you do want to “pass on”,
particularly in the business layer is probably better provided to multiple
objects by means of composition. Anyway that’s just random background thought
on how I’m getting to grips with CSLA, Use-Case driven and SRP.
Moving on to the problem at hand, I think you desperately need to take a step back to use-case level. When you laying out your object I’m presuming your suggesting Employee inherit Individual which inherits Actor?
1.0.0.0 Actor
1.1.0 Individual
1.1.1 Employee
1.1.2 Contact
I think you need to ask yourself (and the objects), why? Is there shared behavior, is more probably just shared data? Be honest with yourself here! It took me a while to convince myself about this on occasion.
If they are just sharing data break them up so Employee and Contact are there own root BOs. Lets say somewhere in your system you need a list of individuals and there phone numbers, so at this point you might be thinking, well if I’d sub-classed Individual I could just take my objects and regardless of there actual type get there Name and Number as that data are properties of the Individual class. However you can do this, you just need to prepared to make the BO to match you use-case. Your use-case being provide user with a list of individuals names and numbers.. blah blah.. So at this point you’d need to think do any of my BOs (currently Employee and Contact) provide me with this info, the answer being no. Employee maintains a single Employee and Contact and single Contact. So you need a need object say IndividualInfo which has the properties Name and Number. Make a list say, IndividualsList which is a list of these IndivudalInfo objects. So now you have the object set to meet the use-case. Simply get the data from the various database tables (or other data store) and put it in the info objects.
I’m yet to find any specific literature that would demonstrate such concepts as multiple Customer objects for different use-cases for instance. However the Applying UML and patterns book by Craig Larmen is an excellent overview of OO techniques. The two cases studies in the book are not forms-over-data style apps though. There is a point of sale system and a monopoly game both of these are rich in behavior so you have to take a step back and remember that they are different types of systems to what most people develop most the time.
Sorry it’s a bit rambley, I just through a few ideas down; if anything catches your interest and you want me to be clearer on something let me know.
George.
Thanks, George ... I'm just starting to process your feedback ... here are my initial reactions / conclusions
Encapsulating CRUD/ DataPortal functions in an inheritance chain of business objects ... that really cool pattern of passing the command object from the Organization and Individual up to the Actor -- base.insert(cm) --- to populate parameters before excecuting the DoInsertUpdate function in the Organization orIndividual
... That's not really an appropriate use of inheritance???
Better to contain an instances of :
and
I'm puzzling over how I can follow that containment pattern and keep the number of database command executions to a minimum.
I see the value in creating a separate "IndividualInfo" object for the phone and address attributes for … Individuals and Organizations
I'm starting to come around ... What would really be helpful is to see an example of where the type of inheritance that am so attached to and am trying to unlearn IS actually a "best practice" .... ie: the use cases where inheritance is actually "behavior-centric" and is a better choice than containment.
If I could understand that, then I would have more to go on in terms of what to look for in analyzing when Inheritance is the "best practice" and when it is better to go with containment.
Is this art ? engineering ?? religion ?????
Thanks,
Steve
Hi
In this case I'm not even suggesting you should contain Actor and Individual in Employee and Contact. Rather Employee should have all the"data" it needs. So basically this involves cutting and pasting all your properties from Actor and Individual into Employee and Contact. Any shared behavouir such as custom validation methods etc can be put into another object, like what Rocky did with the Assignment class in the project managment system described in the book. Thats just my opinion of how you should go anyway. There is no hard fast rule at the end of the day.. if it works it works kind of thing. In general I'd say you shouldn't find yourself inherting your own BO's. Though you may find your self creating inhertience structures with your none BOs, your behavouir class's etc. Then using these via client-supplier in yours BOs. Does this help?
George
I'm going to need more convincing before I consider implementing re-use via cutting and pasting, George .... The Actor Class is actually part of 3 or 4 other entities, and I have other Business Objects that share data and behavior ( CRUD / Data Portal ).
Maybe I don't understand the downside of placing references in Roots to Editable Child ... I got some inspiration from Rocky in this post:
http://forums.lhotka.net/forums/post/12714.aspx
You can have an editable root directly contain an editable child, that is fine. The property in the editable root that allows access to the child should be a read-only property, because you don't want the UI to change that reference, only gain access to the child object.
The idea of containment (or aggregation) is at the core of object-oriented design. Objects contain other objects all the time, this is not a bad thing. In fact, it is a way to express important relationships between objects.
In most cases this is not a form of tight coupling. The root object is aware of its child, but probably won't interact with it very much. The child object may be entirely unaware of its parent.
Again, a major objective of my posting here is to understand when it is ( if ever ) a "good practice" to create sub-classes for the types of entities that are modeled as sub-classes in a relational DB design
.. ie:
Person
Employee
Hourly Employee
Exempt Employee
More thoughts ???
Steve
I think one key element of understanding all this is the following:
Properties are not behavior. Reuse of properties (and thus fields) is not a priority.
Using inheritance to "reuse" properties and fields is counter-productive. It results in more complexity and coupling (fragility) costs than can be offset by any benefits of reuse.
This leads to the second big concept:
Reuse is not the goal. Maintainability is the goal.
Reuse can decrease maintainabiltiy if it results in coupling. Coupling is the big danger, and inheritance is (almost) always a form of tight coupling. Thus inheritance should generally be avoided. Which leads to the maxim:
Favor composition over inheritance.
But actual composition can have some serious downsides in terms of performance, especially when it comes to data access. At least if you view composition as the use of multiple object instances working in a coordinated manner.
However, if composition becomes combination - at least of properties/fields - then you avoid the performance issues. And now we're to the point where you would have separate objects for HourlyEmployee and ExemptEmployee, even though they share some properties/fields.
The key, imo, is that you don't want to replicate behavior (methods). Replicating properties/fields doesn't matter - they can be code-genned or created with snippets. There's little to no variation in a property - they are just stamped out like widgets.
But methods are unqiue. Most methods actually do something interesting (unlike properties), and so you only want to write and maintain a method exactly once. This leads to
Normalization of behavior.
The idea is that you normalize behaviors that are common across objects. To do this, at a design level you move that behavior into its own object. Related behaviors can go into the same object (a concept called cohesion).
Of course at the implementation level you may actually implement many of these behaviors as Shared/static methods and so not have real objects. But that's an implementation artifact and doesn't impact the design process.
In CSLA objects, most behavior is in the form of rule methods, and those are easily normalized (they are normally Shared/static to start with).
Other custom methods (like calculating a price, or a wage or something) are more interesting, but are typically also easily normalized.
In ProjectTracker I do this normalization into the Assignment "object". At a design level, this object contains behaviors common to ResourceAssignment and ProjectResource. At an implementation level it is a collection of Shared/static methods.
But the result is that all interesting business logic that would have been duplicated is now centralized, and the two original objects now collaborate with this Assignment object to do their work.
Thanx, RL ...
I think we're close to putting this to bed .... tho I must again say that the seeing the little trick of implementing inheritence in BO's by passing the command object to add parameters from a base class's InsertUpdate method using base.insert(cm) , then returning it back to the subclass to execute the command added a whole new level of excitement to my life as a developer.
Does that make me an Elvis or an Einstein ?? Or just a hot-dogger ??????
I agree whole heartedly with what you are saying, but one thing in particular needs clarification ....
"And now we're to the point where you would have separate objects for HourlyEmployee and ExemptEmployee, even though they share some properties/fields."
What about adopting the approach where we have HourlyEmployee and ExemptEmployee objects that contain PersonInfo and EmployeeInfo Objects ??
.... I read what you said about re-use ... but implementing this way allows:
Reuse, Maintainibility .... elegance ??? Too brittle ?????
Thanks again.
Steve
tsaltd:I agree whole heartedly with what you are saying, but one thing in particular needs clarification ....
"And now we're to the point where you would have separate objects for HourlyEmployee and ExemptEmployee, even though they share some properties/fields."
What about adopting the approach where we have HourlyEmployee and ExemptEmployee objects that contain PersonInfo and EmployeeInfo Objects ??
.... I read what you said about re-use ... but implementing this way allows:
- the HourlyEmployee to instantiate the PersonInfo and EmployeeInfo objects as EditableChildren ....
- The same PersonInfo editable-children and EmployeeInfo BO's are used in the ExemptEmployee
and
- PersonInfo could be contained/reused in Contacts
This can work. It is a use of both composition and containment.
However, you'll probably find that it is awkward at the UI level. Data binding prefers to have a single, flat object in most cases. Because you'll have a two-part "flat" object data binding will have a harder time working with this model. Or more accurately, you'll have a harder time convincing data binding to work with this model.
In other words, you've achieved some potential elegance at the business layer, but you've increased the complexity at the UI layer (where complexity is more expensive).
Also, you've got a potential data access issue. You may need to hit the database twice to load an object - once for the employee stuff, once for the person stuff.
While you could combine the data access into a single, merged, query, that would result in coupling again. Adding a field to PersonInfo would require alteration to objects and/or queries used to load several other objects - while directly illustrates how coupling creates fragility.
OK - I'm getting "Mort"-ified .....
I'm obviously holding on to my data-centric focus ... and the value of the elegance / reusability "normalization of 'un-interesting' behavior"
I guess I should just hold my nose and go ahead and maintain multiple versions of the same code.
However ...
I am thinking that even tho the BO design pattern that I don't want to give up on may have data access functions that get pretty funky .... the data binding issues could be "normalized" by using a wrapper ... something similar to the "facades" that are created for CSLA Web Service interfaces that would (?) and certainly could be a workaround for the databinding issue.
I don't want to beat this to death ... but there is a germ in this thread that makes me think in terms of an MVC pattern / a controller class that feeds a "flat" boundary object for data binding.
I certainly don't want to trade off the benefits of the CSLA data portal architecture to do this ...
Get the picture ?
Have there been discussions / Are there any examples of anything like this ???
The picture is getting much clearer .... very informative .. thanks.
Steve
“Combination” is basically copy-paste J
Or better, it is code-gen of properties for both objects. The idea is to create
a resulting object with the “shape” (properties) required by the
use case.
The “dumb” object idea is problematic because you
lose interactive data binding.
The relationship with Assignment is more collaboration than
association. In implementation terms there really is no Assignment – just
a bunch of shared methods. But at design time, ProjectResource and
ResourceAssignment are collaborating with (or using) Assignment.
Rocky
From: juddaman
[mailto:cslanet@lhotka.net]
Sent: Tuesday, September 04, 2007 2:27 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] inherit ? contain ?? behavior-centric ????? -
One more time ....
Rocky
In the post above you said:
"if composition becomes combination - at least of
properties/fields - then you avoid the performance issues."
Would you mind defining combination for me please? Are we talking about copying
and pasting or something fancier maybe, making "dumb" object with all
the properties that are shared in or something?
When you talk about collaborating with Assignment this is by association right?
Cheers, George.
What I can do (and just started) is create a list of links to forum posts that are particularly useful
Copyright (c) Marimer LLC