Using rules to change object's state

Using rules to change object's state

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


RichardETVS posted on Wednesday, February 21, 2007

Hi

 

I am new here. Excuse any mistake in English, as it is not my first language.

 

First, I want to say I am very impressed by Rockford Lhotka’s work; in my humble opinion the CSLA is both a good lesson in Dot Net technologies and in development best practices. And the book is, for what I read at now (to page 137) well written.

 

 

We’ll develop a distributed application treating documents. Some parts of the documents will be read with OCR tools, some others will by typed by human operators. Both operations will imply minimum business rules, because the speed of treatment will be critical.  In fact the application will, after all the OCR and typing steps, do automatics verifications on the collected data, and it is in this step that the business rules will be used.

 

The Framework seems to handle that easily, if I understand well. I can add the rules to the business object at the verification step, and maybe unsing a command object to do the job, right?

 

Let’s say it is ok. But the verification process will not prevent object to be stored in database, it must simply change the state of the object. Later, the application will use this object’s state to decide of the fate of the object. So it is not really “valid” result or even a rule severity “error” or “warning” that interests me. It is the ability to use the rules to change the object state. I suppose I’ll find answers to my preoccupation in the rest of the book and in the handbook, but any advice would be appreciated.

 

Thanks a lot!

 

Richard

RichardETVS replied on Friday, February 23, 2007

Hmm, welcome in this forum, Richard!

 

 

 

As far as I am in the book, it seems that the way to go is to overload the “Save()” method of BO. As we’ll have common objects for all the clients (like credit slip), but as the rules will be mostly by client, we can’t put the rule on the BO objects. I think I shall have an object to dynamically attach rules to BO. Again, any advice would be welcome.

 

 

Richard

ajj3085 replied on Friday, February 23, 2007

hey richard,

Since you're not validating, it doesn't seem like you would need validation rules at all.

That said, you may have methods that DO change the objects state in response to a property change.  In those cases, I would probably create a method to do the evaluation after you set the BO's field, but before the PropertyHasChanged call (in case you add rules in the future.. you'd probably want them run before any rules checking).

HTH
Andy

RichardETVS replied on Friday, February 23, 2007

Thanks for your answer, Andy !

 

In fact, we’ll use validation rules, but not in the usual meaning. It will not be edition / validation, but edition at one step, and later validation, on saved objects. So, the rules system of CSLA  seems useful, even if I have to adapt it.

 

Richard

ajj3085 replied on Friday, February 23, 2007

Later when you need validation, it sounds like a different use case, and thus wouldn't you have a different object?  I forgot to mention that in my reply.. that it sounds like you have two uses cases:  data entry, and entry validation, which probably lends itself better to two differnet objects handling each case.

Andy

RichardETVS replied on Friday, February 23, 2007

Let’s say it is a kind of workflow. Effectively, we could say there are two use cases, data entry and entry validation.

 

But the same objects follow all the steps of the workflow. Object A is at data entry step, and then it is at entry validation step. At this step, I think to attach rules to the object A and check them, changing the object’s state accordingly to the results of the rules checking. It would be the responsibility of a controller object, at the entry validation step, to attach rules and check the objects.

 

 

 

Richard

ajj3085 replied on Friday, February 23, 2007

RichardETVS:
But the same objects follow all the steps of the workflow. Object A is at data entry step, and then it is at entry validation step.


Two steps in the work flow would be two uses cases, and you'd probably want two objects.  Only after you design them as two objects would you compare to see if the behaviors are the same.  In the case you describe, that doesn't seem to be the case because in step one the object can be saved without any validation, and in step two certain rules must be meet.

RichardETVS:
At this step, I think to attach rules to the object A and check them, changing the object’s state accordingly to the results of the rules checking. It would be the responsibility of a controller object, at the entry validation step, to attach rules and check the objects.


'Attaching' rules based on some private state is a good indication you'd probably want two different objects.  It sounds like step one would have pretty much no rules, and in step two you'd attach a whole set of rules to prevent saving an invalid object.  Again, it sounds like you'd be better served with two objects, one for each use case.

Of course only you know the details of your use case, so you'll have to decide in the end based on the cases which is the better design.  The problem you may run into with one object is that if use case A changes it would impact your single object, and you may introduce bugs into your program when the user attempts to execute use case B.  With two objects, code which fulfils use case B has a less likely chance of failing because of changes to use case A's object.

RichardETVS replied on Friday, February 23, 2007

Again, thanks for your answers.

 

Not sure I understand what you mean. Let’s say I have a credit slip document; let’s call it object A. At step A, data entry, I’ll use only a minimal set of rules (to be sure there is no empty field, by example). At this step, an object that we could call DataEntryManager do the work on the documents object, like Object A. At the next step, Ill use another object, let’s call it EntryValidationManager, who will work with the same object A, the credit slip. The EntryValidationManager could attach the rules at object A and checks them. In a way, that is an application of the Strategy pattern, in the sense of the same object would change of behaviour at each step.

 

Do you say that the original paper document, the credit slip, should be represented twice, with one class for the data entry and with another for the entry validation? It would seem strange for me.

 

Richard

Justin replied on Friday, February 23, 2007

We do something similar in our application and have started using CSLA for our next version. Basically we have documents who have minimal rules to be met on initial data entry to save and even more rules that must be met before the document gets "approved" and some things that are simply warnings but must not be met.

We are adapting CSLA slightly where we have a base object that understands the approval workflow that all documents follow. Then we are looking at adding a"severity level" to the broken rule objects that the save and approval code can evaluate, so when you add a new rule you specify it severity if failed as to whether it can't be saved or approved or is simply a warning.

As far as custom rules per objects even defined by end users, well we are going to use inhereitance so there is a base document object and inherited documented object for each document type that contains that documents properties and business rules (and even layouts for rendering engines), and further down the road we are looking at users being able to write new document objects in either c# or vb and they can put the source into our app which will compile and dynamically load (perhaps with a gui designer that emits code like winforms). Our view is why make a custom limited business rule language up when the compilers and dom models for much more complete and robust languages already exist in the runtime.

ajj3085 replied on Friday, February 23, 2007

Richard,

A lot of it depends on  your use case.  You bring up the Strategy pattern, which is a perfectly valid pattern.  I would only say that as long as Object A is deciding to use EntryValidationManager or DataEntryManager to check values and there are no other behaviors that must be implemented then you are probably fine. 

The key though is that object A is in charge of that decision; if you have the UI decide which to use, or if either of the managers is attempting to alter the state of object A (including if rules are broken or not, or even which rules are run) then you are going to run into problems because putting business logic in your UI or you're breaking encapsulation. 

Also, if there are other behaviors besides rule checking then you would not want to use the proposed design.  Lets say you have a Finalize use case, which can only be done after the credit slip is fully validated (step two in the workflow).  In that case you would certainly want two different classes, because you should never have a Finalize method on the data entry class.

HTH
Andy

Justin replied on Friday, February 23, 2007

Andy,

I would agree object should be in charge in fact I would put the DataEntryManager and EntryValidationManager code in object A and perhaps filter the broken rules based on it being viewed in a data entry UI or manager UI or perhaps the method that actually sends the document to the manager changes the workflow state so that now manager rules are enforced.

I am not sure why you would want a separate class for a finalize vs finalize throwing an exception if it where somehow called before the proper time? Seems like that would create excessive overhead in object schema change, especially if you needed to make a new version of a object for each step in a workflow just beacuse that step has different methods that can be called when in that step.

Justin

ajj3085 replied on Friday, February 23, 2007

Justin:
I am not sure why you would want a separate class for a finalize vs finalize throwing an exception if it where somehow called before the proper time? Seems like that would create excessive overhead in object schema change, especially if you needed to make a new version of a object for each step in a workflow just beacuse that step has different methods that can be called when in that step.


Well it depends on what Finalize does exactly. and what other behaviors the class implements.  If changing the Finalize method because use case two changes breaks the behavior expected of the object when used in use case one, you have a problem.  That's the case I was thinking of when I posted that part of my reply.

malloc1024 replied on Friday, February 23, 2007

The strategy pattern would be a good option here; however, if you want to have the Document object control its own strategy, you might want to consider using that state pattern instead.

In addition to this, you could create a Document and DocumentEntry class that would implement an interface that would contain the properties that would be exposed to the presentation layer.  The Document object would be the full-blown business object while the DocumentEntry object would be a data container that would contain only the necessary behavior for data entry. The user’s information would be entered into the DocumentEntry object and then sent to the DataEntryManager.  When the DataEntryManager is done with the DocumentEntry object, it would send it to the Document object to check the rules and save it.  The Document object would be able to expose the DocumentEntry information because they would share the same interface. This would allow you to have two separate classes that fulfill two separate use-cases.  Further, the DocumentEntry class solves the problem of exposing invalid methods to the presentation layer.  Although there is nothing wrong with throwing exceptions for invalid methods, it is usually cleaner to not expose them.  This is just another option and the strategy or state should work fine without the extra DocumentEntry class.

Justin replied on Saturday, February 24, 2007

I agree that having different classes for different use cases makes it pretty clear to implementers what methods can and cannot be called, I would argue exceptions thrown from those methods when called at the wrong time might be even more clear since the exception message could describe the reason vs simply no method, and either way an implementer should have suffcient documentation as to the various states and methods of a object.

The IMO huge downside to the interface with multiple classes for each state is schema change and maintenance, you are now spreading your BL and schema across multiple classes that must all be maintained in sync should changes need to be made. In my experience the more source code that represents the same entity the more work in development and testing changes to those entities goes up expoentially.

RichardETVS replied on Monday, February 26, 2007

Well, a lot of interesting answers, I thank you all very much. I shall take time to think about each suggestion, as time is needed for such considerations. Malloc, you’re right, State Pattern is more adapted this situation than Strategy.

 

I’ll keep for now that using the CLSA rules system can be used to alter state of the business object. I have to think about how, when, and if it I the best solution in a given context (or Use Case), but basically it is possible.

 

I shall post a more precise model when I’ll have it. Again, thanks a lot for the answers :) .

ajj3085 replied on Monday, February 26, 2007

Justin:
I would argue exceptions thrown from those methods when called at the wrong time might be even more clear since the exception message could describe the reason vs simply no method, and either way an implementer should have suffcient documentation as to the various states and methods of a object.


I have to disagree here.  You see a method, and you assume you can call it.  If there's no such method, you obviously are using the wrong class to perform the task you want.  Ideally yes you should have sufficent documentation, but that's not always the case. 

Also consider what happens when many people have changed the class; do they always remember to update the exception message?  Probably not.

Justin:
In my experience the more source code that represents the same entity the more work in development and testing changes to those entities goes up expoentially.


That's the thing, its not the same entity.  One entity is performing rule checking and has the code to implement use case one.  The other is a different entity because its rules and purpose is different; namely to fulfill  use case two.  If there is overlap, this should be contained in another class (probably internal to the assembly) whose purpose is to provide the needed functionality. 

All this is theoritical though, since the 'correct' design depends on the use cases.  There are certainly many cases where the 'throw an exception' is correct, I'm not saying that should never be used or even that it should be used sparingly.  To me though, each stage in a work flow sounds like a seperate use case.

RockfordLhotka replied on Monday, February 26, 2007

I know this is semantics, but the use of the word "entity" in this context is dangerous. "Entity" is a term that is closely tied to data in most people's minds, and so using that term when discussing behavioral OO design is dangerous because business objects should not be closely tied to data. Business objects are consumers of data, but they aren't defined by data.

There are entity objects. Even they are behavioral: their responsibility is to contain data, and their behaviors are to get/set values. These are also known as data transfer objects, though there is, I suppose, a subtle difference between the two - though it is a difference of intent, not of implementation.

This is why I think behavioral or responsibility-driven design is so important. It encompasses all the data-driven scenarios with entity objects and DTOs, but is far more expansive because it also covers true business objects, process objects and so forth. Things that pure data-centric OO design just can't express very well.

Justin replied on Monday, February 26, 2007

RockfordLhotka:

I know this is semantics, but the use of the word "entity" in this context is dangerous. "Entity" is a term that is closely tied to data in most people's minds, and so using that term when discussing behavioral OO design is dangerous because business objects should not be closely tied to data. Business objects are consumers of data, but they aren't defined by data.

There are entity objects. Even they are behavioral: their responsibility is to contain data, and their behaviors are to get/set values. These are also known as data transfer objects, though there is, I suppose, a subtle difference between the two - though it is a difference of intent, not of implementation.

This is why I think behavioral or responsibility-driven design is so important. It encompasses all the data-driven scenarios with entity objects and DTOs, but is far more expansive because it also covers true business objects, process objects and so forth. Things that pure data-centric OO design just can't express very well.

I agree in many ways with your view on this and as we are utilizing CSLA you can tell I think it has merit. The flip side is being pragmatic and not forcing a philosphy on to something that may work better in a data centric approach. I think you have protrayed this in the opposite sense that you didn't want people to force an pure-data centric OO approach when it really doesnt work so well.

In my experiance it is a big trade off to maintain multiple classes that all represent the same data entity  (code generators can help). My experiance with basically a document managment system that I was trying to share my opinion on was that its very impractical to maintain a entity who design may change over time that has many dozens of properties and many steps (if not user definable steps) in workflow, by creating one class for each step. I think in this case a data centric approach is better, but again just an opinion.

Justin

ajj3085 replied on Monday, February 26, 2007

Good point..

Everywhere in my post, I was using 'entity' to mean 'business object.'  Probably shouldn't have done that, but I was trying to keep the terms the same from the post to which I replied.   My bad.

Justin replied on Monday, February 26, 2007

ajj3085:
I have to disagree here.  You see a method, and you assume you can call it.  If there's no such method, you obviously are using the wrong class to perform the task you want.  Ideally yes you should have sufficent documentation, but that's not always the case. 

Also consider what happens when many people have changed the class; do they always remember to update the exception message?  Probably not.

I don't assume anything when using someone elses object and the same entity represented across multiple classes with different methods would have no more inherit meaning as to the order in which they can be called.

I would argue to that its easier to remeber to update an exception in one class than keep many classes updated should the one entity change.

So an entity that has perhaps many tasks that could be performed at different states should in fact be many different classes all having the same properties but very few if only one method that executes that task? Sounds very similar to stateless design and at that point why have classes at all, just have functions that take parameters represting the current state of the entity and act on it.

ajj3085:

That's the thing, its not the same entity.  One entity is performing rule checking and has the code to implement use case one.  The other is a different entity because its rules and purpose is different; namely to fulfill  use case two.  If there is overlap, this should be contained in another class (probably internal to the assembly) whose purpose is to provide the needed functionality. 

All this is theoritical though, since the 'correct' design depends on the use cases.  There are certainly many cases where the 'throw an exception' is correct, I'm not saying that should never be used or even that it should be used sparingly.  To me though, each stage in a work flow sounds like a seperate use case.

Again I disagree it is the same entity in the sense that its properties uniquely identitfy the same real world entity, it simply is at a different point in its workflow.

In the design with one class per stage in workflow, what prevents me from loading the entities data in the wrong class? Would it throw an exception as it loads form the data store and checks some persisted state value? If so all you have done is increase the amount of classes with the same properties (more schema change maintenence) and move the exception to the data load instead of the time you try and act on that data.

Justin

ajj3085 replied on Monday, February 26, 2007

To start, after reading Rocky's comments, I'm going to use Business object, and not entity.

Justin:
I don't assume anything when using someone elses object and the same entity represented across multiple classes with different methods would have no more inherit meaning as to the order in which they can be called.


Well that's fine, but you can't argue that an object which doesn't have the method you need will force you to look for the appropriate object. 

Its not the same business object.  If it were the same, it would be identical in all cases and thus you wouldn't need more than one.  But an class with different methods cannot be the same business class, by definition.

Justin:
I would argue to that its easier to remeber to update an exception in one class than keep many classes updated should the one entity change.

You wouldn't be updating many business objects, you'd only update the one affected by a change in the use case.  The other business objects shouldn't need to be updated, since their use cases have not changed.

Justin:
So an entity that has perhaps many tasks that could be performed at different states should in fact be many different classes all having the same properties but very few if only one method that executes that task? Sounds very similar to stateless design and at that point why have classes at all, just have functions that take parameters represting the current state of the entity and act on it.

No, the business objects would only have the properties it needs to peform the use case it was built to handle.  There's no reason to keep properties which have nothing to do with the current use case.

Justing:
Again I disagree it is the same entity in the sense that its properties uniquely identitfy the same real world entity, it simply is at a different point in its workflow.

That's data centric design, and we are talking about behavior centric design.  I'm not going to rehash the problems with data centric design, Rocky and others have posted extensively about the problems with such a design.  Search the forum and Rocky's blogs and books.

Justing:
In the design with one class per stage in workflow, what prevents me from loading the entities data in the wrong class? Would it throw an exception as it loads form the data store and checks some persisted state value? If so all you have done is increase the amount of classes with the same properties (more shcema change maitenence) and move the exception to the data load instead of the time you try and act on that data.

Yes, you'd likely get an exception if you attempt to load a workflow item at an inappropriate stage.  And isn't it better to get an exception before any time is wasted constructing and doing some work on the object, only to find out its in an invalid state when you call the method to move to the next step in the workflow?

It doesn't really matter if there are many classes with similar or the same properties.  Property code is the easiest part of the class to code... so easy that it is ideally generated by a tool automatically.  There's no value in re-using property code.  The value is in the methods (behaviors) that the classes encapuslate.

Again, I won't rehash arguments already made; search the forum and Rocky's blog as this has been discussed many times.

Justin replied on Tuesday, February 27, 2007

ajj3085:
To start, after reading Rocky's comments, I'm going to use Business object, and not entity.

Ok with me, I was using entity to refer to the real thing and class to refer to the "business object"

ajj3085:

Well that's fine, but you can't argue that an object which doesn't have the method you need will force you to look for the appropriate object. 

Either way the object will not allow an incosistent state should a implementer try. I suppose you could argue runtime vs complie time as far as when it would be caught. Although you could still try and load it in the wrong state so you still have exceptions to deal with.

ajj3085:

Its not the same business object.  If it were the same, it would be identical in all cases and thus you wouldn't need more than one.  But an class with different methods cannot be the same business class, by definition.

Again if this is the case why do you need objects at all just have functions that take parameters since in your view an object really shouldnt be stateful or transistion states, only represent one state. You really dont need all this OO overhead if your just going to load a bunch of values up and perform one method on them.

ajj3085:
You wouldn't be updating many business objects, you'd only update the one affected by a change in the use case.  The other business objects shouldn't need to be updated, since their use cases have not changed.

So if I have a document entity that various BL related to certain properties values changing all that would not need to be reproduced through every "business object" that represents that document at a different stage in its workflow? Ah no I guess I could put those in some core "data centric" object that all the "business objects" use except how do I bubble a "data centric" broken rule up to the  "business objects" broken rule so the consumer knows? What did that buy me again besides more schema change overhead?

ajj3085:
No, the business objects would only have the properties it needs to peform the use case it was built to handle.  There's no reason to keep properties which have nothing to do with the current use case.

If a entity has many uses cases in which they all need most if not all the same properties this is still practical or is it just sticking to a pattern blindly?

ajj3085:

That's data centric design, and we are talking about behavior centric design.  I'm not going to rehash the problems with data centric design, Rocky and others have posted extensively about the problems with such a design.  Search the forum and Rocky's blogs and books.

I know what it is and understand the issues, but just as Rocky has pushed poeple to let go of blindly sticking to a complete data centric design I would say to stick to behavior centric without compromise is just as bad. Good thing is CSLA doesn't seem to mind either way.

ajj3085:
Yes, you'd likely get an exception if you attempt to load a workflow item at an inappropriate stage.  And isn't it better to get an exception before any time is wasted constructing and doing some work on the object, only to find out its in an invalid state when you call the method to move to the next step in the workflow?

I don't know seems kind of odd to tie the retrieval from persisent storage to enforcement of an invailid state. Really wasting time seems thin, at that point you already wasted time coding the consumer incorrectly, either way is a runtime exception that should not occur in a consumer using the workflow properly.

ajj3085:
It doesn't really matter if there are many classes with similar or the same properties.  Property code is the easiest part of the class to code... so easy that it is ideally generated by a tool automatically.  There's no value in re-using property code.  The value is in the methods (behaviors) that the classes encapuslate.

What are properties again? Oh yeah they are methods on an object, so how exactly are they any less important than another method. Do you not have any BL embedded in a setter? I would say that thats quite a blanket statement to make that properties have no reuse value, I mean isnt that kinda one of the premises of OO vs a purely procedural langauge?

ajj3085:

Again, I won't rehash arguments already made; search the forum and Rocky's blog as this has been discussed many times.

No need to rehash with me, I know many projects that have failed do to pushing the data centric design without waver. That does not mean it doesn't have it uses and I thought it might have a fit from my experiance in document managment that the OP was referring to.

malloc1024 replied on Tuesday, February 27, 2007

Objects should be able to change their state and behavior dynamically.  This can be done with the strategy, state and other patterns.  However, when you change the behavior or state of an object, it usually means that you are using the class in a different use-case.  It seems to me that a use-case driven design suggests creating a new class for each use-case while a more pure OOP design suggests dynamically switching the behavior or state on the class.  It also seems that a use-case driven design promotes less re-use.  This is the part where I am somewhat confused.  Is there such thing as a use-case driven design and does it differ from a more pure OOP design?  How much of a role should use-cases really have in your design?  I have heard conflicting opinions on this.  I have read on this forum that you should design you classes based on use-case; however, I have read from other sites that use-cases should not influence your design.  I think others have been confused by this and it is the reason why there is disagreement in this thread. 

 

I have provided a link that includes some author’s opinions on use-cases and OOP form ootips.org.

 

http://ootips.org/use-cases-critique.html


RichardETVS replied on Wednesday, February 28, 2007

Food for thoughts, in all those answers. I think I'll have a few more questions :

Jimbo replied on Wednesday, February 28, 2007

Its amazing how a simple question can spark off such depth of esoteric discussion. The newbe or practical developer can be overwhelmed in the search for a straight answer.

I'm also very interested in how we can better approach state changes in BO's  and in a current development we have this same dilema between the use of a universal BO and specific BOs for each use case (state) in the flow.

The biggest hurdle regarding using distinct objects by case (state)  is often simply because of developer inertia fear and uncertainty, and also (to use a vb shortcut) the constant difficulty of clearly differentiating the balance between data centric, structured and behavioural thinking - Is the UI, db, appserver, or the class(BO)  in charge etc.

There is an application/database development human factor that constantly comes in. "Why do we need to have a different BO when the current one has the same basic properties?" is a common question. "Why can't this BO be adaptable?".  Sometimes this complaint is quite justified as we see in our QA, the evidence of the age-old  copy - paste - hack-what-you-think-you-need process going on to achieve the production goals, rather than the drive for appropriate design for re-use, collaboration, inheritance and interface. This leads to maintenace nightmares - which developers can always relate to.

If the architects are so uncertain then the workers make their own decicisions for better or worse.

.









RichardETVS replied on Wednesday, February 28, 2007

Let’s say I see the main BOs, the ones who will follow the workflow, as kind of agents. They have a goal (to follow the workflow). They must, at each step of the workflow, cooperate with some other specialized BO. They have no real intelligence, but they “borrow” they intelligence and behaviour at each step (with patterns like Strategy or State). Those intelligence and behaviour will vary with the configuration (there are rules at per client / per BO basis).

 

The BO live in a kind of loop, in the loop the general manger asks to each object what it wants to do. The BO, with a determined combination of states / configuration, decides to which step it has to go. It goes to this step, and at this step, the specialized object for the step helps the main BO. It can be by providing the right rules for the BO and asking it to check them, varying the BO state. It could be by providing some user input for the BO.

Jimbo replied on Wednesday, February 28, 2007

Richard,
You are pulling us back to the point - great.  And I see the same need to have a BO that lives a life or grows. Some of our peers have already said that this is the implementation of the so-called State pattern. I seem to agree - sort of - but  we need a concrete example, right?

ajj3085 replied on Wednesday, February 28, 2007

Richard,

It sounds like you're on the right track.  Behavior based design does seem un-nature or more complex at first.  Its this way because we are taught to view inheritience and reuse based on data.  I know my degree program did this as well.

The final answer you come to must depend on your use cases.  Do all clients have the same series of steps, but with varying rules to move between each step?  If so, you may end up with a design where each step (and each step is likely a seperate use case) is represented by a BO.  The details of the rules would need to be loaded based on what client is operating.  You'd likely then use state or strategy pattern with in the BO, so that the details of the rules can vary by client.  As long as the BO is in charge of which rule object it should apply (based on the client). 

Justin and I can debate all we want... but in the end the solution to your particular problem lies in the use cases you must implement.  Only they can really guide you as to how to build your system; after all, if you don't implement the use cases, you haven't built the system your customers want.

RockfordLhotka replied on Wednesday, February 28, 2007

Jimbo:
Its amazing how a simple question can spark off such depth of esoteric discussion. The newbe or practical developer can be overwhelmed in the search for a straight answer.

That is so very true... But I'm not going to help in this post Wink [;)]

Jimbo:

There is an application/database development human factor that constantly comes in. "Why do we need to have a different BO when the current one has the same basic properties?" is a common question. "Why can't this BO be adaptable?".  Sometimes this complaint is quite justified as we see in our QA, the evidence of the age-old  copy - paste - hack-what-you-think-you-need process going on to achieve the production goals, rather than the drive for appropriate design for re-use, collaboration, inheritance and interface. This leads to maintenace nightmares - which developers can always relate to.

The biggest issue here, is that reuse is a form of coupling. And coupling is bad. So reuse is bad.

But reuse is good. Reuse is desirable. Reuse has, for many, become an overriding goal.

So the real challenge is reconciling these two opposing facts. Reuse is desirable. Yet reuse==coupling, and coupling is very much not desirable.

I think the answer is to recognize that reuse is not a goal. It is a coincidental and beneficial side-effect of what should be the real goal: increasing the maintainability of code.

To increase the maintainability of code, your code must be consistently structured and behavior must be normalized. But in normalizing behavior, you must not introduce complexity. If you introduce complexity, then you lose maintainability.

Look at it this way. If you have behavior X, that is used for the purpose of P' that is good.

If X, unchanged, can be used by P'' that's very good, because you introduce no complexity, and you get reuse. You do, unfortunately, incur some coupling, because there's a mutual dependency: P'->X and P''->X, therefore P'<-X->P'' and P'<->P''.

But in my view, as long as X is unchanged this level of coupling is acceptible to gain the reuse.

However, if X had to be altered for use by P'' then we have a problem. By definition, changing X to suit P'' means that X is no longer exactly what was expected by P', and you run the risk of breaking P'. The inevitable result is that the complexity of X increases, because it needs to provide exactly what is required by both P' and P'', though they are different.

So in this scenario we have the worst of all worlds. P' and P'' are coupled through X, and X now has complexity that it shouldn't have. So we lose clarity, simplicity and decoupling in the pursuit of reuse.

This is what I mean when I say that reuse is not a goal. If reuse is a goal you end up in this mess. But if reuse is a beneficial side-effect, and maintainabilty is the goal, then you are better able to make an intelligent, considered, decision on the trade-offs between clarity, reuse and coupling.

malloc1024 replied on Wednesday, February 28, 2007

If changing the behavior of an object at runtime is not desirable because it increases complexity and coupling, does this mean that the strategy and state patterns are unnecessary because they allow you to change behavior at runtime?  Is it ever desirable to have the ability to change the behavior of an object at runtime rather than creating a new object to fit a use-case?  Thanks.

ajj3085 replied on Wednesday, February 28, 2007

Justin:
Either way the object will not allow an incosistent state should a implementer try. I suppose you could argue runtime vs complie time as far as when it would be caught. Although you could still try and load it in the wrong state so you still have exceptions to deal with.


Again a lot of what happens depends on the use case.  Assuming you can have multiple items ready for the next stage of the workflow, you'd probably load an editable object based on an item from a readonly collection of items, in which case you wouldn't necessary need to worry about exceptions.  (The bo would still throw one, but the UI may not need to worry.  Again, it depends on the workflow and how many people are in the mix working on work items).

Justin:
Again if this is the case why do you need objects at all just have functions that take parameters since in your view an object really shouldnt be stateful or transistion states, only represent one state. You really dont need all this OO overhead if your just going to load a bunch of values up and perform one method on them.

In a very simple, non-interactive workflow, you might be right you don't need all the overhead of OO. You may be better off with another method.  But if the item needs to be modified, such as additional data added, existing data changed, and certain rules must be met (such as some new data MUST be entered, you can't choose value X if value A is chosen) then a business object makes a lot of sense.  The problem is that you can take your argument and use it to rule out OO in every case.  But we're not just using OO to make things simple; we're using it to help with maintainability.  An OO based application (if done right) is usually easier to maintain than a procedural application (also done right).

Justin:
So if I have a document entity that various BL related to certain properties values changing all that would not need to be reproduced through every "business object" that represents that document at a different stage in its workflow?

Sorry, I'm having trouble understanding the question..

Justin:
Ah no I guess I could put those in some core "data centric" object that all the "business objects" use except how do I bubble a "data centric" broken rule up to the  "business objects" broken rule so the consumer knows? What did that buy me again besides more schema change overhead?

If the change in schema really does affect every use case, yes you're right you'd have some work to do.  It depends on the specifics though.  The rules could be kept in one spot and you could probably designate an object that defines rules for multiple types, not just a  single type.  Proper refactoring  would likely save a lot of headaches.

Justin:
If a entity has many uses cases in which they all need most if not all the same properties this is still practical or is it just sticking to a pattern blindly?

Using code gen and other techniques make it practical.  OO isn't about code reuse, its about building a maintainable application.  Your one BO that handles ALL stages of the workflow is undoutably large, complex and its very likely that making a change to it will break its other intended uses.  Some times you need to do more work upfront to do less work later.

ajj3085:
I know what it is and understand the issues, but just as Rocky has pushed poeple to let go of blindly sticking to a complete data centric design I would say to stick to behavior centric without compromise is just as bad. Good thing is CSLA doesn't seem to mind either way.

I'm not sticking blindly to a principal; I'm sticking to it because it makes sense, and I know what happens when you go the other route.  Workflow rules are business rules, and putting that logic in the data layer or designing  your objects around data lead to harder to maintain and harder to change systems. 

Before Clsa I did design my objects around the database and tried to make one object do many things simply because it shared the same properties.  Our BOs were simply generated from a specific table, and then we added methods.  And you know what, the system WAS harder to maintain and  harder to change.  Since I've started doing things in a behavior based way, I've found it much easier to build and maintain my applications.  I'm advocating the behavior based way because I've found the data based way leads to a mess, each and every time.  

Justin:
I don't know seems kind of odd to tie the retrieval from persisent storage to enforcement of an invailid state. Really wasting time seems thin, at that point you already wasted time coding the consumer incorrectly, either way is a runtime exception that should not occur in a consumer using the workflow properly.

So its better to construct an object which you can do nothing with but throw away?  As I said before, you usually don't get into this scenario because you usually already know you can load the editable object.

ajj3085:
What are properties again? Oh yeah they are methods on an object, so how exactly are they any less important than another method. Do you not have any BL embedded in a setter? I would say that thats quite a blanket statement to make that properties have no reuse value, I mean isnt that kinda one of the premises of OO vs a purely procedural langauge?

Yes, techinically they are methods.  Do I have logic in my properties?  Nothing that's not consistently easy to regenerate via code gen.  The actual business rules themselves are in other methods that get called via the PropertyHasChanged call.  99% of my property definitions are identical to each other in form.  That's what I mean when I say they have no value.  The premise of OO is that the object is the only one that can change its state; in procedural languages, the program keeps ALL state and its up to the program to maintain that state, and almost anything called can modify that state.

ajj3085:
No need to rehash with me, I know many projects that have failed do to pushing the data centric design without waver. That does not mean it doesn't have it uses and I thought it might have a fit from my experiance in document managment that the OP was referring to.

Would I push behavior based design on say a data import tool?  I wouldn't and databased design there is just fine.  But the fact here is that we are talking about a workflow.  Workflows are defined by business processes, and those are the kinds of things that should be put into a business layer, and my experience tells me the best way to build a business layer is behavior (ie, use case) based design. 

RichardETVS replied on Wednesday, February 28, 2007

Strangely enough, it seems to me that this “use case” approach is tied to non object database. We start with some objects (let’s say type A), we save the data of objects in the database, and then, for another use case, we build new different objects from the data in the database, let’s say type B.

 

But if we use a pure oriented object database, it seems to me that becomes complex. There are no rows, tables, datareaders. We save just type A objects, and from them we must construct Type B. It seems complex or not natural, or there is something I did not understand.

RockfordLhotka replied on Wednesday, February 28, 2007

Object databases still need to store their data in a relational manner. This typically means that the “objects” in the database must match what would have been tables in a traditional RDBMS. If that’s true, then you STILL need to map the data from those “relational objects” into your actual business objects.

 

Of course I haven’t looked at all the ODBMS systems out there. And it may be that some of them do store fields in a normalized manner, and allow those fields to appear in numerous object representations. But that’s not the case for the ones I’ve looked at thus far.

 

For example, your Customer object has a CustomerName field. And your Order object has a CustomerName field. They should probably be the same field (updating one auto-updates the other). But if they really are fields in two different objects, then they aren’t linked, and you have a problem. However, if the ODBMS does allow you to “construct” objects that contain arbitrary fields – basically elevating fields to be first-class citizens – then you can solve this by associating that same field with both Customer and Order.

 

But I haven’t seen that. Yet that is the sort of thing you MUST DO if you are creating responsibility-driven business objects. That’s the real job of ORM (though most ORM tools don’t do this well either…)

 

Rocky

 

 

From: RichardETVS [mailto:cslanet@lhotka.net]
Sent: Wednesday, February 28, 2007 7:54 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Using rules to change object's state

 

Strangely enough, it seems to me that this “use case” approach is tied to non object database. We start with some objects (let’s say type A), we save the data of objects in the database, and then, for another use case, we build new different objects from the data in the database, let’s say type B.

 

But if we use a pure oriented object database, it seems to me that becomes complex. There are no rows, tables, datareaders. We save just type A objects, and from them we must construct Type B. It seems complex or not natural, or there is something I did not understand.



RichardETVS replied on Wednesday, February 28, 2007

RockfordLhotka:

Object databases still need to store their data in a relational manner. This typically means that the “objects” in the database must match what would have been tables in a traditional RDBMS.  

 

Well, that's not the case of db4o (by the way, it  is free for internal dev, www.db4o.com ).You just save objects.

RockfordLhotka replied on Wednesday, February 28, 2007

I have actually worked with db4o and use it as an example of what I’m talking about.

 

If you create a Customer object with CustomerName, and you create an Order object with CustomerName you’ll have the field twice in your db. Go change the customer name in your customer and watch as it DOESN’T change on the orders for that customer. Whoops...

 

Rocky

 

 

From: RichardETVS [mailto:cslanet@lhotka.net]
Sent: Wednesday, February 28, 2007 9:57 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Using rules to change object's state

 

RockfordLhotka:

Object databases still need to store their data in a relational manner. This typically means that the “objects” in the database must match what would have been tables in a traditional RDBMS.  

 

Well, that's not the case of db4o (by the way, it  is free for internal dev, www.db4o.com ).You just save objects.



RichardETVS replied on Wednesday, February 28, 2007

But why it should change? Maybe I am a little stupid here, but if I make two classes with each one a same name property, it does not mean that they have the same data. That the property name is the same is coincidence.

If it is important that properties share the same information, I would rather have them containing the same object. And for an Order object, I would have an association with the Customer object. Well, that is so plain, and I know you're really more expert than me, that I suppose I miss your point, here.

ajj3085 replied on Wednesday, February 28, 2007

Richard,

Presumably because that's what the use case dictates should happen.  I wouldn't think you'd want to change the company name on the applications order form and NOT change the master record.  If you didn't update the master record, the next time you place an order, it would be under the old company name.  It would be unusual to let the company name be different for just one order.

That's not to say that a use case would never be created that did allow just that scenario, just that such a use case would be a rare occurance.

Justin replied on Wednesday, February 28, 2007

ajj3085:
Richard,

Presumably because that's what the use case dictates should happen.  I wouldn't think you'd want to change the company name on the applications order form and NOT change the master record.  If you didn't update the master record, the next time you place an order, it would be under the old company name.  It would be unusual to let the company name be different for just one order.

That's not to say that a use case would never be created that did allow just that scenario, just that such a use case would be a rare occurance.

Thats an instance issue not a class issue, if the instance of the customer object data should remain static on the order then fine that instance isnt modified, there would be however a master customer instance that contains the most current customer data for new orders.

Of course this gets into temporal versioning where most developers opt out and take the simpler approach of de normalizing thier data which can work fine in simplier systems like this example, but can become a big problem in a large system where say person data is now denormalized and replicated many times.

Justin

 

RockfordLhotka replied on Wednesday, February 28, 2007

This is where, with real OO applications, people get into trouble.

 

Are you really proposing that, to get one field of data on Order, you are going to load the entire Customer object?

 

I’ve been down that road, early in my exploration of OO. It sounds so sexy. Total reuse. One object with one set of data. One object to rule them all … and in the darkness bind them. (sorry, I’m a hopeless LoTR geek…)

 

But in reality it is bunk. It simply doesn’t work for anything beyond a handful of users, if that. The performance and scalability ramifications are non-trivial, especially in any sort of distributed environment.

 

You can get away with a lot if the database is on the user’s workstation and so, by definition, there’s one user. But as soon as you start trying to load entire Customer objects to get one field of data for dozens or hundreds of users, and that data must travel even from the db to the app server, you are done for.

 

Rocky

 

 

 

From: RichardETVS [mailto:cslanet@lhotka.net]
Sent: Wednesday, February 28, 2007 1:06 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: Using rules to change object's state

 

But why it should change? Maybe I am a little stupid here, but if I make two classes with each one a same name property, it does not mean that they have the same data. That the property name is the same is coincidence.

If it is important that properties share the same information, I would rather have them containing the same object. And for an Order object, I would have an association with the Customer object. Well, that is so plain, and I know you're really more expert than me, that I suppose I miss your point, here.



Justin replied on Wednesday, February 28, 2007

I agree that it may be impracticle to load all the data for an entity and shouldn't be if it's not needed, but isn't that a physical implementation issue and not a logical design issue?

What if the OO runtime we used was orthogonally persisent where you never had to "save" objects to persistent storage instead the runtime handled that and conversely handled demand loading of data as it was accessed would you now change your logical design because the physical platform issues to not impede it?

Now of course we don't have a runtime like that in widespread use (see lisp machines) so we must make compromises in a class design causing physical architecture to creep up into our business objects, but this can be mitigated to some degree.

For instance in our CSLA project we implement some demand loading of properties eleminating the need for XxxInfo classes, instead the main class, say Customer as in this example would only have minimal data loaded (such as ID and Name) in the instance referenced in the Order objects Customer property when the Order is fetched. We have base properties that allow the consumer to know if the Customer is fully loaded and attributes that the designer can specific what loads in minimally. For us this works great since we reuse some entities many times over, and the UI for handling them is very consistent and was well worth the extra effort to add to the base framework, but would not work for everyone I am sure. Oh and yes this scales very well for us.

Perhaps one day we all won't be so worried about how to save and load data from disk and worry more about how to solve business problems directly without compromise.

RockfordLhotka:

This is where, with real OO applications, people get into trouble.

 

Are you really proposing that, to get one field of data on Order, you are going to load the entire Customer object?

 

I’ve been down that road, early in my exploration of OO. It sounds so sexy. Total reuse. One object with one set of data. One object to rule them all … and in the darkness bind them. (sorry, I’m a hopeless LoTR geek…)

 

But in reality it is bunk. It simply doesn’t work for anything beyond a handful of users, if that. The performance and scalability ramifications are non-trivial, especially in any sort of distributed environment.

 

You can get away with a lot if the database is on the user’s workstation and so, by definition, there’s one user. But as soon as you start trying to load entire Customer objects to get one field of data for dozens or hundreds of users, and that data must travel even from the db to the app server, you are done for.

 

Rocky

  

Justin replied on Wednesday, February 28, 2007

RockfordLhotka:

I have actually worked with db4o and use it as an example of what I’m talking about.

 

If you create a Customer object with CustomerName, and you create an Order object with CustomerName you’ll have the field twice in your db. Go change the customer name in your customer and watch as it DOESN’T change on the orders for that customer. Whoops...

 

Rocky

Maybe you where trying to simplify but true OODBMS don't store in relational form at all (columns and tuples), they do however promote normalization which I think most everyone agrees is a good thing, although I am getting the feeling maybe not so here, which seems odd.

Your example also seems odd (again maybe you where trying to simplify), but why would you have a CustomerName string property and not a Customer property with a Customer class? That seems like classic denormaliztion and generally that would be a very bad thing. How do I know it's the right customer "John Smith" or the other "John Smith"?

There are some OODBMS that support composition of new objects from existing object through a query language to say pull just CustomerName out of a full customer object giving you a new simpler object. Most avoid this and instead would perfer you to create these "view" objects in your OO language that wrap the full object, thereby exposing just the members you want while not replicating the same data over and over again. Just classic normalization using objects with object references instead of table with foriegn keys.

Justin

RockfordLhotka replied on Wednesday, February 28, 2007

Please note, I am not saying that the ODBMS stores the data relationally.

 

I am saying YOU must store the data relationally. The concepts of data normalization existed long before RDBMS showed up on the scene. I was doing normalization of data using ISAM files and hierarchical databases long before Oracle was a viable database engine.

 

Just because you store “objects” doesn’t mean you get to mystically ignore the very nature of your data.

 

If you have a single field of data that is shared across multiple “objects” then you are in trouble. And the fact is that most applications have that exact scenario over and over again. That is NOT a relational database issue, that’s a simple data design issue.

 

Rocky

 

From: Justin [mailto:cslanet@lhotka.net]
Sent: Wednesday, February 28, 2007 1:09 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: Using rules to change object's state

 

RockfordLhotka:

I have actually worked with db4o and use it as an example of what I’m talking about.

 

If you create a Customer object with CustomerName, and you create an Order object with CustomerName you’ll have the field twice in your db. Go change the customer name in your customer and watch as it DOESN’T change on the orders for that customer. Whoops...

 

Rocky

Maybe you where trying to simplify but true OODBMS don't store in relational form at all (columns and tuples), they do however promote normalization which I think most everyone agrees is a good thing, although I am getting the feeling maybe not so here, which seems odd.

Your example also seems odd (again maybe you where trying to simplify), but why would you have a CustomerName string property and not a Customer property with a Customer class? That seems like classic denormaliztion and generally that would be a very bad thing. How do I know it's the right customer "John Smith" or the other "John Smith"?

There are some OODBMS that support composition of new objects from existing object through a query language to say pull just CustomerName out of a full customer object giving you a new simpler object. Most avoid this and instead would perfer you to create these "view" objects in your OO language that wrap the full object, thereby exposing just the members you want while not replicating the same data over and over again. Just classic normalization using objects with object references instead of table with foriegn keys.

Justin



pelinville replied on Wednesday, February 28, 2007

I don't get that though.  Why would you have CustomerName as a field in both Order and Customer objects?
 
Having both with a property with CustomerName property I understand.  But both having a field that is a part of the object?
 
It seems this is only a problem when you have conflicting use cases.
 
1. The Order will display the name of the customer. Once placed this name shall not change regardless of customer changes.
 
2. When a customer name changes all references to that name will also change.
 
 
Sorry, missed the first one when you spoke of performance.
 
I kinda agree with that.  But not completly.  Our application does this in almost all cases. We are hosting about 150 schools.  This is for all the teachers students and guardians.
 
I wouldn't try it in a extreamly high transaction environment. But in more moderate cases it works out well.

RockfordLhotka replied on Wednesday, February 28, 2007

I picked an arbitrary, and perhaps not the best, example here.

 

But consider that when you edit a customer’s data, you need to change the name.

 

And when you are entering an order for a customer, the customer may want you to change their name (or some other bit of data). At the very least, that data appears as part of the order. What order doesn’t show the customer’s number, name and probably address? A subset of the customer data is part of (even if only in a read-only manner) the order.

 

It seems obvious, then, that Order has a ‘using’ relationship with Customer, and any time you display an Order on screen, you’d load a Customer to get those few fields of data required. But it turns out, in reality, that loading the huge Customer object just to get 3-5 fields of data is impractical.

 

Rather, those fields of customer data, are really part of the order object. A typical design will involve the Order object having 3-5 properties (perhaps read-only) that are actually customer data.

 

But if the customer data is changed – like the customer’s name changes from “ABC Corp” to “XYZ Inc”, you’d rather expect that any orders would automatically gain that change right? You can either do this the hard (insane?) way, by having your customer edit code seek out and find all orders for that customer so you can change their corresponding values. Or you can normalize the data so changing that one field automatically impacts all other locations.

 

In the RDBMS world you’d store the value once and then use it where needed through JOIN statements. But pre-RDBMS (a world I lived in for years), you’d load the order data, then you’d load the required customer data and you’d use the fields you gathered. Think of it like doing a manual JOIN.

 

And realistically that “manual join” concept is what you have to do with an ODBMS too. Your Order business object CAN’T be loaded directly from the database. You have to load your OrderData object and your CustomerData object and pull the fields from each that are really required to construct the logical concept of an Order.

 

The core issue is that an ODBMS is a database first, and an object representation second. Sure, all data is represented as properties of objects. But it is STILL DATA, and is still subject to the same core rules about how data works.

 

Rocky

 

From: pelinville [mailto:cslanet@lhotka.net]
Sent: Wednesday, February 28, 2007 3:49 PM
To: rocky@lhotka.net
Subject: RE: [CSLA .NET] Using rules to change object's state

 

I don't get that though.  Why would you have CustomerName as a field in both Order and Customer objects?

 

Having both with a property with CustomerName property I understand.  But both having a field that is a part of the object?

 

It seems this is only a problem when you have conflicting use cases.

 

1. The Order will display the name of the customer. Once placed this name shall not change regardless of customer changes.

 

2. When a customer name changes all references to that name will also change.

 

 



pelinville replied on Wednesday, February 28, 2007

My only part of your statement I take issue with is "loading the huge Customer object just to get 3-5 fields of data is impractical".
 
I have found this to often not be the case.  Because huge is, or at least could be, a bit of an overstatement.  If customer only has 6 fields to begin with then I would say that only getting 3 is a bad idea (depending on the size of the other 3 of course.)
 
But even if they are large fields or there are 20 total, I have found that using containment and enforcing encapsulation increases maintainability by a huge amount. Even with something as simple as CustomerName it helps. (Formatting and validation all that)  So normally I have found it to be worth any performance hits to keep fields encapsulated in the class to which they belong.  (But sometimes I have to cheat and join at the db.)
 
But maybe we are just talking past each other.
 
In db4o the developer is tempted to put CustomerName as a field in Order.  This means that CustomerName is actually stored in two places. The reason they are tempted to do this is because the "data" is not easy to get at from outside of the object.  But that is exactly what you don't want to do when using db4o because the data problems you mention. (This is the major weakness of the OODBMS, getting at the raw data.)
 
But when using the RDBMS as the storage, the CustomerName field , in a decent design, would be stored in one place. Order (or any object) can "cheat" to populate it's field.  Logically the CustomerName is still controlled by Customer (since that is the table it is in). So if you change it in Order the next time you load Customer you will see the correct name.  But the only reason to "cheat" is for performance reasons.
 
This is also true in db4o.  The only reason to "cheat" and store the name in the Order object is to facilitate a semblance of reporting efficiency. 
 
And finally there are a large number of applications that just don't need to cheat. These include large multi user apps. It seems to me if the application does not need "real time" data and it is not a high transaction app then why not do it right and resist cheating? In other words only cheat when you are forced to?
 
Isn't there some saying like "Premature optimization is horrible thing?"
 
 
RockfordLhotka:

I picked an arbitrary, and perhaps not the best, example here.

 

But consider that when you edit a customer’s data, you need to change the name.

 

And when you are entering an order for a customer, the customer may want you to change their name (or some other bit of data). At the very least, that data appears as part of the order. What order doesn’t show the customer’s number, name and probably address? A subset of the customer data is part of (even if only in a read-only manner) the order.

 

It seems obvious, then, that Order has a ‘using’ relationship with Customer, and any time you display an Order on screen, you’d load a Customer to get those few fields of data required. But it turns out, in reality, that loading the huge Customer object just to get 3-5 fields of data is impractical.

 

Rather, those fields of customer data, are really part of the order object. A typical design will involve the Order object having 3-5 properties (perhaps read-only) that are actually customer data.

 

But if the customer data is changed – like the customer’s name changes from “ABC Corp” to “XYZ Inc”, you’d rather expect that any orders would automatically gain that change right? You can either do this the hard (insane?) way, by having your customer edit code seek out and find all orders for that customer so you can change their corresponding values. Or you can normalize the data so changing that one field automatically impacts all other locations.

 

In the RDBMS world you’d store the value once and then use it where needed through JOIN statements. But pre-RDBMS (a world I lived in for years), you’d load the order data, then you’d load the required customer data and you’d use the fields you gathered. Think of it like doing a manual JOIN.

 

And realistically that “manual join” concept is what you have to do with an ODBMS too. Your Order business object CAN’T be loaded directly from the database. You have to load your OrderData object and your CustomerData object and pull the fields from each that are really required to construct the logical concept of an Order.

 

The core issue is that an ODBMS is a database first, and an object representation second. Sure, all data is represented as properties of objects. But it is STILL DATA, and is still subject to the same core rules about how data works.

 

Rocky

RichardETVS replied on Thursday, March 01, 2007

Rocky ; let’s see if I get it right.

 

You can get away with a lot if the database is on the user’s workstation and so, by definition, there’s one user. But as soon as you start trying to load entire Customer objects to get one field of data for dozens or hundreds of users, and that data must travel even from the db to the app server, you are done for.{

You’re saying that in an ideal world, the order would have a customer object, but in real world and for distributed applications, performance considerations prevent use of the Customer object as field or Order, and it is better to duplicate some data in the Order object, like CustomerName?

 

And if you use a RDBS, with a join update, you could modify both the Customer and the Client tables, preserving data integrity? And that in an ODBS, you have to manually handle this case, if you chose to optimize performances by having an Order containing a CustomerName field?

 

To manually handle things like that seems pretty complicated. I would rather desing my model object so I can choose activation depth wisely, with a system like db4o. So I could load an Order object with its CustomerObject field; but only the first level fields of the Customer would be loaded; not the collections of objects it could have. That’s clear that I do not want to load the entire data graph of objects if I load an Order, and I came with the Order, the Customer object in the field, and all commands object for this customer. I think using a ODBS implies a different kind of data normalisation than with a RDBS.

 

I wonder if lazy loading and weak references are compatibles with the CSLA concept of mobiles objects, too.

 

Richard

RockfordLhotka replied on Thursday, March 01, 2007

Ultimately what I am getting at here is that there really are different views on how object design should work.

 

There’s a data-centric view, where the primary characteristic of an object is the data it contains.

 

And there’s a responsibility-centric view, where the primary characteristic of an object is its purpose within a use case.

 

I started learning about OOD by reading Booch and Jacabsen, and therefore I started with that data-centric view, like most people do. Slowly over the years, having suffered with pain and complexity over and over again, I came around to the responsibility-driven viewpoint. People like Cunningham, Beck, Taylor and West are the luminaries here.

 

I only wish I’d STARTED where I am now and skipped all those years of pain and suffering.

 

But it appears that everyone must go through this cycle, and it also appears that a lot of people never get out of it – preferring instead to come up with more and more elaborate ways to make the data-centric approach “work”.

 

And please note: I do not think I (or Cunningham/West/Beck/etc) have all the answers. The REAL lesson out of all this, is that OOD is a journey, not a destination. Every time I turn around I’m learning a new and better way to think about something, or at least to express it.

 

It is also important to realize that CSLA .NET supports either approach. You can (with some care) use CSLA to help you build data-centric objects, and you’ll get a lot of value from doing that. I’ve done that myself numerous times. But I personally think you are better off using CSLA to help you build responsibility-driven objects, because I think that approach to OOD is far superior.

 

Rocky

 

 

From: RichardETVS [mailto:cslanet@lhotka.net]
Sent: Thursday, March 01, 2007 7:06 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Using rules to change object's state

 

Rocky ; let’s see if I get it right.

 

You can get away with a lot if the database is on the user’s workstation and so, by definition, there’s one user. But as soon as you start trying to load entire Customer objects to get one field of data for dozens or hundreds of users, and that data must travel even from the db to the app server, you are done for.{

You’re saying that in an ideal world, the order would have a customer object, but in real world and for distributed applications, performance considerations prevent use of the Customer object as field or Order, and it is better to duplicate some data in the Order object, like CustomerName?

 

And if you use a RDBS, with a join update, you could modify both the Customer and the Client tables, preserving data integrity? And that in an ODBS, you have to manually handle this case, if you chose to optimize performances by having an Order containing a CustomerName field?

 

To manually handle things like that seems pretty complicated. I would rather desing my model object so I can choose activation depth wisely, with a system like db4o. So I could load an Order object with its CustomerObject field; but only the first level fields of the Customer would be loaded; not the collections of objects it could have. That’s clear that I do not want to load the entire data graph of objects if I load an Order, and I came with the Order, the Customer object in the field, and all commands object for this customer. I think using a ODBS implies a different kind of data normalisation than with a RDBS.

 

I wonder if lazy loading and weak references are compatibles with the CSLA concept of mobiles objects, too.

 

Richard



RichardETVS replied on Thursday, March 01, 2007

Well, I suppose I still on the data centric side, because there is something I do not understand. Let’s say databases do not exist, that we work only in memory for a local application. How I get my CustomerName updated in both the Customer Object and in the Order object? If I can’t use SQL join to put them in a database?

Now, I am conscious that OOD in a long journey, and there is a lot of things I did not see, yet. If you have some links, books and articles about responsibility-driven object design, I am interested.

And thanks for your good job, Rocky, as I said, your framework and book are both useful and good lesson in development.

Richard

Justin replied on Thursday, March 01, 2007

RichardETVS:

Well, I suppose I still on the data centric side, because there is something I do not understand. Let’s say databases do not exist, that we work only in memory for a local application. How I get my CustomerName updated in both the Customer Object and in the Order object? If I can’t use SQL join to put them in a database?

Now, I am conscious that OOD in a long journey, and there is a lot of things I did not see, yet. If you have some links, books and articles about responsibility-driven object design, I am interested.

And thanks for your good job, Rocky, as I said, your framework and book are both useful and good lesson in development.

Richard

I really think this concept is important, what if you didn't have to worry about your persisents engine, disk i/o and other physical implementation details, what would your objects look like? Are you making design decisions based on good design philosphies or are you letting implementation creep up and break through your encapsulation.

This is always a struggle since physical architecture issues are the reality we work with but the ideal is something we strive for correct?

So which is the better design in this specific example ignoring implementation issues? Should an Order have a CustomerName property or should an Order have a Customer property that is a reference to a Customer class instance?

As far as replicating a relational join using a pure OO in memory model that is relativley easy. The Order object hold a reference to a Customer object (this is equivalent to an Order table having a Customer FK field), then you make a new "view" object wrapping both and exposing both Order properties and Customer properties of your choosing but the getters and setters simply go to to wrapped objects. In this design you simply replace SQL code with OO code to accomplish the same thing. SQL being a declarative language with a smart optimizer can eliminate the physical I/O of retrieving the unrequested Customer data from disk whereas with OO in memory this doesn't matter since you are just holding references to class instances which unless you actually request a specific property it will not incur the overhead of reading the data from that memory location. Note though with a in memory OO model you pretty much eliminate the need to even do this type of "join" since the base Order object holds a reference to the full Customer object yet it has no cost associated with holding the reference.

Now imagine a OO runtime that could be backed by persisent storage instead of volatile ram but performed just as good how would our designs look?

Justin

 

malloc1024 replied on Thursday, March 01, 2007

Booch and Jacobsen are strong advocates of the use-case driven design.  A use-case driven design does have it merits and many developers have used it successfully. However, it does seem that a use-case driven design can lead to a more functional design rather than an object oriented design.  Bertrand Meyer, one of the earliest and most vocal proponents of OOP, wrote, “Use cases favor a functional approach, based on processes (actions).  This approach is the reverse of OO decomposition, which focuses on data abstractions; it carries a serious risk of reverting, under the heading of object-oriented development, to the most traditional forms of function design.”  He and others have written about there dislike of a use-case driven design.   There is never a consensus on how to develop code.  This is what makes it fun, challenging and frustrating at times. Ultimately, it is up to the developer to try different techniques to decide what works best for him or her.  If you want to learn more about the use-case driven approach, you can read the book listed below.  If you want to read about the potential problems with a use-case driven approach, you can read the following article: http://www.toa.com/pub/use_cases.htm .

 

“Object-Oriented Software Engineering: A Use Case Driven Approach” by Jacobsen:

http://www.amazon.com/Object-Oriented-Software-Engineering-Driven-Approach/dp/0201544350

RockfordLhotka replied on Thursday, March 01, 2007

Certainly read the books by David A. Taylor and David West. Evans’ DDD book is quite good as well.

 

Google for “single responsibility design” or “responsibility driven design” and you’ll find a fair amount of material as well.

 

Rocky

 

 

From: RichardETVS [mailto:cslanet@lhotka.net]
Sent: Thursday, March 01, 2007 9:06 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: RE: Using rules to change object's state

 

Well, I suppose I still on the data centric side, because there is something I do not understand. Let’s say databases do not exist, that we work only in memory for a local application. How I get my CustomerName updated in both the Customer Object and in the Order object? If I can’t use SQL join to put them in a database?

Now, I am conscious that OOD in a long journey, and there is a lot of things I did not see, yet. If you have some links, books and articles about responsibility-driven object design, I am interested.

And thanks for your good job, Rocky, as I said, your framework and book are both useful and good lesson in development.

Richard



RichardETVS replied on Friday, March 02, 2007

Ok, thanks for all the answes, I'll dig into tha stuff.

 

Richard

Justin replied on Wednesday, February 28, 2007

ajj3085:

Again a lot of what happens depends on the use case.  Assuming you can have multiple items ready for the next stage of the workflow, you'd probably load an editable object based on an item from a readonly collection of items, in which case you wouldn't necessary need to worry about exceptions.  (The bo would still throw one, but the UI may not need to worry.  Again, it depends on the workflow and how many people are in the mix working on work items).

The read only collection is the consumer here, it must be coded to understand the workflow, I could just as easily write a collection that examines the properties of the object to display only the ones in the correct state, either way the consumer is preventing an exception.

ajj3085:
In a very simple, non-interactive workflow, you might be right you don't need all the overhead of OO. You may be better off with another method.  But if the item needs to be modified, such as additional data added, existing data changed, and certain rules must be met (such as some new data MUST be entered, you can't choose value X if value A is chosen) then a business object makes a lot of sense.  The problem is that you can take your argument and use it to rule out OO in every case.  But we're not just using OO to make things simple; we're using it to help with maintainability.  An OO based application (if done right) is usually easier to maintain than a procedural application (also done right).


Multiple classes with the same properties and one method to act on them is just as hard to maintian as multiple functions all having the same parameters, it's why OO came to be, but some people still prefer pure funtions, sounds like whats happening here except your using a runtime that has all this OO overhead. It's just like MS's stateless com+ object recommendations your barely even using objects more like groupings of functions.

ajj3085:
Sorry, I'm having trouble understanding the question..

Per your example "such as some new data MUST be entered, you can't choose value X if value A is chosen" That BL must be replicated in every class that has X editable. So now to resuse that BL you must make yet another class that understands X and all classes that have X now need to reference this new "rule" class that is separate from the actual classes that contain X. Sounds like a break down of containment, instead of just implement the BL for X in the same place that defines what X is.

ajj3085:
If the change in schema really does affect every use case, yes you're right you'd have some work to do.  It depends on the specifics though.  The rules could be kept in one spot and you could probably designate an object that defines rules for multiple types, not just a  single type.  Proper refactoring  would likely save a lot of headaches.

Again sound like you would be better of without objects and just use a bunch of functions that take parameters since your decomposing all your BL from one entity into separate independent classes.

ajj3085:
Using code gen and other techniques make it practical.  OO isn't about code reuse, its about building a maintainable application.  Your one BO that handles ALL stages of the workflow is undoutably large, complex and its very likely that making a change to it will break its other intended uses.  Some times you need to do more work upfront to do less work later.


I disagree OO is about reuse, function code is very maintainable but objects are all about componentization and hence reuse.

ajj3085:
I'm not sticking blindly to a principal; I'm sticking to it because it makes sense, and I know what happens when you go the other route.  Workflow rules are business rules, and putting that logic in the data layer or designing  your objects around data lead to harder to maintain and harder to change systems. 

I have also seen hard to maintian systems based on your model to doesn't mean it always occurs and that one always works better than the other. Don't busniess rules basically just enforce how data can be modified? Is max length on a string a business rule or data type attribute?

Justin:

Before Clsa I did design my objects around the database and tried to make one object do many things simply because it shared the same properties.  Our BOs were simply generated from a specific table, and then we added methods.  And you know what, the system WAS harder to maintain and  harder to change.  Since I've started doing things in a behavior based way, I've found it much easier to build and maintain my applications.  I'm advocating the behavior based way because I've found the data based way leads to a mess, each and every time. 

I have seen systems that work great on data centric approaches so what? I don't propose one is better than the other they both have thier uses and I don't think we are done fully understanding information theory to proclaim one the absolute winner.

ajj3085:
So its better to construct an object which you can do nothing with but throw away?  As I said before, you usually don't get into this scenario because you usually already know you can load the editable object.

Define "better" they both have their tradeoffs kinda depends on teh specific use-case huh ;)?

ajj3085:
Yes, techinically they are methods.  Do I have logic in my properties?  Nothing that's not consistently easy to regenerate via code gen.  The actual business rules themselves are in other methods that get called via the PropertyHasChanged call.  99% of my property definitions are identical to each other in form.  That's what I mean when I say they have no value.  The premise of OO is that the object is the only one that can change its state; in procedural languages, the program keeps ALL state and its up to the program to maintain that state, and almost anything called can modify that state.

Again isn't the point of OO combining data and code not separating it?

ajj3085:
Would I push behavior based design on say a data import tool?  I wouldn't and databased design there is just fine.  But the fact here is that we are talking about a workflow.  Workflows are defined by business processes, and those are the kinds of things that should be put into a business layer, and my experience tells me the best way to build a business layer is behavior (ie, use case) based design. 

"Workflow" is a pretty general term, workflows invlove data, heck even a data import tool probably has "workflow" ;).

Copyright (c) Marimer LLC