Some information about exceptions in software systems

Throughout my software development exposures, defining and handling exceptions has always constituted a fair amount of my programming considerations. This post collates information about exceptions that I had came across.

The need for handling errors in your codes

Handling errors in your codes is intuitive - you are writing codes that people will use and people make mistakes. A good read of 100 things every designer needs to know about people by Susan Weinschenk will give you great insights on that.

Preventing people from making mistakes

Perhaps it may be better to prevent people from making mistakes while using a program feature, but there are times when it is beyond our control or technically challenging. A batch processing job that receives work input from the HTML file upload dialog box can be given a file type that is not expected. Even if we implement restriction on the file type, there is still no way to stop mischievous users from uploading files with invalid data format.

Unavoidable mistakes

The people part is one part of the story; components that you use in your code may fail too. Insufficient storage, invalid permissions, server does not like your request and what not. For example, making a WSDL call via C# codes generated from wsdl.exe may result in

  1. Server code encountering errors in processing the wsdl call.
  2. Server process could not find the code to handle the wsdl call.
  3. Server refusing the client request.
  4. Client cannot connect to the server at the network layer.
  5. Client does not have network connection.
  6. And many unexpected ones like Microsoft fly-by compiler attempts to create a temporary file but the operating system doesn't have a temporary folder.

What are exceptions?

Exceptions are programming constructs that encapsulate error information. In an object oriented environment, they are usually defined with a generic exception construct and thrown around when unwanted conditions occurs.

Suppose that we want to define an exception that is thrown when our program cannot initialise itself due to missing prerequisites. One way to do so in C# is as follows:

public class MissingPrerequisitesException
: ApplicationException
{
    // Declare an enum that provides a set of
    // reasons for callers
    public enum ExceptionReason
    {
        MissingComponents,
        MissingConfigurationFile,
        MissingConfigurations,
    };

    // Take note of the reason
    private ExceptionReason _reason;

    public ExceptionReason Reason
    {
        get
        {
            return this._reason;
        }

        private set
        {
            this._reason = value;
        }
    } 
 
    public MissingPrerequisitesException(
        ExceptionReason reason,
        string message)
        : base(message)
    {
        this.Reason = reason;
    }

    public MissingPrerequisitesException(
        ExceptionReason reason,
        string message,
        Exception inner)
        : base(message, inner)
    {
        this.Reason = reason;
    }

} // end public class MissingPrerequisitesException

And when our program detects a missing configuration file, it can throw an instance of the exception class with the throw keyword:

public void LoadConfigurations()
{
    if (!File.Exists("config-file.txt"))
    {
        throw new MissingPrerequisitesException(
            MissingPrerequisitesException.ExceptionReason.MissingConfigurations,
            "Configuration file does not exists!");
    } // end if

    // Read configurations from the file
    // ...

} // end public void LoadConfigurations()

Why exceptions?

Exceptions contain rich information about an error that happened

Implicitly, exceptions contain information for developers to know how and what error had happened.

For instance, the caller of LoadConfigurations can enclose the call in a try-catch block and print the exception stack trace:

private void Init()
{
    try
    {
        LoadConfigurations();
        // Configure other components
        // ...
    }
    catch (MissingPrerequisitesException mpe)
    {
        // The error that occurred is due to
        // missing prerequisites
        Console.WriteLine("Missing prerequisites!");
        // Print the message
        Console.WriteLine(mpe.);
        // Print the stack trace
        Console.WriteLine(mpe.StackTrace);

    }
} // end private void init()

And when the config-file.txt file cannot be found by the program, the program will output something like this:

Missing prerequisites!
Configuration file does not exists!
   at Program.LoadConfigurations() in d:\poc\exceptions\Program.cs:line 47
   at Program.Init() in d:\poc\exceptions\Program.cs:line 27

The 3rd line is the stack trace. Reading from the bottom up (from the 4th line), a developer can know that there is a Program.cs file and the error happens in the following sequence:

  1. The Init method is called
  2. In the Init() method, the LoadConfigurations method is called.

And because the LoadConfigurations method is at the top of the stack trace, it is the method that reports a missing configuration file.

Those are standard items that our MissingPrequisitesException class inherits from its parent class. We can also introduce more information within our custom defined exceptions to aid the exception handling code in reacting to the exception. For instance, with the Reason property that was introduced in the MissingPrequisitesException class, the exception handling code can react to different cases of missing prerequisites with a switch statement:

switch(mpe.Reason) 
{
    case MissingPrerequisitesException.ExceptionReason.MissingComponents:
        Console.WriteLine("Missing components, please check your installation.");
        break;
    case MissingPrerequisitesException.ExceptionReason.MissingConfigurationFile:
        Console.WriteLine("Missing configuration file, make sure that config-file.txt is in the same directory as the running program.");
        break;
    case MissingPrerequisitesException.ExceptionReason.MissingConfigurations:
        Console.WriteLine("Missing configurations, make sure that all needed configurations are supplied via config-file.txt.");
        break;
} // end switch(mpe.Reason)

Some articles which helped me gained great insights to the area of exceptions

About Clivant

Clivant a.k.a Chai Heng enjoys composing software and building systems to serve people. He owns techcoil.com and hopes that whatever he had written and built so far had benefited people. All views expressed belongs to him and are not representative of the company that he works/worked for.