http://www.perlmonks.org?node_id=231024


in reply to Re: Best Practices for Exception Handling
in thread Best Practices for Exception Handling

Java Boutique has an interesting article about exceptions that you might find useful.

What I like about exceptions is fairly straightforward. If I have a GUI (A) which issues a message to some object (B) which in turn sends a message requesting data from object (C), what happens if C determines that the data is bad due to user input (and not, say, a programming error)? There's probably no point in issuing a warning in the error log (because it's not an error from a programming standpoint) and there's no point in killing the application because a user typed something stupid (an all too common event, though).

In the above scenario, C throws in exception and B catches it. B then checks the exception to see if anything unusual needs to be done. If the exception is caused by failing to select a required option, no big deal. If the exception is caused by a bad password, perhaps it is a big deal. B can decide whether or not to log the exception and do further processing. B, at this point, rethrows the exception and A catches it. Because A is simply the GUI, A doesn't worry about logging the exception. A simply has to have some method of displaying the exception to the end user in a meaningful way.

Thus, with an exception based system, particularly if it's multi-tiered, you have full control of the error processing rather than simple die and warns. Further, uncaught exceptions will kill the program when encountered during execution, thus making them morely likely to be reported in testing and feedback -- which in turns means they are more likely to be handled appropriately and leads to more robust code.

Cheers,
Ovid

New address of my CGI Course.
Silence is Evil (feel free to copy and distribute widely - note copyright text)

Replies are listed 'Best First'.
Re: Best Practices for Exception Handling
by jonadab (Parson) on Jan 30, 2003 at 04:53 UTC
    > If I have a GUI (A) which issues a message to some object (B) which
    > in turn sends a message requesting data from object (C), what
    > happens if C determines that the data is bad due to user input

    See, that's where I always get lost. If C is getting user input, and the user input is invalid, C should just reget the user input. When it has valid input, it should pass that back to B. Otherwise, it should continue to ask the user to fix up the input.

    In a slightly different scenerio, C might think the input is okay (there's an integer in this integer field, and some text in this required text field; C does not know the meaning of these data, but they are the kind of data that were requested), but B might discover that it's inconsistent. (There is no thirty-first of February.) In that case, B would possibly explain the problem to the user and then call C again; only when the input is good enough for B to do its job does it then pass the result back to A.

    Do you see where I'm getting hung up? It's not with the question of HOW to pass stuff back to the parent (which was the original topic of the thread, I know), but more with the more basic question of why that is a thing that needs to be done. That's the point I haven't managed to understand yet.

     --jonadab

      jonadab wrote:

      If C is getting user input, and the user input is invalid, C should just reget the user input. When it has valid input, it should pass that back to B. Otherwise, it should continue to ask the user to fix up the input.

      I see your point, but I look at it differently. You want to decouple your functions. Your function that validates the data should do just that: validate the the data. Either the data is validated or it throws an exception which other portions of your program might handle differently. This function's role is not to acquire the data. If you do that, you have a less robust function as you're forcing it to do too much. You could conceivably get around this by passing the function an object that knows how to fetch data, based upon what type of object it is, but I still feel this is doing too much. Consider the following:

      
        +--------------+
        | presentation |
        +--------------+
               |
        +--------------+
        |   dispatch   |
        +--------------+
               |
        +----------------+
        | business rules |
        +----------------+
               |
        +--------------+
        |    db api    |
        +--------------+
               |
        +--------------+
        |   database   |
        +--------------+

      That might be the tiers of a multi-tiered system that allows each tier to be developed seperately and replaced, if necessary. Your data validation might be in the "business logic" tier or in your "database API" tier, depending upon your needs. How does something in one of those two tiers refetch the data? They then have to know about the dispatch and presentation layers -- that's not good. As much as possible, different layers should not be overly dependant on one another or changing something in one layer will affect the others and drive up maintenance costs.

      Instead, let's say that the validation (and I know this is not a great example) is in the database API layer. It does not know, nor does it care, why the validation fails. It just throws an exception. That exception is caught by the business logic layer and it determines if this is user error (they forgot to select from a menu), or something more serious (the third failed login attempt). At this point, the business logic layer can decide whether or not to log the error, rethrow the error, or do something entirely different. The dispatch layer might catch an error, if thrown, and send an error object to the presentation layer. The presentation layer is not going to want to handle the error the same way. It might simply say "bad username/password combination", while the business logic layer wants to know if someone is brute-forcing a login.

      In other words, exceptions allow you to decouple different portions of an application and allow each section to determine how to handle the exception. How this is handled will vary depending upon the layer, but it can help to ensure more robust applications by providing a mechanism by which we are more likely to spot problems and handle them where they should be handled.

      Hope that helps :)

      Cheers,
      Ovid

      New address of my CGI Course.
      Silence is Evil (feel free to copy and distribute widely - note copyright text)