How to handle errors in your Application

Don't let your Application Crash.

In software development, there is no such thing as an application that doesn't fail. Do you remember the Blue screen of death? When it happened, there was nothing you could do but restart your machine and hope it doesn't happen again. But how about the latest Windows OS? How come you don't see those errors as often as before? The answer is, Microsoft spent more time on error handling.

It's not just the operating system, every application has points of failures and when designing them it is important to anticipate where they might fail. For example, let's look at a small application that has a point of failure:

// Show user information
$users = GetUserInformation();

$render->UserInfo($user);

This little program does two things. It gets the user information externally, maybe from a database or the web, then it renders it on a canvas. This is just two function calls, but there is a possibility for multiple errors to occur.

If GetUserInformation() has to connect to the web the get any information, what happens when there is no internet connection? Nothing checks if there is a connection or not. So let's start by handling that.

if (InternetStatus() === INTERNET_CONNECTED){
    $users = GetUserInformation();

    $render->UserInfo($user);
} else {
    $render->NoInternet(MESSAGE_NO_INTERNET);
}

Just like that, our application will not fail if there is no internet connection available. But what if there is an internet connection, but somehow your validation token fail, or an error you did not anticipate occurs, how do you deal with that? That's when you make use of a try catch. I usually try to stay away from try catch, because it shows that my application doesn't have well defined points of failures. But still it can be very useful. Let's start from inside GetUserInformation() function and work our way out.

function GetUserInformation(){
    $userId = GetLocalUserId(); // not external.

    $jsonString = FetchUserInfoFromWeb($userId);

    if (empty($jsonString)) {
        return null;
    }

    $userObject = json_decode($jsonString,true);
    return $userObject;
}

Let's say fetching the json returned an empty string. Our function will return null. And our other side of the application will have no clue what went wrong. So our option is to either check for the data returned by GetUserInformation or throw an error.

function GetUserInformation(){
    $userId = GetLocalUserId(); // not external.

    $jsonString = FetchUserInfoFromWeb($userId);

    if (empty($jsonString)) {
        throw new Exception("User data for id:{$userId} returned an empty string.");
    }

    $userObject = json_decode($jsonString,true);
    return $userObject;
}

Now if we get an empty string an error is thrown. But it wouldn't make sense to just throw an error and crash the application, let's catch it and create an appropriate course of action for it.

if (InternetStatus() === INTERNET_CONNECTED){

    try {
        $users = GetUserInformation();
        $render->UserInfo($user);
    }catch(Exception $e) {
        // log the error
        Debug::Log($e->message);
        $render->ShowEmptyUser("We were not able to retrieve your data. Please try again later.");
    }

} else {
    $render->NoInternet(MESSAGE_NO_INTERNET);
}

Our two line of code looks much more complex now, but now no matter what error happens inside our GetUserInformation() our application is not going to crash. We can show our user an appropriate message to help them continue using the application.

One thing I learned programming throughout the years is that we should never let an error happen all by itself. We shouldn't let the hard drive throw an error because it couldn't write a file to disk, instead we should check if we can’t write then go to web storage mode. If the database connection disappears, we should try to save to the hard drive until the connection comes back. If the internet disappears, we should go to offline mode. You shouldn't let the application crash but instead handle the issue ourselves and only close the program if we have to.

Error handling can be used any place where you think you can't control the behavior of a component. If you don't have a 100% guaranty on a function, try to determine it's out come before you call it and your application should never fail.


Comments

There are no comments added yet.

Let's hear your thoughts

For my eyes only