Exception/Error Handling, An Integral Part of Programming

Exception handling is an essential part of the programming experience, it polishes the application and is a bulwark against somewhat forgivable oversight. We most likely will not cover every situation in the first build of an application but at least we can include the ability to handle unforeseen runtime exceptions and build some useful tools utilising exception systems to help with the application development process.

CUSTOM EXCEPTIONS
=================

Custom built exceptions are a handy tool for both release and development versions of an application. They can be used in the following ways:

Custom Exceptions as Developer Warnings
---------------------------------------

We can use exceptions to remind us of not providing requisite information to a class or object. For example: We build a class as an interface to multiple vendor databases, let's call it Multiple Vendor Management (MVM) class. To connect to a particular database we perforce provide the instantiated MVM class with the vendor database type we are connecting to via a database_type method within the class. The MVM class also has a SQL_select method that can be called to return a recordset from our chosen vendor database. Within the SQL_select method is a switch (select case) statement which decides how to send the 'select request' to our chosen database type. If we fail to provide the vendor database type to our class and call the SQL_select method at runtime or a debug compilation, a default (case else) option within our switch (select case) statement throws a custom exception for developers. The custom exception will remind a developer during runtime testing that the requirements of the class have not been fulfilled during our coding. Below is an example of where our custom exception can be used:

Private Sub SQL_select(SQL As String)

dim exp_developer_1 as RuntimeException
exp_developer_1 = new RuntimeException
exp_developer_1.Message = "'database_type' property is not set."
exp_developer_1.ErrorNumber = -90000

dim rs As RecordSet

select case database_type

case MySQL_DATABASE
if Connect_mysql then
rs = mysql.SQLSelect(SQL)
end if // Connect_mysql

case ODBC_DATABASE
if Connect_odbc then
rs = odbcdb.SQLSelect(SQL)
end if // Connect_odbc

case REAL_DATABASE
if connect_rbdb then
// replace any instance of the word DISTINCT with UNIQUE to cater for RBDB syntax.
SQL = Replace_passed_regex_strings(SQL,"sDISTINCTs"," UNIQUE ")
rs = rbdb.SQLSelect(SQL)
end if // Connect_rbdb

case else
Raise exp_developer_1

end select

Exception err

d=New MessageDialog
if err = exp_developer_1 then
d.Set_Icon_Caution_Triangle
else
d.Set_Icon_Stop
end if

d.ActionButton.Caption = "OK"

#if TargetWin32 or TargetLinux Then
//ERR_MODULE is a constant that holds the module's/form's name + a full stop
d.Title = ERR_MODULE + "SQL_select"

if err = exp_db_error then
d.Message = d.ERROR_NUMBER_TEXT + cstr(exp_db_error.ErrorNumber) + _
EndOfLine + d.ERROR_DESCRIPTION_TEXT + exp_db_error.Message 'message
else

d.Message = d.ERROR_NUMBER_TEXT + cstr(err.ErrorNumber) + _
EndOfLine + d.ERROR_DESCRIPTION_TEXT + err.message 'message
end if
#else

//ERR_MODULE is a constant that holds the module's/form's name + a full stop
d.Message = d.ERROR_ROUTINE_TEXT + ERR_MODULE + "SQL_select" + EndOfLine if err = exp_db_error then
d.Message = d.Message + d.ERROR_NUMBER_TEXT +
cstr(exp_db_error.ErrorNumber) + _
EndOfLine + d.ERROR_DESCRIPTION_TEXT + exp_db_error.message 'message else

d.Message = d.Message + d.ERROR_NUMBER_TEXT + cstr(err.ErrorNumber) + _
EndOfLine + d.ERROR_DESCRIPTION_TEXT + err.message 'message
end if
#endif

d.AlternateActionButton.Caption = "Details to Clipboard"
d.AlternateActionButton.Visible = True
b=d.ShowModal

Select case b
case d.ActionButton
case d.AlternateActionButton
d.Details_to_clipboard

case d.CancelButton
end select

finally
// clean up
if d<>Nil then d=Nil
return rs
End Sub

Custom Exceptions used for Call Stack Retrocession
--------------------------------------------------

A custom exception could be used to create a call stack (http://en.wikipedia.org/wiki/Call_stack) break out scenario. For example, we have an application that is six calls down a call stack of database transaction routines and a critical data error has occurred. Instead of handling the exception, exiting the routine and allowing the parent routine to continue processing it's database transactions we use a custom exception to roll back all calls within the call stack and their transactions. We throw the custom exception within the current routine whose exception handler rolls back our current routine's database transactions and then throws the custom exception again within the exception handling section of our routine's code. The exception handler in our current routine cannot handle the newly thrown custom exception so transfers control back up the call stack to the previous routine. The previous routine handles the custom exception in the same way, and so on until we reach the top of the stack, having rolled back all routines' database transactions. The initiating routine of the stack can then report the exception or, the routine that caught the first exception could report the exception (see heading Exception Notification Detail further on in article for why we would do this) and then start the retrocession of the stack.

Custom Exception Generics
--------------------------

Custom exceptions do not need to be specific in their reporting detail, they are custom built so we can change their messages to better fit the circumstance in which we want to throw the exception. For instance, say we have a custom database exception:

dim exp_db_error as RuntimeException
exp_db_error.number = -10001
exp_db_error.message = "Database file can not be found."

We raise this exception within a routine where the database file is found but is corrupt, we can change the message to better fit the circumstance of the exception:

exp_db_error.message = "Database file is corrupt."
Raise exp_db_error

The exception number relates to database specific issues but the message the user receives is more relevant to the situation than a generic exception message.

EXCEPTION NOTIFICATION DETAIL
=============================

Details provided in exception notifications perforce should be useful to both the developer and the end user. A basic exception-type number and description is usually too vague or concise to be of use to either party. What good is an exception notification that states:

Exp No: 4026
Exp Desc: Index out of bounds

An exception notification needs to provide two types of useful information, diagnosis information for the developer or the vendor of the application and explanatory information for the end user or the the vendor's client. Useful details to provide can be:

  • Routine name. The name of the routine in which the exception occurred.
  • Line number. If available the code line number or last declared line number when the exception occurred. This can really help pin point the line of code the exception occurred within.
  • Class or module name. This helps locate the code that threw the exception.
  • Call stack: This can be useful to trace the series of events prior to the exception.
  • Active controls or forms: The current active control and/or form which could give a clue as to what the user was trying to do when the exception occurred, although the call stack could cover this instead.
  • Source of the exception: Perhaps the exception was caused by an application interactivity or interoperability.
  • Time of the exception: Maybe the user went to lunch before reporting the exception. It may help to know that when the exception occurred there was a concurrent hiatus of intranet connectivity.
  • User explanation: An explanation for the user on how the exception impacts their ability to carry out their tasks. It probably is not necessary to confuse the user with exactly what went wrong, just that the application can not perform their task at the present time.

    HANDLING HIDDEN ASSUMPTIONS
    ===========================

    As a rule I put exception handling into almost every routine to neutralise the spectre of the hidden assumption. I am currently working with a business process diagramming application in which there are scripted reports. One particularly critical report every now and then can not complete it's processing, this is a legacy report which has code that makes inadequate use of exception handling. Every time the report stops I diagnose the problem as missing Lane symbol names within the diagram the report is trying to process. The developer who had scripted the report mistakenly assumed that there would always be a name attributed to a Lane symbol, but when a user forgets to enter a Lane symbol's name, the report stalls and has no way to handle the exception that is thrown. The hidden assumption is: A Lane symbol has a name property therefore there is a name value available within that property. Of course the developer and client most likely tested the report against well formed diagrams before releasing the first build so the exception was never thrown during testing. This is not really any party's fault but the result of human fallibility that has not been catered for by utilising exception handling.

    EXCEPTION LISTENER
    ==================

    Instead of building a central exception handler to provide exception notification or central exception reporting we could create an class that captures exceptions and performs functions based upon the type of exceptions it receives. One function might be to capture exceptions into a collection and provide advice to calling routines as to what kinds of services the application can provide the user at any one time, for example: We have an application that accesses several diverse data sources which upon start up fails to connect to one of it's data sources and throws an exception. The exception is handled and passed to the Exception Listener. From now on any event that opens a form can call the Exception Listener to see if any details the form provides the user are inaccessible and as a result can disable controls that allow the editing or reading of those details. The latter scenario would allow the user to still perform some duties although in a limited way, which is better than not allowing the user to do any work and may still enable the user to finish their work tasks with the limited functionality provided. When I say limited functionality we could be speaking of only a minor disruption to functionality overall.

    Another benefit of an Exception Listener could be the ability to periodically check the collection of exceptions it holds and try to resolve the original cause of the exceptions. In the example above where our application could not access a data source, the Exception Listener could thread a retry of the connection whilst the application is running and upon a successful connection notify it's clients of the availability of details from the data source again and remove the exception from the collection. This is better than the user having to save what they are doing, close the application and reopen it to reconnect to a previously inaccessible data source.

    If our Exception Listener was a software bus it could publish any messages to it's subscribers within the application and we could have a real-time release of limited functionality within forms, web pages and other interfaces.

    Statistical Analysis of Application Functionality
    -------------------------------------------------

    Statistical analysis of the amount of functionality that can be provided by an application can also be published by the Exception Listener where a missing data source may be determined to reduce the application's functionality by 25%. The user can be notified that the application is only 75% functional which would be useful information in a unstable environment. The percentage of functionality would rise or fall based upon exception resolution and exceptions thrown respectively.

    Exception Cluster Explanation
    -----------------------------

    With a collection of exceptions within the Exception Listener we could abstract out a comprehensive explanation of what an application's current capabilities and limitations are by diagnosing clusters of various exceptions and/or exception types. When a user tries to perform a task and receives an exception the notification of the exception could provide the ability to open an explanation dialogue instead of only providing the ability to dismiss the exception notification. The Exception Listener could provide a comprehensive report upon current application limitations that are producing current system behaviour. For example, even though our application may have successfully connected to an Account system we cannot retrieve a staff member's salary transactions because our application cannot access the necessary employee identification details on a Human Resources system that is offline. Throwing an exception that informs the user that an accounts routine can not perform its task does not explain why this has happened and the user will most likely contact the help desk for the explanation, whereas a comprehensive explanation from the Exception Listener which explains the effects of a Human Resources system being offline could instantly explain why the accounts routine is failing the user.

    SUMMARY
    =======

    Exception handling is an integral and sometimes unappreciated part of any programming regimen. Points covered were:

  • Custom exceptions help with the development process using custom developer exceptions to remind developers of missed requirements during coding.
  • Custom exceptions can retrocede through a call stack and rollback prior transactions and processes.
  • Exceptions can handle the scripting of our hidden assumptions.
  • Exception Listeners can provide the ability to limit services within an application allowing the user to perform tasks albeit some functionality will be disabled.
  • Exception Listeners can provide comprehensive explanations of limited application behaviour and the possible cause of thrown exceptions.
  • Exception Listeners can provide a statistical percentage of application functionality.
  • Exception Listeners can periodically try to resolve earlier exceptions that reduce a system's functionality.
  • Exception notifications can provide enough detail for a developer or vendor to pinpoint the cause of an exception in code whilst concurrently providing a useful explanation to assuage user anxiety over an exception.

    Duane Hennessy - EzineArticles Expert Author

    Duane Hennessy
    Senior Software Engineer and Systems Architect
    Bandicoot Software
    Tropical Queensland, Australia
    (ABN: 33 682 969 957)

    Your own personal library of code snippets.
    http://www.bandicootsoftware.com.au

    Moderator of http://groups.yahoo.com/group/AccessDevelopers