Exforsys
+ Reply to Thread
Results 1 to 3 of 3

Best Practices for Checking Prerequisites

This is a discussion on Best Practices for Checking Prerequisites within the Software Patterns forums, part of the Testing category; Greetings, I've been reviewing the code for software that I've been working on for a couple years. I'm looking at ...

  1. #1
    Mario T. Lanza Guest

    Best Practices for Checking Prerequisites

    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.



  2. #2
    cstb Guest

    Re: Best Practices for Checking Prerequisites



    Mario T. Lanza wrote:

    .... snip ...

    > 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.


    Patterns: Observer (esp. MVC), Adapters, Checks

    Practice: Separation of concerns

    a)

    Build a complete and consistant model of the system.
    By "complete" is meant "has interfaces which allow
    all needed manipulations and/or which produce any and
    all data which is of interest to the outside world."
    By "consistant" is meant "every manipulation available
    through such an interface either succeeds (prereqs are
    met, invariants are maintained, change is applied, and
    any data provided to outside world from now on reflects
    the change), or fails (prereqs not met, changes not
    applied, any data provided to outside world remains
    as it was before the attempted manipulation)".

    b)

    When finished, attach Views and Controllers to it.

    If you have first accomplished (a), then (b) is nearly
    trivial. As an example, the notion of a button which
    is enabled only when all prereqs are met, becomes:

    Attach a controller which sends "releaseDrawer"
    whenever it is both enabled and pressed.

    Attach a view which observes the "drawerIsReleaseable"
    boolean, and which enables/disables the aforementioned
    controller (button) accordingly.

    Note that "drawerIsReleaseable" is a boolean maintained
    by the model. If you keep this in mind, you needn't
    "ask permission", you can instead "observe availability".
    This boolean *must* be changed (recalculated) whenever
    anything it depends on is changed -- it *can* be recalculated
    more often than this (such as every time a caller needs the
    current value) -- but it *must* be recalculated whenever it
    could actually change. You are free (as designer) to pick
    any frequency of update between these two extremes. Such
    choices affect "performance" and "usability", but not
    correctness. MVC allows one to optimize update frequency.

    Another question you can ask yourself is whether the
    "releaseDrawer" function is distinct, or just one of the
    subtasks the user must complete. Consider keeping a list
    of unfinished subtasks (in the model), each of which is
    enabled/disabled according to the current state of the model.
    Consider keeping the list sorted in "a proposed order", such
    that the "releaseDrawer" subtask is always last in the list.
    Attach controllers/views as before, observing this list.


    Regards,

    -cstb




  3. #3
    Mario T. Lanza Guest

    Re: Best Practices for Checking Prerequisites

    Thanks for your detailed response.

    Mario



    •    Sponsored Ads



Latest Article

Network Security Risk Assessment and Measurement

Read More...