Objects with large # of properties

Objects with large # of properties

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


SonOfPirate posted on Monday, February 19, 2007

I'm looking for suggestions/explanations about design approaches so that I can address and respond to the questions (and criticisms) I am taking over the object model design we are implementing for a current project.

We have a standard web app where we display a list of Projects in one page then allow editing of a single Project in another page.  To handle this, we have a ProjectList class of (read-only child) ProjectInfo objects for the list page and an editable root Project class for the second page.  We repeat this pattern with several objects.

The issue that I am facing is the result of the massive number of properties that we have in a number of our objects.  For instance, we have one class with more than 40 properties.  And all of these are duplicated in the editable root and read-only child objects.  If we need to make a change, we have to do it in two places.  This seems to fly in the face of OOP principals.

In anticipation of the questions, yes all of the properties are necessary and yes they must be in both classes.  The list that the user views is configurable.  In order to support this, we must expose all of the properties available for display.  This means all of them are in our read-only class as well as the editable root class.  Only difference is (besides read/write capability) all foreign-key references (object references) are resolved in the read-only child class.

What I am wondering is how others have handled the same situation?  The scrutiny I am facing is related to both OOP principals and change management.  Is there a better approach?

Thx.

 

pelinville replied on Monday, February 19, 2007

Do you use compostion?  What I mean is the ProjectInfo composed of a Project object?

SonOfPirate replied on Monday, February 19, 2007

No, for a few reasons.

One, to use composition we would still have to have a property defined in both objects for each contained property in order to expose it publicly - so nothing is gained there except encapsulation of any logic of which there is none for the most part as these are simple get/set properties.

Two, there are really no common behaviors between the objects.  One is used to edit the object while the other only displays the object in list form.  The editable root object contains all business logic, such as authorization and validation rules none of which is necessary in our readonly child object.

Three, the goal of the read-only child ProjectInfo object is to have a "lightweight" (as Rocky put it) object to use when listing a number of objects.  If I was willing to incur the additional "weight" that comes from using the editable root Project object, then I would simply use this for both purposes and exchange code simplification for a more behavior-oriented design.

 

SonOfPirate replied on Monday, February 19, 2007

Andy,

Sorry about that, we obviously crossed posts...

I hadn't thought about using a "property bag" type design for the read-only child.  I'm not sure if this would lead to more problems then solutions as I agree that it complicates data-binding.  Right now we are using standard ASP.NET 2.0 controls via the CslaDataSource for our "lists".  I'm not sure how we'd accomplish this without true property names to specify in our bindings.

This is also a team development effort and having properties kept in a propery bag requires late binding  and no type checking, etc. during compilation which would make debug more complicated as well.  Rather than having the compiler throw an error when it comes across an attempt to access a property that doesn't exist, we now defer this kind of error detection to run-time testing.

I'm inclined to think that maybe the answer lies somewhere in between these suggestion in that we would have a ProjectProperties object that is used by both the Project and ProjectInfo classes following the composition suggestion.  This would allow us to centralize all of the business rules, etc. related to the properties but again, composition doesn't eliminate the need to make a single change in multiple places and this approach would mean we have three places to change (if we added a property, say) rather than two.  The benefit is that we would only have to change one if it was a logic change, like a business rule or something.

 

Brent Dunham replied on Monday, February 19, 2007

SonOfPirate,
 
Is there any need for all 40+ properties to be in the search result list? I would likely include only the properties realtive to the use case.
 
I introduced CSLA to my (soon to be ex) place of employment 3 to 4  years ago. I found many of the less OO knowledgable developers tended to want the framework to be something it wasn't. A magic bullet of sorts. I received a lot of challeges on this topic. Many wanted to define just one BO for each relational table and that BO would be used in all use cases,  etc. Don't get caught up in the idea that "there's only one Foo Db table so I should only need one Foo BO to work with it. ADO Orcas will come with the Entity Framework. This will bring some help to a lot of people with visualizing the purely conceptual. Acutally, it will help bring the purely conceptual itno something tangible.
 
Essentially, just because both the read only child and the editable root contain similar data or are views of the same relational object, doesn't mean that they should be the same object or contain the same object. Mapping to the same Entity object would make sense, but then again behaivor will dictate that.
 
Brent

SonOfPirate replied on Monday, February 19, 2007

Brent,

The read-only child object is used to support the use case when we need to display a list of items (Projects).  This object is not a one-to-one mapping of the back-end db table, in fact, it is quite the opposite and some use pretty involved sprocs and views to populate.  At its simplest, the read-only version will expose a text/string property where a foreign key reference exists in the database table and would possibly be represented by an object reference in our editable root BO.

The reason that we populate the read-only child object with all of the properties we do is to support the dynamic nature of the interface where we allow the user to turn on/off columns to tailor the UI to their liking (and needs).  To do this, our underlying BO to which we are binding the interface must expose all of the properties that the user may select from.  Realistically (and by default), only a handful of these columns are displayed, but they are all available if chosen.

 

Where my interest mainly lies is addressing what is required if we, let's say, added a "Mobile Phone" property to a Contact object or "Design Due Date" property to our Projects.  In order to accomplish this, I have to add the property to both the Project and ProjectInfo class (assuming it is to be exposed as an available field for the list).

However, after this discussion began, I realized that I am also interested in a couple of other aspects such as properties which are actually "derived" properties, such as a FullName property on a Contact that returns a composition of the Contact's FirstName, MiddleName and LastName properties based on a FileAs property which determines the format.  Do I repeat this logic in both classes or do I use some form of composition to encapsulate this into a common object shared by both the Contact and ContactInfo objects?

Or am I simply putting too much thought into this?

 

RockfordLhotka replied on Monday, February 19, 2007

You could be overthinking it a bit Wink [;)]

But the "normalization of behavior" concept dictates that the logic to create a FullName value should exist exactly one time in your code. Other objects that need such a value should collaborate with the one object that implements that behavior.

Of course in reality that behavior might be a static/Shared method somewhere, but the design concept is consistent. Big Smile [:D]

In terms of having objects with lots of properties - especially read-only objects, you might consider using ICustomTypeDescriptor. This is particularly useful if you know ahead of time which columns the user does want. Then you could pass the list of desired columns through in your criteria and only load the requested data. The object's shape would change (thanks to the interface) to match the selected values.

This only really works if your UI component is equally flexibile, which pretty much means the grid controls only.

SonOfPirate replied on Tuesday, February 20, 2007

Well, I'm not too familiar with ICustomTypeDescriptor so I'm not sure how that would fit into the mix and aleviate this situation.

Let me throw another scenario out there as an example where I am having trouble finding an appropriate (easy to implement and maintain and OOP sound) design:

In our application we have Accounts (customers with credit lines) and Contacts.  A Contact may or may not be associated with an Account but an Account does have a list of Contacts that are associated with it.  In our UI, we have two pages, AccountsList and ContactsList that display the full list of each type; therefore, I know we need a root collection of each type.  Because these are simply web page lists, these are read-only collections of read-only objects.  That gives me:

I also have pages to edit each object.  To support these, I need editable root objects for each type:

Now I also need to support displaying a list of Contacts that have been assigned to the displayed Account.  Plus, I have to be able to add/remove items to/from this collection but editing of the individual objects can be done via the same editable root object.  However, this is not a many-to-many relationship and adding a Contact to an Account means that the Contact's Account property should be updated to reflect the relationship.  So, I'm not so sure that this object can be read-only.

Anyway, my first inclination was to have these additional objects:

It appears that I will need both of these to be read-write in order to support adding/removing in the collection and the changes to the Contact's Account property as a result.

At first glance, I am now dealing with three separate forms of a Contact object.  They may have all or only a few properties in common, I'm not sure yet.  But, assuming that I need the majority of properties in all three cases, there is a lot of duplication and a maintenance nightmare if/when changes occur.

I'm thinking that maybe the AccountContact object should inherit the editable root Contact object (?), but that's just an initial thought.

This may be further complicated as additional objects are introduced with additional views required.  For instance, we will be adding a Project object into the application next which is directly related to an Account; however, the client has already indicated that they are going to want to be able to view the list of Contacts so that they may select which Contact applies to that Project.  This can be done via the Account object, but that would require us to instantiate that object as well as the parent Project object.  I'm thinking a ProjectContactList with the appropriate SQL would be a more efficient way to do this.  If so, then I'll end up with a ProjectContact object and yet another class with all the same properties defined.

Thoughts, recommendations and/or suggestions?

 

RockfordLhotka replied on Tuesday, February 20, 2007

Are you saying that everywhere the user can view data, they can edit that data? So everything is read-write everywhere?

SonOfPirate replied on Tuesday, February 20, 2007

Well, let me explain how I've been doing it and how I foresee implementing what I described and you tell me if I'm on the wrong page.

When I display the list of Accounts, I am binding a GridView to the read-only root collection, AccountList, which contains read-only child (lightweight) AccountInfo objects.  When a row is double-clicked, the item's unique identifier is passed to the subsequent page which displays the individual item with a FormView bound to the editable root Account object.

Much like ProjectResources in the ProjectTracker application, the editable form will also include a "subform" containing a GridView bound to the child AccountContactList collection of read-only child AccountContact objects.  A link is provided which will allow the user to create a new Contact directly from this form using the same page to create the object as was used before to edit one.

In the cases where there is a true parent-child relationship, such as a ContactAttachment, the object that is created is added to the parent's collection and persisted with the parent.  The Contact's child AttachmentCollection is populated with existing children with the parent and changes persisted to the database with the parent as well.  In this case, the ContactAttachment object is an editable child (inherited from AttachmentBase which is shared by all attachment objects) and the data portal methods are used to persist it when called upon by the parent.

The Account / Contact relationship is a bit different because a Contact can exist without the parent Account.  So, when a new Contact is created, it should be persisted to the database just as with any other root object, yes?  Then, if the parent Account was set, it should show up in the parent's list of Contacts when next viewed.

Imagining the use case where the user views the list of Accounts, opens an Account object for editing and while viewing the list of child Contacts elects to add a new Contact, the UI would include the necessary javascript to refresh the AccountEdit page when the ContactEdit page is closed. As a result, if the Contact was assigned to the Account being viewed, it would now show up in the list.

On the other hand, there is an implicit intent that the new Contact should be assigned to the open Account when the "add contact" link is selected, so perhaps it should be automatically set to the selected Account.

Either way, my hesitation with this solution is the extra round-trip to the database incurred to update the Account object after the new Contact is created (oh, or an existing one is modified).  The only way around this is to make the editable Contact an item in the Account's child collection so that it is persisted with the parent.

Then, tying this back to the original subject, there is the maintanance and debug related issues that stem from having ContactInfo, AccountContact and Contact objects presenting the same) or mostly the same) data.  Add the next step where we repeat most of this via a Project object and we'll have another, ProjectContact, object - perhaps.

Does it make sense to have all of these editable?  I could create an abstract ContactBase class defining all of the common properties and behaviors then derive the necessary classes described above.  I would lose the benefit of the lightweight, read-only objects for the various list views but perhaps this would simplify the object model - and have the added benefit of in-cell editing should I want to implement that later, eh?

I hope that explanation was clear enough to convey what I'm doing and highlight any areas of improvement.  I look forward to your critique.

 

SonOfPirate replied on Thursday, February 22, 2007

No thoughts/suggestions?  Esp. wrt abstract base class...

Plowking replied on Thursday, February 22, 2007

With the Account / Contact problem it's OK to have that extra database round trip after you create and persist the Contact object. You have accomplished a Use case "Add Contact", so a fetch trip to update the Account is not such a heavy penalty, I feel.

Justin replied on Friday, February 23, 2007

We have been struggling with this in our design using CSLA. We made what I consider a mistake by trying to stick with the object per use case in our current project(not using CSLA) and the maintenence is a real problem. This becomes even more of an issue if you really try and stick to separating the BL from the presentation layer (as we have) that is preached so heavly today, as you need to modify the presenation when adding a new property as well. If we need to add a new property there are no less than 4 places that this change needs to be made because of the standard way most of our entities are represented.

You will never get away from this issue completely though, there are definetly certain situation that call for a specific representation of an entitiy, but in our app design we have been able to reduce it down to two common representations that you see in the XxxInfo and Xxx pattern in the CSLA examples. That is an abbreviated version used usually for read only representations where performance is important such as search results and the full version used  used to fully read and edit a single entity.

From our R&D there are two ways to reduce the maintenance overhead of changing business entities schemas when using an OO design. Both require a central schema that has provisions adjusted by the designer to delineat what properties are to be in the abbreviated view.

#1 Use code generators to examine a core object source code and some metadata and generate the abbreviated view and perhaps readonly versions of the entity. A variation on this would be making a one off schema language (probably in xml) and use it to create the core object as well.

#2 Always use the core class with the ability to partially load the properties in abbreviated "mode" then be able to fully load or demand load the other properties later on. Same with read only being a runtime property of the core object and enforced as more of a business rule than simply no setters in a normal read only object.

We choose #2 for its runtime flexibility, for instance being able to display search results for an entity and when you open the specific entity it simply takes the object from the collection and tell it to fully load, then if you are allowed to edit it can switch from read only to editable and the be saved and there is only one class to maintain. BTW we use attributes for the metadata to decribe which properties are part of the abbreviated load. Currently we still have separate criteria objects for finding objects that usually mirror properties on the core object(but are looking into query by example to forego these). 

We already have the first version of a product out using this design and already we are seeing amazing productivity benifits to centralizing the entity design and are even looking into writing the class first then having a code generator make the database tables eliminating that maintence step as well.

I am sure there are those who would disagree with this design, but it has proven itself to us and significanlty reduces those things which I think CSLA tries to address anyway which is to centralize business object design so it is architected once not over and over again in different tiers with different technologies.

jhoojharsinghyadav replied on Thursday, October 11, 2007

Hello Son of pirate ,

read your issue . i am also dealing with such kind of scenario .where
i do have a readonlylist form of invoices .
the user clicks addnew button and a new form is being avaialable to add new invoice .unlike the project tracker , the identity column is being maintained by the database itself not front end.

the add new invoice form button then allow user to enter the invoice details via a form view which is binded to the invoice base class , the form view also do contain a grid view and few textboxes with add button .
the user enter the invoice line items details in the textboxes and pushes the add button  , the line items are then added to the editablechildcollection of invoiceline items . and the grid is databinded again to that child collection . so no  round trip to database , just an post back occur on server .

now the user pusshes save to save the object , and it gets saved as the object is new it works fine .

but coming over in update mode , the user dont change the invoice(parent object)  but do changes the invoicelineitems and pusshes save . here on root.save the root is not found dirty so the child is also not saved .

can any one throw some light to resolve this issue.

thanks
govind

JoeFallon1 replied on Thursday, October 11, 2007

 the user dont change the invoice(parent object)  but do changes the invoicelineitems and pusshes save . here on root.save the root is not found dirty so the child is also not saved .

can any one throw some light to resolve this issue.
=================================================================

The book clearly states that a Root object with editable children needs to override both IsValid and IsDirty (in the Root) so that the state of the child objects is also taken in to account.

Joe

 

ajj3085 replied on Monday, February 19, 2007

Hey Pirate,

I'm not sure if the situation 'flies in the face of OOP principals.'  You have two use cases, and each one needs to expose the data to the UI.

There may be something you can do to help with the read-only object; perhaps you can have a ProjectInfo and expose a ProjectInfoProperties which allows the UI to enumerate over all the properties (perhaps with type information). 

You could have a void GetValue<T>( string propName, out T val ) method to get the actual property value.  I suggest T so that your object can verify that propName is actually of type T, and you can do a shortcut when you call the method... eg GetValue( "ProjectStart", out startDateTime ).  The compiler doesn't require you to specify <T> in that case, because it can be infered from the second parameter.

Now, you won't be able to databind easily anymore.. perhaps you can build a class to properly setup your grid or whatnot to allow databinding again (using Reflection.Emit)... but it would save you from changing the API of the read-ony class.

You may be able to do this with the edtiable class as well.. although I'm not sure how much effort it will require to keep the Csla features you want.

david.wendelken replied on Monday, February 26, 2007

SonOfPirate:

The issue that I am facing is the result of the massive number of properties that we have in a number of our objects.  For instance, we have one class with more than 40 properties.  And all of these are duplicated in the editable root and read-only child objects.  If we need to make a change, we have to do it in two places.  This seems to fly in the face of OOP principals.

Gosh, in the olden days, we would have just put the common code in a COBOL CopyBook and included it in both code assemblies.  The compiler was smart enough to grab the text in the copybook, slap it into the file being compiled, and produce a result.

Isn't there some way to do something this simple in C#.Net or VB.Net?

 

Copyright (c) Marimer LLC