For Programmers: Free Programming Magazines  


Home > Archive > C# > August 2004 > Best Practices for Checking Prerequisites









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Best Practices for Checking Prerequisites
Mario T. Lanza

2004-08-26, 4:05 pm

Greetings,

I've been reviewing the code for software that I've been working on
for a couple years. I'm looking at some of the situations that I've
come across and deciding what I can learn from them and how I can best
handle similar situations in the future.

Since I am sure that my situation is a familiar one to many of you, I
am wondering what practices many of you have formed over the years.
Perhaps there is even a published best pattern/practice for my
scenerio.

Here it is:

I have certain methods that users direct my software to call in order
to perform certain business-specific tasks. To avoid speaking in
generalities, I'll provide a specific example.

My software allows tellers (like bank tellers) to transact with
customers (as one would do at a bank or a supermarket). At the
beginning of the day when a teller reports to work he must assign
himself a cash drawer over which cash contents he will be held
entirely accountable. My software has methods that correspond to the
actions a teller may take over the course of a day's business. Two
that come immediately to mind are 1) the assigning of a drawer and 2)
the unassigning of a drawer. Let's focus on the latter for now:
Unassigning a drawer.

My .NET C# code has a method: UnassignDrawer(DrawerData.DrawerRow
drawer)

Imagine also that my application has a button entitled "Unassign
Drawer" (it could have just as well been a menu option in addition to
or instead of). When the user clicks this button, the application
calls the UnassignDrawer method.

Now, understand that the drawer unassignment process has a number of
prerequisites. Before a drawer may be unassigned the teller must
have:

1. Deposited all his checks (using another method that flags his
checks as deposited)
2. Audited (counted out) the cash in his drawer (by denomination so
that database may track the exact count of each cash/coin
denomination)
3. Closed out any two-sided transactions (as a banker would first do a
withdrawal transaction and then a second deposit transaction to
transfer funds between accounts as part of one larger overall
transaction)
....
....
.... (etc.)

The number of procedural steps in unimportant. What is important is
that there may be any number of business-related prerequisites that
the teller must meet before unassigning the drawer.

As part of my method UnassignDrawer method I have another method
entitled AllowUnassignDrawer(DrawerData.DrawerRow drawer). This
method is called early within the UnassignDrawer method. If the
prerequisites have not been met, the teller is alerted (with a list)
as to the actions he must take in order for the unassignment to be
allowed.

An interesting question I've asked myself is this: Do I disable the
"Unassign Drawer" button until the prerequisites have been met? If I
do, then I will have to call the AllowUnassignDrawer method as the
state of the application (the requisite conditions) changes in order
to enable/disable the button. Whenever the prerequisites are checked
there is overhead associated with querying the database. Even if this
overhead takes only 3 seconds to check the multiple conditions, it
seems wise to query the database as infrequently as possible.
Futhermore, since I have to call the AllowUnassignDrawer method in
order to disable/enable the button and then call it again from within
the UnassignDrawer method itself (as a safegaurd against allowing the
drawer to be unassigned if the button is ever inadvertently enabled
when it should not have been), it seems that it may be necessary to
call the AllowUnassignDrawer method twice.

Presently, I leave the "Unassign Drawer" button enabled (so long as
the teller has a drawer assigned). Then when the teller clicks the
button, I report any failed prerequisites in a panel at the side of
the screen. The teller then performs the tasks to meet the
prerequisites before clicking the "Unassign Drawer" button again.

My thinking was:

If I go ahead and disable the button while the prerequisites are not
met then I must be responsible for calling the prerequiste checking
function (AllowUnassignDrawer) more frequently in order to maintain
the enable/disabled status (even if the user does not wish to unassign
the drawer). Conversely, when I call the prerequisite checking
function only when the user wishes to take the action, I alleviate the
overhead of maintaining the enabled/disabled status of the button.

Furthermore, by perpetually maintaining the button status I may
confuse the user who will wonder why he is unable to unassign his
drawer (because he cannot click the disabled "Unassign Drawer" button
in order to review the prerequisite checklist). If I choose to provide
some other option for reviewing the checklist, where would it best be
located? In my opinion, it would best be located as close to the
"Unassign Drawer" button as possible so that the user can easily
determine why the button is disabled in the first place.

The other issue with my AllowUnassignDrawer method is that it returns
a boolean value indicating whether or not the drawer may be
unassigned. Since the scenerio at hand deals with potentially
numerous prerequisites the one fact (the true/false response provided
by the AllowUnassignDrawer method) is insufficient. I need some other
output to communicate the various reasons (the failed prerequistes) to
the user. In my case, I invoke an event to display a filled out
checklist.

Since the AllowUnassignDrawer method doesn't return the checklist (it
invokes the event), the event listener (which is the application's
primary form itself) must then go ahead and build the checklist
thereby calling the database again for each of the prerequisite
conditions. Obviously, I could have built more elaborate event
argument/handler classes to communicate the checklist conditions
directly to the listener.

I'm not concerned at all with this specific example. I provided it
only as framework on which to more clearly communicate the issue at
hand.

In my case I have a method that facilitates a business task
(UnassignDrawer), a method that tests for permission to perform the
particular business task (AllowUnassignDrawer), and an event that is
subscribed to by the primary form in order to display the numerous
prerequisite conditions to the user (the user interface). This is one
design that evolved as the application evolved. It wasn't one that I
fully thought out and planned in advance. I make this post to
faciliate a discussion on the best practices/patterns surrounding the
handling of prerequisite conditions associated with specific business
tasks.

Your ideas and practical examples are appreciated.

Mario T. Lanza
Clarity Information Architecture, Inc.


NOTE:
Originally posted on comp.software.patterns.
Cross-posted because the example is C# specific and because of lack of
feedback on original newsgroup.
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com