OO with CSLA: 1 Object = 1respoinsibilties and many Behaviours?

OO with CSLA: 1 Object = 1respoinsibilties and many Behaviours?

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


ianinspain posted on Wednesday, October 25, 2006

Hi there,

I was reading a thread lately ( http://forums.lhotka.net/forums/1/1658/ShowThread.aspx )... and still I am a little confused so i thought i would outlay what i think i have learnt and i was hoping somebody could step in and help with my rights and wrongs..

I have been reading that an object (a class) should have one responsibility.... ermm ok ... I accept this but how do we clarify reponsibility..

Take for example an invoice object (yep a typical example :-) ) .... so where is the responsibility... Is this infact the INVOICE .... so hence a CUSTOMER, SUPPLIER, etc are all different responsibilities ??

Or is it a case of an "INVOICE can PRINT", an "INVOICE can EDIT" ?? In this is the case, does this mean i would potentially need in this example 2 objects, 1 that handle the PRINT and one that handles the EDIT?

Ok... so taking this further, from what i have learnt (so i believe anyway :-) )... that an object can have many behaviours .... fine .. accept this also... but what do we classify a Behaviour??

If we assume that an object called "INVOICE" can PRINT,EDIT,DELETE,CLONE etc .. then assuming that INVOICE is only 1 object.. then i presume the behaviours are PRINT,EDIT,DELETE and CLONE.

ermm Ok... sounds good, but thats where i am confused because lets assume that this is wrong (which it may be) and an INVOICE must have separate objects to PRINT, EDIT, DELETE etc then what would the behaviours be here?

i.e. Object "INVOICE - PRINT" - then behaviours would be PRINT_BOLD, PRINT_DRAFT, PRINT_QUALITY, etc

Well this is basically what i have so far, but i have a fine line between each statement thats just confusing me...

I hope somebody can help on this... I think i am nearly there, am i not? Or possible could be on a different planet :-)

Look forward to any input

Thanks in advance

Ian

ChristianPena replied on Wednesday, October 25, 2006

I am fairly new to this myself so I might be off on this as well but I see it as you described.

The Invoice class has one responsibility: To maintain invoice state and data. The behaviors are as you described; to Edit, Delete, Clone, etc.

I'd love to hear from others.

ajj3085 replied on Wednesday, October 25, 2006

You're close.  Its not the invoices responsibilty to display itself, that is the responsibility of the UI.  An Invoice object would likely be for modifying invoice data.  To actually print you'd probably not use the edtiable Invoice object, since you dont need any of its editing capabilities.  You'd probably create an InvoiceInfo object, which is meant only to display invoice data.  It has no other purpose.  Edit, delete, and cloning are all functions which must obey business rules so that the object cannot be saved in an invalid state (one in which one or more of its rules are broken). 

Business objects in general are only meant for one thing; to enforce business rules.  The data layer's job is to store data, the business layer's job is to intererpate and change the data, and the UI's job is just to display data.

HTH
Andy

ianinspain replied on Wednesday, October 25, 2006

Hey thanks...

I think i am understanding it a little better now.....

So continuing on the invoice object....

So editing, creating, delete an invoice object would be ONE object

but to display it only that would be ANOTHER object

... I think i am nearly there, so taking the invoice object/s to the extreme .... in what other scenerios would there be more "different" types of invoice objects..

And... with the InvoiceInfo object, then i presume the behavior would be "GetFormattedOutputForPrint" or similar?

In this scenerio whatelse would the InvoiceInfo be good for?

In the ACTUAL Invoice Object, the behaviours here would be Edit, Delete etc .. because there are all related to changing the object ?

Thanks once again for your time

Ian

Bayu replied on Wednesday, October 25, 2006

Hey there,

I think you are too deep into your definition study. Let's take a step back and consider your software from a broader viewpoint.

Why do you apply OO anyways?
Or more to the core of your question: when do you apply OO techniques?

About the why:
- this could open up a huge discussion, let's not fall into that trap and stay generic:
- I postulate that you will not (at least should not) apply OO for its own sake ...
- basically, this translates to: you apply OO for a purpose beyond the OO design pattern itself

So, about the when, how do you recognize when there is a purpose for OO techniques (which is basically your question):
- that is anytime when you encounter (or envision) that variability of one part of your application software is required.


I will not provide formal proof, but let me give a number of examples based on CSLA instead:

- any BusinessBase object needs to support some or all CRUD operations (insert/update/remove, etc), so there is no variability in there, hence we put all of these IN the object. If you like to call these behaviors or something else does not really matter, what matters is the presence or absence of the variability requirement;

- CSLA does intend to support different tier-setups: local database, remote database, etc. So this is a variable, hence you see that this aspect is factored out of the BusinessBase and got it's own design (the dataportals)

- your invoice needs to be persistable (insert/update/save), so the CRUD operations, no question about variability so there is no need to externalize these (behaviors) to new objects

- your invoice may also need to be printable, if 'printing' has a single interpretation (e.g. printing to paper) then you could put it inside the invoice class and be done with it.
- if you find that you are repeating printing-related code over and over in all your classes, then start scratching your head:
    - either move printing code to a base class so that all your printable classes inherit this single set of code (just like BusinessBase implements a lot of default behavior)
    - or change viewpoint: take the 'printing logic' as your anchor point and note the variability in objects that can be printed. This would validate a design where all printing logic goes into its own class.
- another case is when you have different kinds (flavours) of printing, e.g.: printing to printer and printing to a Word document and printing to a PDF file. Then the printing logic is variable and again you have a case to externalize this logic in its own class hierarchy.

Maybe you have some experience with relational databases. If that is the case, then OO could be seen a 'normalizing business objects and logic'.

Hope this helps.

Bayu

pelinville replied on Wednesday, October 25, 2006

ajj3085:
To actually print you'd probably not use the edtiable Invoice object, since you dont need any of its editing capabilities.  You'd probably create an InvoiceInfo object, which is meant only to display invoice data.  It has no other purpose. 
 
But the InvoiceInfo object would probably use an Invoice object and then format the data from the Invoice  BO.  Correct?
 
This allows the InvoiceInfo to change without affecting the Invoice object.  For example the InvoiceInfo might have to display the Customer Information also.  To accomplish this the InvoiceInfo object now uses the Invoice obj and a CustomerInfo object to produce the desired output.
 
 
 
 

ajj3085 replied on Wednesday, October 25, 2006

No, the invoiceinfo object wouldn't use the invoice object at all.  The invoiceinfo would 'know' how to get its own data.  A change to invoice should not require invoiceinfo to change at all (although changes to the concept of an invoice may).

That said, both of those classes might use a third, internal (to the assembly) class which gets the data from the database.. since both are reading from the same table.  But that depends on how similar the fetching is for both of those classes.

The invoiceinfo object would likely query the customer table, to get information on the customer (where as the invoice just needs to know the name and address, for example).

Check out the project tracker sample that comes with Csla, and consider purchasing the book.

HTH
Andy

pelinville replied on Wednesday, October 25, 2006

ajj3085:
No, the invoiceinfo object wouldn't use the invoice object at all.  The invoiceinfo would 'know' how to get its own data.  A change to invoice should not require invoiceinfo to change at all (although changes to the concept of an invoice may).

That said, both of those classes might use a third, internal (to the assembly) class which gets the data from the database.. since both are reading from the same table.  But that depends on how similar the fetching is for both of those classes.

The invoiceinfo object would likely query the customer table, to get information on the customer (where as the invoice just needs to know the name and address, for example).

Check out the project tracker sample that comes with Csla, and consider purchasing the book.

HTH
Andy
 
So to display the InvoiceInfo stuff you would have to save the invoice object then retrieve the InvoiceInfo data?
 
That doesn't make any sense.  What if the current invoice was dirty?  How do you print (or whatever) without saving it.  How do you do this if the application is running disconnected?
 
oops... Premature post.
 
Anway.  You are probably right.  I just don't see the need for that complexity.  Of course this is a pretty basic example so it probably isn't needed here.
 
I just don't see why you couldn't just "use" the objects already layin around.  Seems like alot of extra work and resource usage for no reason.
 
 

ajj3085 replied on Wednesday, October 25, 2006

Typically yes, that's what you would do.  Printing the invoice being edited would likely make use of the edtiable business object, although you have to think about things like 'can the user print an invoice not in a valid state?'  Eitehr way though, the UI uses the business object (editable or not) to create the report, but the invoice object doesn't know (or care) about what is done with it.  It is only concerned that its state is valid and providing a way to query about its state.

What you do in a scenario depends on your exact use case however.  You build classes to satsify the requirements of a use case.  If your next use case can reuse those objects (meaning that the use case has some behaviors in common) then you can do it.  If not, you may have to build another object which operations on the same data but does something different with it.

Disconnected is a whole other issue, that doesn't have much to do with Csla.  For example, how do you save an invoice if you aren't connected to the database?  Those are seperate issues from Csla.

pirithoos replied on Thursday, October 26, 2006

Hi Andy, Hi All!

I do follow up a lot of threats about OOD with CSLA.

Having my roots in very data-centric programming (MS Access) I do face each day the old problem to think first about data instead of  behaviour.  Rockys newer 2005 book was of great help. The new chapter in which Rocky lead us from the use cases to the class design of his PTracker application shows the right approach to design an application.

Anyway myself  and (seeing from this and other threats)  a lot of others let themselves seduce again and again trying to creat one super-power BO that can do anything. And mostly (at least in my case) it is due to the fact that one is trying to put all data in a class that might be usefull in other use cases as well, but we do miss out to focus on the current single use case we want to map to e.g. a class diagram. and to narrow the data to the minimum required herefore.

Maybe the mistake is to think CSLA is a frame-work with base classes which must be subclassed in any case for  any  class  required by an application.  IMO this  is  a problem  quite some people may have. (at least those like me  who are not a native developers/software architects or programmers).

One thing is for sure: If the use case is to write validated data into or edit existing data in a DB via some UI by users a CSLA.Businesbase is the right and pretty obvious choice. How easy this can be made by using CSLA is clearly shown by the PTracker application.

I assume, and this is also in my particular case the challenge, finding the right way to implement the other behaviours required by an application into classes. Or how to find out if it makes sense to subclass a CSLA base class or not. This is of course a issue that not mainly has to do with CSLA and therefore not a typical threat for this forum, but still I act under the impression quite some people here looking for advise.

For example I currently try to sort out the following:

Use Case:
Ship a consignment from A to B. The shipment could be effected by  road, sea, air.

The ConsignmentBO is pretty simple. Data is: CosignmentID, Productname,  net-weight, goss-weight, maessurements, Flag if consignment is already shipped or not and ShippedBy containing data about the shipment mode (by road, by sea, by air)

(There is another use case where the consignment can be created) Very easy approach, inherit Consignment from BusinessBase, writting a UI to create, edit and save it to the DB. This leads to the point where I am aware of the fact that a ConsignmentBO already exits in my design. And again I would think - well for the other use case (Ship a consignment from a to b) I already have one involved object ready designed....

...back to the 'ship out consignment' use case:

I could design an abstract class Shipment and sublass concrete classes  for ShipByRoad ShipBySea, ShipByAir.

Then I could pass a Consignment to a ShipmentBy... class which sets the flag if shipped and
according to the type of shipments set the Consignments.ShippedBy field to either road, sea, or air.
when finished the ShipmentByBO invokes the Save method of Consignment. Neither the abstract nor the concrete implementations like ShipByRoad, ShipBySea need to inherit from any CSAL base class.

Sounds reasonable to me, but...

another approach would be not to pass the CosignmentBO to a ShipBy class but implement the ShipBy classes in another way where they e.g. get an CosignmentID in there constructor and
load just the required data from the consigmnents DB table which must be modified due to a shipment effected. (In this case the required data is just IsShipped and ShippedBy). The abstract shipment class would know how to save this data into the DB again., the subclases would take care of other things like notifiying other classes to generate the freight-papers required for a sea shipment, curier-shipment or road-shipment.)  But in this case the ShipBy classe(s) must again inherit from CSLA (to assure a clear common way how to write data into the DB)

I could argue for the first choice as the Cosignment is still edited, validated and somehow returned to the DB and that was the reason for its creation in the other use case.

On the other hand I have somehow the feeling the second approach is more correct in respect to
OOD/OOP.

What is the best / or at least the most common approach ?

Best Regards

Frank

P.S.: If some other people know good comunities for OOD topics not necessarily related to CSLA your imput is much appreciated.
 




SonOfPirate replied on Thursday, October 26, 2006

Wow, quite a bit going on here...

Let me back-up to the original topic and address the question over 1 object - 1 behavior.  In the scenerio Ian originally described, you would have an Invoice object and yes, in some regards to semantics, one could say that this class is "defined" by its data.  However, a better way to think about it is that you have a shell of an object with properties and methods that support a specific behavior.  Then, you may or may not couple that object with "predefined" values obtained from a data store.

I word it this way because one of the keys to a good, stable and extensible design is to have our BO's data-agnostic - meaning that the BO doesn't care where the data comes from (e.g. SQL Server, Oracle, MySql, Access, XML file, config file, etc.).  To wrap my head around this, I always approach my design without a data store.  In other words, I always assume (at first) that my objects will be created and populated in code.  Then, once I have my "shell", I can provide the "hooks" for data access - as provided by the data portal features in CSLA.  I'll spare you an explanation on how data-agnosticity is achieved...

So, given this design, all that the data from our data store does is "describe" the actual instance of our object.  It does not "define" our object because that is done in code.  For example, what is a person?  A person is someone who has a name, eye color, etc. and, let's say breathes.  A person is our object and is defined as just that: an object with a name, eye color and that breathes.  To describe a specific person, we need to populate those properties with data.  So, we go to our data store and pull out the name and eye color of a specific person.  While this identifies that person it does not define WHAT a person IS.  Does that help?

Second, to implement a behavior-based model for your scenario, as Andy and others have described, you need to think about the core behavior that your Invoice object possesses.  It is there to allow you to edit the data that is contained in the Invoice.  Operations such as printing, e-mailing, etc. only use the data contained in the invoice and represent different behaviors.  As pointed out earlier, this is really no different than having a different object (or objects) to represent the invoice in the UI.  Printing is the easiest parallel as all you are doing is creating another presentation of the invoice data with the printer beign the target rather than a Windows or Web form.

In my experience, you would want to create an InvoicePrinter object that is responsible for printing.  A Print method, for instance, would accept the instance of your Invoice object or InvoiceInfo object (more on that in a second) as a parameter and do the rest of the work.  Why do this versus having a Print method on your Invoice class?  A couple of reasons.

First, while it seems to makes sense from an encapsulation perspective to have the Invoice "own" its Print method, you've added an additional responsibility onto that object.

Second, by encapsulating the Print method into the object, you've tied the object to a single way of printing.

Third, by using a separate class whose responsibility is printing, you can interchange that object with others to achieve different behaviors.  For instance, you can have a BlackAndWhiteInvoicePrinter, ColorInvoicePrinter, PostScriptInvoicePrinter, PdfInvoicePrinter - what ever (I'm just pulling names out of the air).

So you see, by decoupling the object from this second behavior, you actually give your app more flexibility and a more extensible and scalable object model to work with.  That is part of the rationale behind the 1 object, 1 behavior approach.

As for the InvoiceInfo object, remind yourself that the purpose of the Invoice object is manipulation (editing) of your invoice data.  As pointed out earlier, when printing, you don't need this behavior - all you need is a read-only copy of the data.  In addition, for reporting purposes, you don't necessarily need a complex heirarchy of objects as may be the case with your Invoice object which may have a BillToAddress property of Address type, etc.  When printing (a type of reporting), you will want all of this in a flat record rather than heirarchically.  So, the InvoiceInfo object gives you that different "view" of the same data so that it can be used in a different way (different behavior).  The InvoiceInfo object is still a BO and still possesses the requisite knowledge to acquire its data but exposes the data differently and provides different behavior.  In addition, this approach allows you to further extend your object model by creating multiple version of this type of class as well, such as SimpleInvoiceInfo and DetailedInvoiceInfo, that can be used to implement different use cases.  And, in the future, should you need to implement a new use case, you have the ability to just extend this one more time, for say a ConsolidatedInvoiceInfo object.

I hope that this makes sense and helps to clarify what I agree to be a confusing transition to make.  I came from the world of data-centric programming driven by relational databases and had to struggle through the same logic changes that you are going through.  So, hopefully this will help you wrap your head around the concepts a little better.

Good luck.

Cool [H]

pirithoos replied on Thursday, October 26, 2006

Hi,

thanks for your prompt reply and sorry if I came up with another use case in this threat. Anyway I would appreciate a recommendation for my use case.

It might clarify also other questions.


I will map the use case from my previous post to the world of  Invoices:


In real world the somebody from the bookkeeping puts a date-stamp on an invoice once it is paid.

Back in  Objectville I could…

 

Spend my InvoiceBO a new field InvoicePaidDate


Doing so I could pass an InvoiceBO to a Bookkeeping Object which
stamps it (edit the new PaymentReceivedDate field of the InvoiceBO and invokes Invoice.Save).

[very seductive, but it really seems again to be a data-centric approach as the InvoiceBO is treated only as a piece of data; well, smart data, but anyway just data]


or

 

I could create a PaidInvoiceStamperBO having the only responsibility to set the

InvoicePaidDate for a certain Invoice in the invoice table from the DB to e.g. Today.

 

This PaidInvoiceStamperBO would load the relevant invoice data (in this case only the InvoicePaidDate field from the DB by the InvoiceID passed into it via the constructor,

Set the InvoicePaidDate to Today and write it back into the DB.

 

 


Frank

SonOfPirate replied on Thursday, October 26, 2006

I would use a command object to handle the update.  All you would need is to identify which invoice was paid and execute the command object which would trigger the appropriate stored procedure in your database to update the record.

Depending on your interface is how you could do this.  If you have an instance of the Invoice object (because you are using it to data-bind the UI form), you could have a PaymentReceived method that would trigger the command object.  Or, (a better way, imo) have a static PaymentReceived method on the Invoice class that accepts the Invoice object and overloaded to accept the invoice's ID that triggers the command object.  This way you don't have to have an instance of the Invoice object, just its ID value (from a NameValueList used with a drop-down list, for instance).

However, having such a method in the Invoice class does raise the 1 object, 1 responsibility issue again as this behavior would be directly coupled with the Invoice object and tightly implemented with the single command object.  Doesn't leave much room for flexibility.

This is an area (command objects) that I have struggled with a bit.  This is the approach Rocky uses in the book for the ExistsCommand implementation, but I can see an argument about it so I'll leave it to someone else to explain the preferred way to implement this to satisfy the 1 object, 1 responsibility rule.

Hope that helps.

 

dean replied on Thursday, October 26, 2006

May not understand but:

Isn't the datestamp on the invoice really a relationship between the invoice and the payment? (Don't remember whether we are talking about payables or receivalbes but) Doesn't the payment get applied to the invoice (ar) or generated based on the invoice (ap)? During that process wouldn't the datestamp be generated/updated or is the datestamp just a reflection of the either payment object creation date or the check object creation date?

Dean

SonOfPirate replied on Thursday, October 26, 2006

That very well may be.  But, the use case we were presented with didn't say anything about other activity.  If the application is posting the payment information, then it would certainly be reasonable to extend this to include a relationship between the invoice and the payment received against that invoice.  But, it may also be the case that the goal is to simply reconcile the invoice and no further information or action is required.

Based on the simple use case presented, I'd go with the simple solution and use a command object.  If the use case was expanded to include other objects and actions, then I'd have to reconsider and you are correct that we would most likely introduce another business object into the mix to represent the payment and handle its responsibilities.

 

Wal972 replied on Friday, October 27, 2006

Hi,

This whole scenerio could be changed with a different perspective. The stamping of the invoice once it's paid, is really part of the Paying the Invoice use case and would form part of this BO rather than be part of the Invoice BO or being passed between the Bookkeeper BO and Invoice.

Its a step the process of paying the invoice. Not a part of an isolated BO

Hope this helps

Ellie

SonOfPirate replied on Friday, October 27, 2006

Agreed.  And depending on the scale of the "Pay" BO, it may simply be a command object or it may require additional data and logic to satisfy the use case.  All depends on the actual use case.

ianinspain replied on Friday, October 27, 2006

Hi SonOfPirate! thanks for the help.... its really been helpful.. I have a couple of clarifications... if thats ok

InvoiceObject is the editable BO

and InvoiceInfo is the ReadOnly BO .... so the CRUD methods would not be shared, they would implement there own Data classes - correcT?

You say: "Third, by using a separate class whose responsibility is printing, you can interchange that object with others to achieve different behaviors.  For instance, you can have a BlackAndWhiteInvoicePrinter, ColorInvoicePrinter, PostScriptInvoicePrinter, PdfInvoicePrinter - what ever (I'm just pulling names out of the air)."

So basically basically BlackAndWhiteInvoiePrinter and COlourInvoicePrinter would inherit from InvoicePrinter which would be an abstract BASE class?


You say "A Print method, for instance, would accept the instance of your Invoice object or InvoiceInfo object (more on that in a second) as a parameter and do the rest of the work. "

I would pass this into the method from my UI. right?

Thanks once again, things are quite a bit clearer now....

Ian


ajj3085 replied on Friday, October 27, 2006

The invoiceobject and invoiceinfo could share fetch code, if you can load an invoiceinfo directly; that is, it is a root object (has public factory methods).

The InvoicePrinter interface and implementing classes would belong in the UI layer.  The reason is that they are of no use unless you're building a Forms application.  For a webapplication, they are pretty much useless.  Their concern is displaying (printing) a report, which is a pure UI artifact.

HTH
Andy

ianinspain replied on Friday, October 27, 2006

wow that has thrown me :-)

So the InvoicePrinter BO belongs in the UI classes..... but i presume it still inherits from CSLA??


malloc1024 replied on Friday, October 27, 2006

Yes the InvoicePrinter class belongs in the UI; however, it does not inherit from any CSLA classes.  It doesn't need too.

malloc1024 replied on Friday, October 27, 2006

Why would the InvoiceInfo object get its own data from the database?  It seems to make more sense for it to accept an Invoice object and perhaps other objects to display an invoice.  The InvoiceInfo objects job is to display the invoice in a proper format.  It shouldn’t need access to the database.   Think of the InvoiceInfo object as a read-only form in the presentation layer.  Does the read-only form get its own data so it can display it or do you pass an object to it so it can display the objects data?  Based on the logic that two objects shouldn’t interact if based purely on data, the read-only form should get its own data from the database.  However, passing an object to the read-only form is preferable.  Therefore, it seems acceptable to pass an Invoice object to an InvoiceInfo class.  Just because the InvoiceInfo class only needs data from the Invoice class, doesn’t mean you shouldn’t pass an Invoice object to an InvoiveInfo object.  Does the mantra, “objects are defined by behavior, not data” really mean that two object can’t interact with each other if it is based purely on data?  I am not sure that it does.

ajj3085 replied on Friday, October 27, 2006

malloc1024:
Why would the InvoiceInfo object get its own data from the database?  It seems to make more sense for it to accept an Invoice object and perhaps other objects to display an invoice.


Why force the user to load an invoice on the edit screen just to print it?  It really depends on the use case.  However...

While it might be valid to load InvoiceInfo from Invoice, I would argue against it.   The reason is that you've now coupled your InvoiceInfo class to your invoice class.  You may make a change to Invoice that requires a change to InvoiceInfo, which is something you want to avoid. 

You don't want to put yourself into a situation where your changes in your classes cause changes to other classes, if possible. 

A better solution would be to have the invoiceprinter accept either an invoice or invoiceinfo object.  Ideally you'd have a factory because you should probably have an InvoiceInfoPrinter object and an InvoicePrinterObject.. 

Of course that's my opinion, you can decide for yourself if you agree.  one of the goals in OO though is to keep things as loosely coupled as possible, so that changes to one class don't ripple through to your other classes.

malloc1024 replied on Friday, October 27, 2006

I agree that you want to keep things as loosely coupled as possible.  To provide loose coupling between InvoiveInfo and the Invoice classes, you would use interfaces.  Allowing the InvoiceInfo class to retrieve its own data does require the class to know about persistence logic.  There are always a trade-offs.   Like you said, it does depend on the use-case.  Both solutions can be acceptable depending on the use-case.

pelinville replied on Friday, October 27, 2006

 

ajj3085:
malloc1024:
Why would the InvoiceInfo object get its own data from the database?

It seems to make more sense for it to accept an Invoice object and perhaps other objects to display an invoice.

Why force the user to load an invoice on the edit screen just to print it?  It really depends on the use case.  However...

While it might be valid to load InvoiceInfo from Invoice, I would argue against it.   The reason is that you've now coupled your InvoiceInfo class to your invoice class.  You may make a change to Invoice that requires a change to InvoiceInfo, which is something you want to avoid. 

You don't want to put yourself into a situation where your changes in your classes cause changes to other classes, if possible. 

A better solution would be to have the invoiceprinter accept either an invoice or invoiceinfo object.  Ideally you'd have a factory because you should probably have an InvoiceInfoPrinter object and an InvoicePrinterObject.. 

Of course that's my opinion, you can decide for yourself if you agree.  one of the goals in OO though is to keep things as loosely coupled as possible, so that changes to one class don't ripple through to your other classes.


I was trying to explain this earlier. 

While loosely coupled is a design goal for the system it is not really a consideration for the object design itself.  In fact encapsulation is one of the primary concerns of object design. Objects do not care if they are loosely coupled, only the system does.

This is what I was trying to explain before. Data stores, no matter they be xml files, RDBMS's or whatever, really do defeat one of the primary and most basic of object thinking. Encapsulation.

Ideally the data of the Invoice is only controlled by the Invoice. No other object has access to that data unless the Invoice object gives it permission.  Having the IvoiceInfo object (or whatever) get it's data from the data store bypasses the whole concept of encapsulation.

Here is one of the problems I am dealing with in the world of object databases.

First, you have to forget that their is a pool of data out there you can create your objects from.

So in the original data driven design I had three Objects; Address, AddressCol and AddressDirectory.

Address was a simple little thing I am sure we all have created and worked with.

AddressDirectory was a list (collection) of all the addresses in a particular format listed with who could be reached at it.

There was also an AddressCol that was a collection of Address.

Now in the DB world when I wanted to create the AddressDirectory I went to the address table and joined it with the person, company and organization tables then loaded them into a collection of strings.

But In the pure object world there is no database. I can't just get all the addresses because that would mean creating an address object for each address that existed.  Not only that but because the AddressDirectory also needs to know who (company, person, organization) the address is for, and Address objects have no idea who they belong to,   So in reality I would have to load all the Company, Person and Organization objects then get their AddressCol objects to create the AddressDirectory.

In the DB world I simply do a few joins and tada! all the info is available.

So what I have ended up doing is creating a AdressRegistrator object. When a Company etc. adds or changes an address it adds its information to the AddressDirectory. (It really is just a list of strings.)

Now the database is kinda out of wack.  The DB guy hates the idea of having a table that contains this "Address Directory" data because the two can go out of sync. It is just asking for abuse. So what I am doing is having a table with a single row and I am serializing the AddressDirectory to a blob. Ugly but I don't think those using the DB will try and use a big ol blob to extract data from.

What I am trying to say is that if you use a DB you do let data define your objects even if you don't realize it.  Looking back it was always stupid of me to just pull the address and people names in a join to populate the AddressDirectory. Stupid from an OO perspective anyway.

So going back to the InvoiceInfo object.  Having it load it's data from a data store is not good oo practice. It works fine until you have to do something like I am doing.

As malloc stated there are ways to keep things loosy goosy. Though in this example I don't think it is really necessary. What kind of change in an invoice object would mean the InvoicePrinter/Info object would need to change? Again invoces are a bad example because they are so common and really quite static.

And I don't see what advantage their is in creating an InvoiceInfo object over creating a Invoice object and using it in the InvoiceInfo object. Even in the most complex of editable business objects it's creation can't be more than a couple of cpu cycles more than creating a InvoiceInfo object.

Plus the InvoiceInfo object is much more complex now.  It has all it's own crud/dataportal code.  If it just uses the Invoice object that dataportal stuff is kept down. If the schema of the Invoice data changes then only one object would have to change.  Which is the point of encapsulation.

 

 

SonOfPirate replied on Monday, October 30, 2006

A couple of key points.  First, you provide a good explanation of exactly how something such as an InvoiceInfo class is intended to work.  And, second, you provide a good example of how confusing the data-driven versus behavior-driven model can be to developers.

Using the example you provided, I agree that you would have three classes defined in your object model: Address, AddressCollection and AddressDirectory.  However, to completely implement, you would also need a fourth class: AddressInfo.  In addition, there would be no AddressDirectory table in your database as this is unnecessary (and any DBA would have fits with it).  There is no one-to-one relationship between the structure of your data (in the database) and the structure of your classes (in your object model).  Just because you want an AddressDirectory object does not mean that you need a corresponding table in your DB.  Let me explain (and hopefully you'll see how this parallels the Invoice scenario we were discussing earlier):

Your AddressCollection class will be a read-write collection of Address objects which provide read-write access to the Address data and encapsulates the behavior of an Address.  As you stated, the Address has no idea who they belong to or what kind of address it is (e.g. billing, shipping, etc.).  Presumably you'll have a Customer object that has an Address property of type Address and that's how it all fits together at that level.

But you want a list of addresses with all of the related information for searching and listing - I assume.  This is your AddressDirectory class - as you've stated.  Where things deviate is that this class is actually another collection class (read-only) containing the new AddressInfo objects.  AddressInfo is a read-only class that contains the results of the joins you mentioned.  So, the Company, Person or Organization (as you listed) would be part of the AddressInfo class.  It is the responsibility of this class to present the data for each directory entry.  It is the responsibility of the AddressDirectory class to present the contents of the directory - the collection of directory entries.  Both of these would be read-only and the contents generated based on the query you mentioned in your database that performs all of the requisite joins, etc. to generate the appropriate resultset.  I tend to use Views for this type of thing, but that's a preference.

So, as you can see, there is not a one-to-one relationship between the AddressDirectory class and your database,so your assertion that the data leads itself to the object model is not entirely accurate in a behavior-driven model.

The case of the InvoiceInfo class will be along similar lines.  Instead of having a heirarchical structure where the Invoice class holds a reference to the Customer object, the InvoiceInfo class may have a Customer property with the customer's name returned as a string value.

This leads to the question about data access and who has it, etc.  Because the Invoice and InvoiceInfo classes (and likewise the Address and AddressInfo) classes are using data differently, they will need different data access procedures.  Again, the Invoice object may get a reference to the customer via the foreign key held in the Invoice table whereas the InvoiceInfo gets the string name of the customer because a join was performed in the database to flatten the data model.  Because of this, you can't have shared data access.

Oh, one more thing.  The statement that you have an AddressRegistrator object whose responsibility it is to add addresses to the directory should have raised a red flag to you as this is an overlapping responsibility and causes redundant data, etc.  Using the model described above, you can have normalized data in your database and a complete object model for your code.  Your AddressDirectory remains robust and in sync because it is generated right from the source data - the same data that is being managed by your Address and AddressCollection classes.

This is a terrific example to work through because it does highlight the struggle many of us have gone through trying to rationalize how to approach things from a behavioral basis rather than being data-centric in our designs.  I, for one, struggled with this for a while and fought with the notions of encapsulation and inheritance versus what Rocky was evangelizing until I was able to alter my perspective to understand that encapsulation and inheritance still have their place within this approach.  I just needed to better understand and define these terms and when they are and aren't appropriate.

Hope all of that helps.

 

pelinville replied on Monday, October 30, 2006

SonOfPirate:

A couple of key points.  First, you provide a good explanation of exactly how something such as an InvoiceInfo class is intended to work.  And, second, you provide a good example of how confusing the data-driven versus behavior-driven model can be to developers.
Using the example you provided, I agree that you would have three classes defined in your object model: Address, AddressCollection and AddressDirectory.  However, to completely implement, you would also need a fourth class: AddressInfo.  In addition, there would be no AddressDirectory table in your database as this is unnecessary (and any DBA would have fits with it).  There is no one-to-one relationship between the structure of your data (in the database) and the structure of your classes (in your object model).  Just because you want an AddressDirectory object does not mean that you need a corresponding table in your DB.  Let me explain (and hopefully you'll see how this parallels the Invoice scenario we were discussing earlier):
Your AddressCollection class will be a read-write collection of Address objects which provide read-write access to the Address data and encapsulates the behavior of an Address.  As you stated, the Address has no idea who they belong to or what kind of address it is (e.g. billing, shipping, etc.).  Presumably you'll have a Customer object that has an Address property of type Address and that's how it all fits together at that level.
But you want a list of addresses with all of the related information for searching and listing - I assume.  This is your AddressDirectory class - as you've stated.  Where things deviate is that this class is actually another collection class (read-only) containing the new AddressInfo objects.  AddressInfo is a read-only class that contains the results of the joins you mentioned.  So, the Company, Person or Organization (as you listed) would be part of the AddressInfo class.  It is the responsibility of this class to present the data for each directory entry.  It is the responsibility of the AddressDirectory class to present the contents of the directory - the collection of directory entries.  Both of these would be read-only and the contents generated based on the query you mentioned in your database that performs all of the requisite joins, etc. to generate the appropriate resultset.  I tend to use Views for this type of thing, but that's a preference.
So, as you can see, there is not a one-to-one relationship between the AddressDirectory class and your database,so your assertion that the data leads itself to the object model is not entirely accurate in a behavior-driven model.
The case of the InvoiceInfo class will be along similar lines.  Instead of having a heirarchical structure where the Invoice class holds a reference to the Customer object, the InvoiceInfo class may have a Customer property with the customer's name returned as a string value.
This leads to the question about data access and who has it, etc.  Because the Invoice and InvoiceInfo classes (and likewise the Address and AddressInfo) classes are using data differently, they will need different data access procedures.  Again, the Invoice object may get a reference to the customer via the foreign key held in the Invoice table whereas the InvoiceInfo gets the string name of the customer because a join was performed in the database to flatten the data model.  Because of this, you can't have shared data access.
Oh, one more thing.  The statement that you have an AddressRegistrator object whose responsibility it is to add addresses to the directory should have raised a red flag to you as this is an overlapping responsibility and causes redundant data, etc.  Using the model described above, you can have normalized data in your database and a complete object model for your code.  Your AddressDirectory remains robust and in sync because it is generated right from the source data - the same data that is being managed by your Address and AddressCollection classes.
This is a terrific example to work through because it does highlight the struggle many of us have gone through trying to rationalize how to approach things from a behavioral basis rather than being data-centric in our designs.  I, for one, struggled with this for a while and fought with the notions of encapsulation and inheritance versus what Rocky was evangelizing until I was able to alter my perspective to understand that encapsulation and inheritance still have their place within this approach.  I just needed to better understand and define these terms and when they are and aren't appropriate.
Hope all of that helps.
 
It does help but I think you are missing a something.
 
I want to assume there is no data source. None, not even a flat text file exists.
 
(I do have to store the info encapsulated by the objects in a database at some point. This is a separate issue handled by a separate logical tier. (And btw, I am the data guy also. Yes, I do argue with myself alot.)
 CSLA does not care in the least that their is no datasource.
 
This goes to what I said earlier.  That just knowing there is a data source does alter the thought process and design of my objects.*
 
As to the AddressRegistrator/AddressDirectory classes.
 
First it really isn’t redundant data.  The AddressDirectory is not a “List of Address Objects and their related objects”. It is a list of information provided by People, Companies and Organizations that is published to the world. The class might be misnamed. But it is misnamed because I knew I could get the data from a place outside the objects. It is supposed to be like a phone book.
 
Even before my change all I did was join the Address table with the other tables to produce a collection of strings. The collection can sort the strings and find a string for a given criteria but that is all it does and that is all the use case called for. It is not the AddressDirectory responsibility to be up to date and or accurate. It did assume this responsiblity, poorly, when I violated encapsulation and retrieved the address data indirectly from the objects. So I created another class, AddressRegistrator, to take that responsiblity over.
 
The problem arises when there is no longer that data store to get this information from (and to a lesser extent store it to).
 
Now what do you do?
 
You said use an AddressInfo object. That would mean I would have to load every Customer, Person and Organization. Then load every address for each of those. Remember there is no data source, only objects are available.
 
This is the subtle but important (at least I think so) point.  The solution you suggested to me assumes that there is a place I can get the data (breaking encapsulation btw) and create the objects needed for the AddressDirectory class to function. But there is no data source for my current situation.  Realizing this forced me to admit that I was breaking some very basic OO principles to begin with.
 
Don’t get me wrong, I don’t have all the answers. I don’t even know all the questions at this point.
 
*In the end this has to be done if a data store of some type is used. I want to stress I am no purist. I am a Mort through and through. And I have no problem with using the powerful functionality of a database to make things both easier and more efficient.  And if I have to bend (or even break) the rules of OOD/OOP to get something to work, I will with only a bit of hesitation. In fact I am admittedly still confused about some of the OO principles and rules put forth by the intelligentsia. But I get paid when I quickly produce something useful for our customers and they could care less whether I conformed to good object design. So be it.
 
 

SonOfPirate replied on Monday, October 30, 2006

I agree with you on one point but at the same time disagree with you. - that being the data-centric approach behind CSLA limiting you to database back-ends.  I agree that the BO's created using CSLA are designed to make use of a back-end data store. However, I referred to it as a "data store" on purpose because there is nothing that says it has to be a database, for one, and as Rocky does point out in the book, you can bypass the data access portions by simply not using them.

I don't like the latter approach, but it is there.  And, I should preface this by saying that we use our own framework which is based heavily on CSLA but not exactly Rocky's implementation.

For us, data agnosticity (?) was critical.  This is evident by an application we released just this past Friday which is driven exclusively by XML files - no database.  But our framework allows our BO's to exist in EXACTLY the same form and fashion as if the data was coming from a database.  Why?  Because we didn't care about the data store when we designed the objects.  Should the customer decide six months from now that their explicit requirements to have the data maintainable in a simple-to-edit file format that doesn't require a DBA, all we have to do is flip a switch in the config file and the application will start running on top of a database.

So, this is where I continue to disagree with you.  The data model does not have to affect the object model.  I agree that in many cases it does.  But, that's because the developer allows it to happen.  The whole point of abstraction is to separate the two and if you find yourself altering your object model to suit your back-end data store, then there's a red flag that something's not kosher.  Approach your design as if all of your objects are being created and populated via code. This will ensure that whatever providers you implement to create and populate your objects will be able to do so whether they are database providers like SqlClient, serializers or some other adapter such as what you will have to develop to transform the data contained in your heirchical object model into your flat AddressDirectory class.  Point is that AddressDirectory shouldn't care where the data came from, only what to do with it - it's responsability.

That was the point behind Rocky's very lengthy discussion in the book of where to put the data access code.  Yes, one can say that managing an object's data interface is a responsibility and should be handled by a separate object and there is quite a bit on that in the book.  Rocky made the choice, and I agree with it, that this is a secondary responsibility and to achieve mobil objects, we would rather have the benefit of encapsulation that worry about splitting this out.  Although, you will find several design patterns suggesting this is a bad approach.

But, even with this, in reality, we are delegating the actual responsibility of managing the data interface to objects like the DataReader.  All our BO's are doing is telling them how to do their job.  The BO doesn't really know how to do it, and, with a totally agnostic design, it doesn't even really know "who" is doing it.

I know I am drifting away from your particular case, but I think it would be worthwhile for you to keep the possibility that you could be database driven in the future in your mind when approaching your design.  Make your AddressDirectory class  a "shell" so to speak that makes use of other objects to populate it with data from whatever source you are using.  If that is the role your AddressRegistrator class is intended to serve, then you are probably on the right track.  As long as the AddressDirectory class doesn't have any knowledge of or require the AddressRegistrator class to do its job.

Hope that helps.

 

ajj3085 replied on Monday, October 30, 2006

pelinville:
While loosely coupled is a design goal for the system it is not really a consideration for the object design itself.  In fact encapsulation is one of the primary concerns of object design. Objects do not care if they are loosely coupled, only the system does.


I know I'm nitpicking here, but I don't think this is correct.  The system doesn't care at all about being loosely coupled either.  The idea behind OO is to build maintainable systems.  Decoupling allows us to build those maintainable systems.  So if we don't have to maintain an application, then couple all you want, it doesn't matter how you put it together at all, as long as it works.

But to build the maintainable system, each class must be decoupled as much as is feasible for the implementation.  The decoupling is what makes the whole thing more maintainable.  We can safely change a class and know it won't have a ripple effect on other classes.

pelinville:
This is what I was trying to explain before. Data stores, no matter they be xml files, RDBMS's or whatever, really do defeat one of the primary and most basic of object thinking. Encapsulation.


This is true.  But we don't really have a better way to store data.  In OO, if one object of a class changes state, other objects of that class likely don't change.    This is a problem though if that change does need to be carried around to all instances which had similar state.. for example, changing the name of a country... it really should be 'picked up' by all other instances which have that same country name. 

Rocky acknowledges that we're breaking encapsulation... which is why using the DP is a good idea.  At least we know the data access code is in one well despot.  Its not scattered throughout the app.
  This is the best option we have now... realistically, we need some way for the object to trigger an event that will cause it to be persisted after the application shuts down.  Even if you moved all the data access somewhere else, at some point something somewhere is going to have to persisit the state, correct?

pelinville:
Ideally the data of the Invoice is only controlled by the Invoice. No other object has access to that data unless the Invoice object gives it permission.  Having the IvoiceInfo object (or whatever) get it's data from the data store bypasses the whole concept of encapsulation.


Not so.  Imagine a company where one department generates invoices.  Its not that departments responsibility to mark invoices as paid, as that's the accounts receivables department's job.  If the AR department changes how it deals with marking invoices paid (or doing whatever they do with invoices), we don't want to change the code at all for the invoicing department.  That code is tested already, we know it works.  Having one class means not only do we have to test the code the AR department relies on, we have to test the code invoicing relies on.  Which means we have more chances to introduce bugs into the system.  Again, we're trying to build maintainable systems that can adapt to change.  Which do you think is more maintainable?  One super class that knows every behavior an invoice must perform, or several smaller classes which do one thing and one thing well? 

pelinville:
But In the pure object world there is no database.


Says who?  Why can't we have objects and databases?  Because they don't map one to one?  Why not just have an object that ONLY knows how to map between the db and objects?

pelinville:
I can't just get all the addresses because that would mean creating an address object for each address that existed.


So what?  If your really need all your addresses in one shot, you have to store the data somehow, right? 

pelinville:
Not only that but because the AddressDirectory also needs to know who (company, person, organization) the address is for, and Address objects have no idea who they belong to,   So in reality I would have to load all the Company, Person and Organization objects then get their AddressCol objects to create the AddressDirectory.


Sounds more to me like you have some bad design somewhere.  What exactly are you trying to acomplish?  Do you really need all the addresses at once?  Does sound likely to me..

pelinville:
So what I have ended up doing is creating a AdressRegistrator object. When a Company etc. adds or changes an address it adds its information to the AddressDirectory. (It really is just a list of strings.)

Now the database is kinda out of wack.  The DB guy hates the idea of having a table that contains this "Address Directory" data because the two can go out of sync. It is just asking for abuse. So what I am doing is having a table with a single row and I am serializing the AddressDirectory to a blob. Ugly but I don't think those using the DB will try and use a big ol blob to extract data from.

Again, sounds like bad design.  In the database world (where you are not worried about objects), you don't store the same data twice... and this out of sync problem is exactly one good reason as to why you don't do that.

pelinville:
What I am trying to say is that if you use a DB you do let data define your objects even if you don't realize it.  Looking back it was always stupid of me to just pull the address and people names in a join to populate the AddressDirectory. Stupid from an OO perspective anyway.


It can be hard to avoid that trap, yes.  But if you're doing a good OO design you won't.  The object will need to do something.  It will only have the data elements it needs to carry out that function.  If there's more data (such as address info or invioce info) that it could get, but doesn't need, then it won't show up in your object design.

I have a contact object that makes three tables (not counting a bunch of lookup tables) appear as one object.  Why?  From the business case, it is just one object.  On the DB side though, its most efficient to store it in different tables.

pelinville:
So going back to the InvoiceInfo object.  Having it load it's data from a data store is not good oo practice. It works fine until you have to do something like I am doing.


If you want a maintanable system, it works well.  As I said though, if the loading of InvoiceInfo and Invoice is idential, than there should be an InvoiceData object which knows how to fetch the data.   What exactly are you doing that the InvoiceInfo abosolutely cannot load its own data?  This thread has given you several ways to have an InvoiceInfo load from other places besides the db (including the InvoiceData class).

pelinville:
And I don't see what advantage their is in creating an InvoiceInfo object over creating a Invoice object and using it in the InvoiceInfo object. Even in the most complex of editable business objects it's creation can't be more than a couple of cpu cycles more than creating a InvoiceInfo object.


No one here can tell you the answer for sure, because it really does depend on your use case.   

pelinville:
Plus the InvoiceInfo object is much more complex now.  It has all it's own crud/dataportal code.  If it just uses the Invoice object that dataportal stuff is kept down. If the schema of the Invoice data changes then only one object would have to change.  Which is the point of encapsulation.


That's the thing; your breaking encapsulation in another spot.  Encapsulation means that InvoiceInfo shouldn't know anything about the internals of Invoice and visa versa.  What you are trying to achieve is code reuse, which is better acomplished by creating an InvoiceData class which BOTH InvoiceInfo and Invoice can use.  Having an Invoice directly create and populate InvoiceInfo may break encapsulation.

Again though, your exact solution depends on your use cases.   If you need InvoiceInfo without being able to first create an invoice, you'll be in trouble.  If not, you're fine.  If you just need to print an invoice which isn't saved, then your InvoicePrinter class should know how to print an Invoice object; why waste resources creating InvoiceInfo just to give to the InvoicePrinter class?

pelinville replied on Monday, October 30, 2006

ajj3085:
pelinville:
While loosely coupled is a design goal for the system it is not really a consideration for the object design itself.  In fact encapsulation is one of the primary concerns of object design. Objects do not care if they are loosely coupled, only the system does.


I know I'm nitpicking here, but I don't think this is correct.  The system doesn't care at all about being loosely coupled either.  The idea behind OO is to build maintainable systems.  Decoupling allows us to build those maintainable systems.  So if we don't have to maintain an application, then couple all you want, it doesn't matter how you put it together at all, as long as it works.

But to build the maintainable system, each class must be decoupled as much as is feasible for the implementation.  The decoupling is what makes the whole thing more maintainable.  We can safely change a class and know it won't have a ripple effect on other classes.

 

No, you are right.

ajj3085:
pelinville:
This is what I was trying to explain before. Data stores, no matter they be xml files, RDBMS's or whatever, really do defeat one of the primary and most basic of object thinking. Encapsulation.


This is true.  But we don't really have a better way to store data.  In OO, if one object of a class changes state, other objects of that class likely don't change.    This is a problem though if that change does need to be carried around to all instances which had similar state.. for example, changing the name of a country... it really should be 'picked up' by all other instances which have that same country name. 

Rocky acknowledges that we're breaking encapsulation... which is why using the DP is a good idea.  At least we know the data access code is in one well despot.  Its not scattered throughout the app.
  This is the best option we have now... realistically, we need some way for the object to trigger an event that will cause it to be persisted after the application shuts down.  Even if you moved all the data access somewhere else, at some point something somewhere is going to have to persisit the state, correct?

 

For this case, shouldn’t there only be one instance of “Country” that has that particular value?  That way if Country.Name is changed then all things that use Country would automagically get the change.

 

Now whether a Country object or a string field CountryName is used is an important question. A question that isn’t always easy to answer.  (Country is a bad example but I am sure everybody gets the idea.)

 

I agree with what you are saying in that there isn’t a better way to store data if the goal is to have that data shared among many users. But there are alternatives.  (One coming up would be the transactional file system of Avalon and simply saving objects as files.)



ajj3085:
pelinville:
Ideally the data of the Invoice is only controlled by the Invoice. No other object has access to that data unless the Invoice object gives it permission.  Having the IvoiceInfo object (or whatever) get it's data from the data store bypasses the whole concept of encapsulation.


Not so.  Imagine a company where one department generates invoices.  Its not that departments responsibility to mark invoices as paid, as that's the accounts receivables department's job.  If the AR department changes how it deals with marking invoices paid (or doing whatever they do with invoices), we don't want to change the code at all for the invoicing department.  That code is tested already, we know it works.  Having one class means not only do we have to test the code the AR department relies on, we have to test the code invoicing relies on.  Which means we have more chances to introduce bugs into the system.  Again, we're trying to build maintainable systems that can adapt to change.  Which do you think is more maintainable?  One super class that knows every behavior an invoice must perform, or several smaller classes which do one thing and one thing well? 

 

Not if there is an InvoicePayment object. InvoicePayment MAY not be apart of the Invoice at all. InvoicePayment would probably use Invoice to do whatever it needed to do. I can’t see why invoice would need to ever know if it had been paid or not. And still Invoice is the only one that has direct access to its data.

ajj3085:
pelinville:
But In the pure object world there is no database.


Says who?  Why can't we have objects and databases?  Because they don't map one to one?  Why not just have an object that ONLY knows how to map between the db and objects?

 

I never said we couldn’t have objects and databases. I said in the “pure object world” (which admittedly is a fantasy for most applications) there are no databases. Pure being the key word.

ajj3085:
pelinville:
I can't just get all the addresses because that would mean creating an address object for each address that existed.


So what?  If your really need all your addresses in one shot, you have to store the data somehow, right? 

pelinville:
Not only that but because the AddressDirectory also needs to know who (company, person, organization) the address is for, and Address objects have no idea who they belong to,   So in reality I would have to load all the Company, Person and Organization objects then get their AddressCol objects to create the AddressDirectory.


Sounds more to me like you have some bad design somewhere.  What exactly are you trying to acomplish?  Do you really need all the addresses at once?  Does sound likely to me.

 

pelinville:
So what I have ended up doing is creating a AdressRegistrator object. When a Company etc. adds or changes an address it adds its information to the AddressDirectory. (It really is just a list of strings.)

Now the database is kinda out of wack.  The DB guy hates the idea of having a table that contains this "Address Directory" data because the two can go out of sync. It is just asking for abuse. So what I am doing is having a table with a single row and I am serializing the AddressDirectory to a blob. Ugly but I don't think those using the DB will try and use a big ol blob to extract data from.

Again, sounds like bad design.  In the database world (where you are not worried about objects), you don't store the same data twice... and this out of sync problem is exactly one good reason as to why you don't do that.

 

You are correct that is was bad design.  The first thing that should have tipped me off was that I was violating encapsulation. The AddressDirectory object was directly accessing the Address, Customer, Person and Organization objects data without asking their opinion about the matter.

 

But because the AddressDirectory needed the Customer and the Address data, I couldn’t just load a bunch of address objects (Which is trivial to get from the OO db, btw.) and then populate the data structure.

 

So a compromise has to be made some place (I am the DB guy).  At this point I am compromising the Database design instead of the object design.

ajj3085:
pelinville:
What I am trying to say is that if you use a DB you do let data define your objects even if you don't realize it.  Looking back it was always stupid of me to just pull the address and people names in a join to populate the AddressDirectory. Stupid from an OO perspective anyway.


It can be hard to avoid that trap, yes.  But if you're doing a good OO design you won't.  The object will need to do something.  It will only have the data elements it needs to carry out that function.  If there's more data (such as address info or invioce info) that it could get, but doesn't need, then it won't show up in your object design.

I have a contact object that makes three tables (not counting a bunch of lookup tables) appear as one object.  Why?  From the business case, it is just one object.  On the DB side though, its most efficient to store it in different tables.

 

I should have said “You might be letting the data side define your objects”.

 

Another example.  I have a Section that has a CourseNumber. (Section is a class like “8th grade math”.  The CourseNumber is a simple string like “4001”).  But really the section doesn’t have a CourseNumber, it contains a Course object that has the CourseNumber field.

 

In the first place I don’t think the Section.CourseNumber should really even exist.  I only put it there to make data binding easier. Even worse I set the CourseNumber during the DataPortal_Fetch by using a join between the Section and Course tables.

 

I think the most I should do is have a field called CoursesUID and return Course.CourseNumber.

 

At one time I thought about having a SectionListing object that joined the various tables (Session, Course, Instructor etc) but rejected it.  Instead I created a SectionListing and use the Session, Course and Instructor to make the SectionListing class.


ajj3085:
pelinville:
So going back to the InvoiceInfo object.  Having it load it's data from a data store is not good oo practice. It works fine until you have to do something like I am doing.


If you want a maintanable system, it works well.  As I said though, if the loading of InvoiceInfo and Invoice is idential, than there should be an InvoiceData object which knows how to fetch the data.   What exactly are you doing that the InvoiceInfo abosolutely cannot load its own data?  This thread has given you several ways to have an InvoiceInfo load from other places besides the db (including the InvoiceData class).

 

I am developing a click-once application that can run both connected and disconnected from the database.  I cannot install any software on the client outside the framework itself.  It must work with the current classes with minimal modifications.

 

We don’t want to put copies of tables (e.g. pure xml or saved datasets) on the client for various reasons but we do want to synchronize the changes when the user does connect to the database.

 

What looks to be my best bet so far is an object oriented database.  The only problems I am running into are like the ones described in this thread where I have violated encapsulation.

 

So far they are all easy to fix and the fixes have turned out to be better anyway. I am still not completely sold on this approach but it does look promising.

ajj3085:
pelinville:
And I don't see what advantage their is in creating an InvoiceInfo object over creating a Invoice object and using it in the InvoiceInfo object. Even in the most complex of editable business objects it's creation can't be more than a couple of cpu cycles more than creating a InvoiceInfo object.


No one here can tell you the answer for sure, because it really does depend on your use case. 
  

ajj3085:
pelinville:
Plus the InvoiceInfo object is much more complex now.  It has all it's own crud/dataportal code.  If it just uses the Invoice object that dataportal stuff is kept down. If the schema of the Invoice data changes then only one object would have to change.  Which is the point of encapsulation.


That's the thing; your breaking encapsulation in another spot.  Encapsulation means that InvoiceInfo shouldn't know anything about the internals of Invoice and visa versa.  What you are trying to achieve is code reuse, which is better acomplished by creating an InvoiceData class which BOTH InvoiceInfo and Invoice can use.  Having an Invoice directly create and populate InvoiceInfo may break encapsulation.

Again though, your exact solution depends on your use cases.   If you need InvoiceInfo without being able to first create an invoice, you'll be in trouble.  If not, you're fine.  If you just need to print an invoice which isn't saved, then your InvoicePrinter class should know how to print an Invoice object; why waste resources creating InvoiceInfo just to give to the InvoicePrinter class?

 

InvoiceInfo is not created by Invoice.  It is a class that takes an Invoice, Customer, Address etc. and flattens out the data for printing.  This still maintains encapsulation.  At no time does InvoiceInfo need to know how Invoice, Customer or Address work. I admit that if the fields exposed by any of the used classes are removed you have a problem. But that would cause problems in many other parts of the application anyway.

 

I still have a problem and that is the business logic.  Example: At my old job Invoices had a rule that if the total was between 4.95 and -4.95 then the total returned was zero. If an InvoiceInfo object is created from the database that logic has to be maintained in two places.

 

You have an interesting idea in having a bunch of XXXData objects. That is basically how ORM works, right?  I have also thought about each object having a collection of name value entries to represent its data. One problem I have with either of these is it seems I would have to give up the luxury of data binding. Also with business logic. Should it reside in the XXXData object?

 

At any rate thank you for the input. It has helped me see what I need to do and forced me to further develop my early ideas.

 

malloc1024 replied on Monday, October 30, 2006

I believe the traditional way to approach the invoice formatting problem is to use the strategy pattern inside an Invoice class to format an invoice.  This allows you to format an invoice in many different ways without having to change any code inside the Invoice class.  The strategy pattern might not be appropriate for all invoice formatting problems, but it can help in many.  The two sites listed below also suggest using the strategy pattern to format an invoice. 

 

http://www.csis.gvsu.edu/~tao/CS621/Proj4%20-%20Inovice%20Management.htm

http://cse.yeditepe.edu.tr/~taytekin/cse349-2005-Fall/slides/Ch5/Ch5.html

 

ajj3085 replied on Monday, October 30, 2006

Right, that is likely a valid method also, although I would think the actual formatters should live in the UI layer... How something is formatted is irrelevent to the business logic.

malloc1024 replied on Wednesday, October 25, 2006

A responsibility is a reason to change.  If the class has more than one reason to change it has more than one responsibly.  The single-responsibility principle is a fundamental principle that states that a class should only have one reason to change.  An example that violates this principle is placing your persistence logic in your business classes.  Doing so gives your class two reasons to change and thus violates the principle.

pelinville replied on Wednesday, October 25, 2006

 
ajj3085:
Typically yes, that's what you would do.  Printing the invoice being edited would likely make use of the edtiable business object, although you have to think about things like 'can the user print an invoice not in a valid state?'  Eitehr way though, the UI uses the business object (editable or not) to create the report, but the invoice object doesn't know (or care) about what is done with it.  It is only concerned that its state is valid and providing a way to query about its state.

What you do in a scenario depends on your exact use case however.  You build classes to satsify the requirements of a use case.  If your next use case can reuse those objects (meaning that the use case has some behaviors in common) then you can do it.  If not, you may have to build another object which operations on the same data but does something different with it.

Disconnected is a whole other issue, that doesn't have much to do with Csla.  For example, how do you save an invoice if you aren't connected to the database?  Those are seperate issues from Csla.

I understand what you are saying but I don't understand.... something.

I am asking this because our first release is now stable and I now have time to clean up some crappy code I wrote during the "crunch time" (AKA re-factoring time!!!)

Add to that I am finally really looking deep into object databases.  (I am using it to allow the application to work off-line.)

Two things I keep hearing over and over just don't ring true to me.

 

1. Objects are defined by their behavior, not data.

 

This is easy to say when the data is easy to get from just about any where. But after using an object database for a bit you quickly see that objects are, in part, defined by their data.

Think about it.  Think about your application with no traditional database.  Think about having an application that is always "ON".  If there is no "database", no place where the raw data is stored, then what object has what data becomes very important. (And what class holds what type of data is also.) If you can't just go to some mythical place and load phonenumber with id xxxx then how do you get the phone number?

It isn't really that surprising when you stop and think about it.  But due to the power of relational databases we never stop and think about it.

Which brings me to..

 

2. Objects are defined by their behavior, not their data.

 

From a different perspective I don't think people are really doing this.  Take the example that was mentioned above.

"InvoiceInfo object would know how to get it's data".  And where exactly does the data live?  In the Invoice, of course!  But that is not what that sentence meant.  It meant that the data is not apart of the application at all.  That the data is someplace else and not apart of any object. 

 

What this leads to is that the database is an integral part of the application. With business lines of application the database becomes 50% or more of the application.

 

I don't think I am saying this correctly. It sounds like I am criticizing something.  I am not.

 

Hmmm

 

I think what I am trying to say is that when you say "objects are defined by behavior not data" you are making an assumption that something else is taking care of the data.

 

When you can not assume that, your view points changes, radically.

 

I am starting to see ever more clearly what David West was talking about. Kinda. Now I have to read that book, yet again.

 

 

dean replied on Thursday, October 26, 2006

pelinville,

I had to clean up my own code and upgrade to 2.1 recently. This is a project that originated in VB6, then went net 1.0, net 1.5, and now 21. When doing so I looked hard at my biggest classes (lots of properties) and the ones that I new were kinda hacked to get certain functionality. By hacked I meant anytime I was getting away from the basic CSLA/Project tracker type structure.

In some instances I couldn't/didtn't want to change the code but usually I found that refactoring into other classes and encapulsating them into my "big" classes cleaned things up. In some instances upon reflection I saw that I was intertwining UI and BO responsibilities and that moving the code out of the bo and into the UI it would simplify. I would occasionally create a UI class to manipulate the bus objects to make presentation easier.

When going thru this process I would keep the rules in mind: one object, one responsibility, keep UI code out of BO, double check use cases for accuracy. These would tend to push me towards more objects, but better organized and simpler objects.

My two cents...

Dean

Copyright (c) Marimer LLC