Exceptions aren’t problems but symptoms, let them show up

When we design an application we are the ones to govern the rules, it’s like a country having its own laws which everyone inside has to abide to and obviously, we don’t want people who won’t follow our jurisdiction. Assuming people keep the same persona both in and outside the country. There are several ways to ensure this, you can have a check-post to ensure whom you wish to allow inside, or you can allow everybody in & have cops to catch intruders when they disobey some laws, or you can simply have enough trust in the outside world to only send good people to your country. I am a big time believer of peace and hence strongly recommend the last. Rest of the blog is for people who simply cannot follow the crappie-big-time-believer-of-peace-ethic

Trust brings with it expectations. Since we programmers, unlike managers, don’t expect impossible things and hence we can say expectations are a small subset of possibilities. All code that you write, should be against expectations and not possibilities, with just one exception which we shall see later in the post. What this means is, your code should be free of try...catch blocks, unless one of the use case is expected to produce some exception, and even in such cases your catch block should be against that particular expected type of exception and not against all subclasses of Exception. Assume our acceptance criteria says, Divide should return Double.Infinity if we encounter division by zero.

A way to do this would be

public double Divide(MyNumber num1, MyNumber num2)
{
    double result;
    try
    {
        result = num1.Value / num2.Value;
    }
    catch (Exception exception)
    {
        return Double.Infinity;
    }
    return result;
}

The above code is sure to return Double.Infinity if num2.Value were to be zero. Here even if we pass num1 or num2 as null, we will be returned Double.Infinity, since num1.Value / num2.Value will throw a NullReferenceException exception, which will be caught. As we are not expecting num1 or num2 to be null, we should be alerted when this happens. By catching it we will never know something unexpected even happened.

Right way to do it would be to only catch the expected DivideByZeroException & not others

public double Divide(MyNumber num1, MyNumber num2)
{
    double result;
    try
    {
        result = num1.Value / num2.Value;
    }
    catch (DivideByZeroException exception)
    {
        return Double.Infinity;
    }
    return result;
}

Another thing to keep in mind is your try block should have as few statements & operators as possible. More the number of statements, less likely the exception occurred at the expected place.

// We are sure the exception occurred at the expected line
public double Divide(MyNumber num1, MyNumber num2)
{
    double result;
    double value1 = num1.getValue();
    double value2 = num2.getValue();
    try
    {
        result = value1 / value2;
    }
    catch (DivideByZeroException exception)
    {
        return Double.MaxValue;
    }
    return result;
}
// We can't say the exception happened during division
// It may have been thrown by one of the getValue() calls too
// If latter was the case, we better come to know about it
public double Divide(MyNumber num1, MyNumber num2)
{
    double result;
    try
    {
        result = num1.getValue() / num2.getValue();
    }
    catch (Exception exception)
    {
        return Double.MaxValue;
    }
    return result;
}

So what happens to all the exceptions that we did not catch? Any unhandled exception will crash your application. Let our application crash!! Are you crazy? you may say, well craziness is a relative term 🙂 When an exception that we were not prepared for occurs, its better to let your app sink, than to let it continue in an unknown and possibly inconsistent state. But the same can be done gracefully.

All applications/processes/threads have start points, like main() is a start point, so if anything inside fails it cascades back to these start points, this is one place where we use a generic try...catch(Exception e) and in the catch, we should log the exception, and let the user know that the ship is sinking. It gets a bit tricky with multi-threaded applications but most of these do have some event to subscribe to unhandled exceptions, in case of threads one can create a utility method that creates threads, and hence this utility becomes the start point of all user-created threads, and the try...catch can be deployed here. Note that, in case of unhandled exceptions in threads, only that thread will die and not necessarily entire application, some special care may be needed

eg: Catching unhandled exception in main

static void Main(string[] args)
{
    try
    {
        //All you code goes in here
    }
    catch (Exception ex)
    {
        Logger.log(ex);
        Console.WriteLine("Some unknown error occured, the application will close now");
    }
}

eg: Catching unhandled exception in multi-threaded applications.
This is the simplest way of achieving a streamlined thread creation mechanism and hence handling any exceptions in the new threads, we just need to make sure that any new thread should only be spawned using this method

public static void ExecuteOnNewThread(Action actionToInvokeOnNewThread)
        {
            var thread = new Thread(PerformAction(actionToInvokeOnNewThread));
            thread.Start();
        }

        private static ThreadStart PerformAction(Action actionToInvokeOnNewThread)
        {
            return () =>
            {
                try
                {
                    actionToInvokeOnNewThread.Invoke();
                }
                catch (Exception ex)
                {
                    //Logger.log(ex);
                    Console.WriteLine("Some unknown error occurred, the application will close now");
                }
            };
        }

So what does all this give us? This helps us track down all unexpected behaviors a.k.a defects which may have been hidden due to the improper exception handling. These exceptions in the generic catch blocks are your symptoms to a bigger problem which is waiting to be solved by you, so go and gear up with your debugging hat and get started…

Latest posts by Jugal Thakkar (see all)