Interaction between Use Cases and similar objects

Interaction between Use Cases and similar objects

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


Brad posted on Thursday, May 03, 2007

Greetings,

I have a situation where I am torn on how to use two different (but similar) business objects.
The first use case is to list a set of "User" objects. I've implemented this by created a read only list (UserInfoList) and a read only object (UserInfo) that retrieves some data. The second use case is to edit a "user" object (User). For this, I have created a editable business object.

The UI interaction is as follows: I open the "User List" view. A list of read-only "UserInfo" objects are displayed. I select a row, and the id of the UserInfo object is used to populate an editable "User" object - which is displayed in a dialog. I then change some settings on the "User" object via the UI, and press the button which saves my changes and returns back to the "user list" view.

My dilemma is that I need to update the "user list" view - which is what is displayed after the user closes the "Edit a User" dialog (specifically one "UserInfo" object) with the potentially changed data. Now when I close the dialog, I know which user has been updated - and in fact I just happen to have all the data I need. However, my UserInfoList object controls the "get" of the data for the UserInfo objects.

So, do I take the hit to the db to get the entire list of UserInfo objects (which is the cleanest conceptually, but slowest and requires both a hit to the db and a lot of data to bring over the wire); vs take the hit to update the one business object (and break the design of the UserInfoList and UserInfo objects for the sake of a speed increase of less data over the wire); vs just update the object in memory (which seems to break the design of the CSLA business objects, but is very fast).

Any thoughts?

Cheers,
-Brad

joshpainter replied on Thursday, May 03, 2007

Rambling idea off the top of my head:

On your read-only UserInfo object, add internal setters to the properties.

Create an instance method on your User object called something like ToUserInfo(UserInfo userInfo).  Inside this method, update the passed-in userInfo's properties with the current User object's properties.

Back in your UI, after the form is closed simply pass the selected UserInfo into the just-edited User object's ToUserInfo.  Databinding should update your list!

SonOfPirate replied on Thursday, May 03, 2007

Seems to me that you've got three options:

  1. Refresh the whole list, as you've said. This would be the most commonly used approach.
  2. Implement some hybrid way of updating the read-only object with the editable object used in the form as was suggested about.  I don't like the sounds of this one as it sounds unnecessarily complex.
  3. Convert your list to a read-only collection of editable objects. Cache the collection in memory. When you open the data entry form, retrieve the object from the collection using the passed Guid value - this means that both the list and the form reference the same object.  When the form closes, simply re-bind your list to the original collection without making a round-trip to the database and the item will update to reflect the change.

Option 3 works if caching the list in memory is reasonable and the application isn't multi-user because you'll never see changes resulting from the actions of other users unless you make round-trips to the database.  If it is a multi-user app, then #1 is still the best option despite the possible performance impact.

HTH

 

joshpainter replied on Friday, May 04, 2007

Excellent points.  The best solution, as always, depends on the use case.  If the editable User objects are relatively light-weight and there will be a relatively small number of them in the list, I think having a read-only collection of editable User objects would be a great solution.  Instead of using a guid value on the edit form to look up the object in the cached collection though, I'd just say pass in the whole User object to the edit form since you already have a reference to it in the UI list control.  That edit form would update the object and the parent form's list control would be updated dynamically behind the form.

However, if the user objects are "heavy" with lots of properties, children, collections, etc. and/or there will be LOTS of user records then I still like option 2.  I think of a read-only object not necessarily as just an object with read-only properties.  I think of it more as an object that can only be fetched from the data portal, but after that it can still change its state or be modified by another process or behavior (usually internal).  Also, by keeping the property setters internal, you don't expose them to the UI developer to play with.  Just look at ToUserInfo() as another behavior exposed by User; in this case User imprints itself onto an existing UserInfo object by using the internal property setters.  To take advantage of this, the UI just asks the just-edited User object to imprint itself on a reference to a UserInfo item in its list control.

I'm not sure I consider refreshing the whole list after an edit to a single user *normally* part of the use case of "editing a user," even for a multi-user app.  I understand that other users may be making changes to other items in the list, but that's what a refresh button at the top is for, yes? :) Again, I'd say this would depend on the specific use case here, especially dealing with user load and the possibility of several users working on the list at once.  However, I might just be being argumentative because I really shouldn't be worried about performance of refreshing the whole list after each edit; after all, your application either has a smallish number of users, in which case your hardware is more than likely way over-powered anyway, or you have a HUGE number of concurrent users editing this list in which case not only is performance a concern, but you probably need to modify your use case significantly anyway to handle all the multi-user editing, such as timed refreshes or change notifications of some sort.  It seems rare to be forced in between those scenarios after analyzing the cost/benefits of how the UI will actually be used.

SonOfPirate replied on Friday, May 04, 2007

joshpainter:

Excellent points.  The best solution, as always, depends on the use case.  If the editable User objects are relatively light-weight and there will be a relatively small number of them in the list, I think having a read-only collection of editable User objects would be a great solution.  Instead of using a guid value on the edit form to look up the object in the cached collection though, I'd just say pass in the whole User object to the edit form since you already have a reference to it in the UI list control.  That edit form would update the object and the parent form's list control would be updated dynamically behind the form.

Very true. This is not an approach I have used very much but you are correct that passing the actual object would make more sense if it is cached in memory.

joshpainter:

However, if the user objects are "heavy" with lots of properties, children, collections, etc. and/or there will be LOTS of user records then I still like option 2.  I think of a read-only object not necessarily as just an object with read-only properties.  I think of it more as an object that can only be fetched from the data portal, but after that it can still change its state or be modified by another process or behavior (usually internal).  Also, by keeping the property setters internal, you don't expose them to the UI developer to play with.  Just look at ToUserInfo() as another behavior exposed by User; in this case User imprints itself onto an existing UserInfo object by using the internal property setters.  To take advantage of this, the UI just asks the just-edited User object to imprint itself on a reference to a UserInfo item in its list control.

Keep in mind that allowing the user to edit the item in the list (via a DataGridView or whatever) would also require the list to contain editable items.  So, this is not an unusual way to go.  Again, depends on the use-case.  But, yes, the heavier the object, the more overhead you will incur.

The issue I have with this option is that you are either a) putting the UI in charge of maintaining and updating your objects or b) coupling the User and UserInfo objects together so that the latter is updated by the former when changes are applied.  Not saying this is wrong or bad, just not something I've personnaly done and doesn't give me the "warm and fuzzies."

joshpainter:

I'm not sure I consider refreshing the whole list after an edit to a single user *normally* part of the use case of "editing a user," even for a multi-user app.  I understand that other users may be making changes to other items in the list, but that's what a refresh button at the top is for, yes? :) Again, I'd say this would depend on the specific use case here, especially dealing with user load and the possibility of several users working on the list at once.  However, I might just be being argumentative because I really shouldn't be worried about performance of refreshing the whole list after each edit; after all, your application either has a smallish number of users, in which case your hardware is more than likely way over-powered anyway, or you have a HUGE number of concurrent users editing this list in which case not only is performance a concern, but you probably need to modify your use case significantly anyway to handle all the multi-user editing, such as timed refreshes or change notifications of some sort.  It seems rare to be forced in between those scenarios after analyzing the cost/benefits of how the UI will actually be used.

It sounds like you are making the assumption that this is a Windows application.  That has not been specified.  There is no such thing as change notifications to update the UI in Web apps.  And, if that is the case (which I also assume it is not), this discussion is mute because the list will always be updated as a natural part of the process anyway - unless the app uses multiple browser windows such as my last big project.

Furthermore, in a distributed, multi-user environment, there is no way to know if another user has made changes in the database except to refresh the data you have locally.  I don't know if was ever acceptable to display a list and allow the user to edit an object only to notify them of a conflict AFTER they perform all of their work and try to save.  While this is inevitable, for it to be the only option went out of style...well, I can think back at least ten years ago when my clients were having issues with it.

Again, all of this goes back to the use cases.  The first being Windows vs. Web app.  If Windows, the next is stand-alone or multi-user.  If a stand-alone Windows app, then the refresh issue isn't an issue and I'd go with having the list bound to a read-only collection of editable objects and have your form bind to the actual object.  If it's an MDI, memory consumption could increase if you have multiple lists available but an SDI app should have no problem.

One other option to consider and the path I had to take in a recent app that had to provide pseudo-realtime monitoring capability. This was a multi-user app in a truly distributed environment (multiple facilities, not just systems) with users in various locations and roles making changes to the underlying data all the time.  The way I handled ensuring that the data being viewed on the "administrative" or "monitoring" interfaces stayed current was to add smart refresh capability to my business lists.  By this I mean that I added a Refresh method to the class that was called by the UI at regular timed intervals.  This method performed a call through the data portal to retrieve a current copy of the data which by the very nature of the data portal was returned in a new collection object.  The refresh method then iterated through the collection and updated the existing collection with changes to the objects.  For example, if a record that is contained in the existing collection came back from the db marked as deleted, it was likewise deleted from the local copy.  Property changes were applied using reflection and since all property setters are wrapped with an if (existingValue != newValue) condition, only actual changes were applied and PropertyChanged events raised.

By tweaking the interval, we were able to achieve the affect of a real-time app in such an environment.  Of course it wasn't truly real-time, but close enough to satisfy the customer who could bring up the app and just sit back and watch as other users performed their jobs and the data worked its way through their systems.

Anyway, that was done like everything else described here, to satisfy a particular use-case.  So to go back to my original statement, you need to clarify your use cases and I think the answers will come to you.

Good luck.  HTH

 

joshpainter replied on Friday, May 04, 2007

SonOfPirate:

The issue I have with this option is that you are either a) putting the UI in charge of maintaining and updating your objects or b) coupling the User and UserInfo objects together so that the latter is updated by the former when changes are applied.  Not saying this is wrong or bad, just not something I've personnaly done and doesn't give me the "warm and fuzzies."

This may be my own inexperience of what "UI in charge" means, but I feel like the UI is already "in charge" of calling the load/save methods, popping up forms, etc.  Seems like another behavior of the UI would be invalidating a list item after an edit form has been closed since it could have changed.  Or invalidating the whole list and refreshing it as has been suggested.

As far as coupling the objects together, you could easily have another helper class that had a single responsibility of updating a UserInfo object with properties from the User object.  That way the two objects don't "know" about each other if that is your goal.

SonOfPirate:

It sounds like you are making the assumption that this is a Windows application.  That has not been specified.  There is no such thing as change notifications to update the UI in Web apps.  And, if that is the case (which I also assume it is not), this discussion is mute because the list will always be updated as a natural part of the process anyway - unless the app uses multiple browser windows such as my last big project.

Woops! I certainly was making that assumption. I've been working on a WinForms project recently and immediately went into "how would I do this on my project" mode.  However, with Ajax on the scene, the point may not necessarily be moot. :)

SonOfPirate:

Furthermore, in a distributed, multi-user environment, there is no way to know if another user has made changes in the database except to refresh the data you have locally.  I don't know if was ever acceptable to display a list and allow the user to edit an object only to notify them of a conflict AFTER they perform all of their work and try to save.  While this is inevitable, for it to be the only option went out of style...well, I can think back at least ten years ago when my clients were having issues with it.

I think we are disconnecting here...in option 2, the listcontrol would be bound to a Read-Only list of UserInfo objects, but when you double-click one, the selected guid would be passed to the Fetch static method of User, so it would load the latest data from the db.  Users wouldn't be editing out-of-date data, so the only conflict notification that the user would see is a normal concurrency violation where another user updated the same data AFTER they opened the form but before they saved.  So the only out-of-date data that the user would potentially see would be the read-only UserInfo objects.  But I think we've both hit upon the solution there...just use some sort of timer to update that read-only list of UserInfo objects if heavy multi-user editing is expected.

SonOfPirate:

Anyway, that was done like everything else described here, to satisfy a particular use-case.  So to go back to my original statement, you need to clarify your use cases and I think the answers will come to you.

Agreed.  Being architecture astronauts is fun, but give us more details! :)

Brad replied on Friday, May 04, 2007

Firstly, thank you both for a thoughtful discussion on this topic. It has provided me with some interesting ideas to think on.

 

Now, some more detail. Smile [:)] This is a multi-user windows application. This particular area of the application will not receive many data changes (more than likely this will be an administrative function, that is performed by one person at a time). The User objects are quite heavy (numerous properties and 4 child collections - 2 of which are computationally expensive). There are a number of other use cases which also feed off the list of user objects view: Delete a User, Add a User, Disable a User Account. There is a refresh button, which refreshes the list. At this stage, I'm expecting a few hundred users, but depending on some decisions to be made later, that could balloon into thousands.

 

Originally I thought this was a common pattern that would be used in numerous areas of the application. While this may still be the case, there are certainly variations based on a couple of keys facts (how "current" the data needs to be, and how heavy the editable objects are). One thing is for sure - I will need to carefully consider each (set of) use case(s).

 

Interestingly, the majority of the other use cases (Delete, Add, Refresh) all will retrieve the complete list of "current" users from the database. Maybe, from a UI consistency point of view, updating is the most logical action. It's certainly the easiest, and cleanest from a maintenance angle. However, I am tempted to try the ConvertUserToUserInfo idea (either by a static helper class, or public method on the User class). Carefully implemented (by using a memento pattern), it could potentially provide only a limited coupling. However, it is a coupling between business objects (and/or interfaces to business objects) and that does make me feel uneasy. Without proper control, it could get out of hand.

mr_lasseter replied on Saturday, May 05, 2007

In some of my apps I have the same senario.  What I do is use the observer pattern as well as event channels (I use the ActiveObjects Observer.dll http://csla.kozul.info/Documentation/Activecodev16/Observer/tabid/153/Default.aspx).  In my case, the ReadOnlyList is created and subscribes to any events published by the EditableObject.  In the EditableObject, Events are published in the either the update, insert, or delete functions (or any other events that I want respond to).  I don't use the data portal as I have stripped down CSLA to get the functionality that I want from it (mainly the validation), so I don't have to worry about serializtion/deserailization of the objects and trying to determine if the object was inserted/updated.

When an event is published the ReadOnlyList updates the item in the list that changed.  The ReadOnlyList does get a copy of the Editable object so there is some coupling involved, but I don't have a problem with this since the ReadOnlyList and the Editable Object actually represent the same thing.  In my mind there should be some coupling involved. 

joshpainter replied on Monday, May 07, 2007

Sounds like you have a plan.  One other interesting observation:  Microsoft's AD Users and Computers MMC snap-in does not refresh the whole user list after you double-click a user and edit the account.  It only refreshes the one item in the list after you close the window.  Looks like Microsoft made the cost/performance/benefit choice of not automatically refreshing the whole list for an obviously multi-user application for that specific use-case.

Copyright (c) Marimer LLC