Design help

Design help

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


ajj3085 posted on Friday, February 08, 2008

Hi,

I have a new feature I'm trying to implement.  Nothing too extraordinary, but if implemented wrong I'll end up with a maintenance nightmare.

My quoting system supports revising documents (quotes, orders, etc).  Basically, before  a document can be printed or sent to a customer (or our internal fulfillment area), it must be locked so that no more changes are allowed.  This functionality exists.  If the document needs to be changed, the user can choose Revise, which executes a database comment that takes a snapshot of the documnt as is, and then updates the IsLocked flag.  The snapshot is copied to another table, DocumentHistory, and all child tables of Document also has a history.  These are populated as well.  Users can lock and revise as many times as they like, until the document is finally closed (closing implies locking) when no changes can ever be made to the document again.

The users would like a way to view the old version of the document.  Nothing more, no rollback feature, nothing.  My current thinking is to make the existing Quote, Order, etc. classes smart enough to be able to load a revision.  Locking takes care of the no-edit requirement, and I could add a flag indicating that the instance is not the current version, which would prevent some other actions (like converting the obsoleted version to an order, for example). 

This is by far the easiest way to implement this functionality, since I just need minor changes to the business classes and UI as well.  I could even abstract out things in the DataPortal so that the object doesn't need to know for the most part that its getting data from say DocumentHistory instead of the Document table.  At least that's part of my plan..

Of course the other alternative is a whole new set of classes, containing almost identical code.  But this would be 100% safe, since I could change the two sets of classes and not break functionality. 

So.. should I choose the easier route for now, and if requirements later dictate I create a new set of clases for this use case, then do that work when its needed, or should I start off with a new set of classes?

Thanks
Andy

webjedi replied on Friday, February 08, 2008

Personally I would create the new classes.  My thoughts behind it are that while they are similar in structure, they serve different purposes, one is to actively conduct business and do something, while the other is a snapshot in time and for reference only.  And in my limited experience one object that tries to do two different things usually is a trap.

Ryan

ajj3085 replied on Friday, February 08, 2008

I agree, it does smell like a trap, which is why I posted.

To play devils advocate to you though, all the functionality is there.. its soley a matter of "where is the data coming from."  The document classes and the shared LineItem subclasses already support a view only notion (which is their Locked state).

Seperate classes also means creating two new classes for every one behavior.. that is I would need a SubTotalLineItem and then a SubTotalLineItemInfo, for example.  Thus doubling the amount of work needed whenever a new type of line item (or document) is added.

Therein lies my delima; on one hand, if the "current" and "revision" items share the same behavior (except revisions are permantely in a locked state), seperate classes means twice as much work duing maintenance. 

If though I reuse and tweak the existing classes, maintenance can also suffer if the behaviors start to deverge too much.  Although part of me thinks this is unlikely; a SubTotal should always work the same as a SubTotalInfo, except that latter is permantely locked.  The same can be said for the others, like PackingFeeLineItems.  The fee rate may change (and this is stored in the database, so that future changes don't mess up history), but what the fee applies to shouldn't.  (If it does, I have a whole other can of worms..)

webjedi replied on Friday, February 08, 2008

Is it too simplistic to suggest deriving "revision" from "current" and overriding the authorizations so that nobody has CanDeleteObject and CanEditObject?

Then theoretically your maintance should be simpler.

Ryan

JoeFallon1 replied on Friday, February 08, 2008

I have used Inheritance in situations like this. In the derived class I have all of the normal properties plus one extra property which is used internally to handle the modifications. I also override the DataPortal_Fetch code to select the data from a different source than the "standard" object.

Joe

 

ajj3085 replied on Friday, February 08, 2008

That's actually not too bad of an idea.  I still have to create two classes for each line item type, but the duplicate code should be minimal in that case. 

praevsky replied on Friday, February 08, 2008

I haven't actually done this myself, but it's on the schedule.  My concept is to report off of an auditing system.  Tables of interest are shadowed by auditing tables.  Triggers on insert, update and delete populate the auditing system.  What appeals to me is that all the changes are captured by the auditing system, and you don't do anything to your business classes.  An even bigger plus is that it's at sourceforge.  http://sourceforge.net/projects/sqlaudit

Copyright (c) Marimer LLC