appendto-logo-transparent

Error handling is important. It’s significantly important to user experience (or in this case, developer experience) because it’s living, reactive documentation of your code. The most detailed, wiki-filled documentation can’t see your code and suggest to you why something does not work. I strongly believe that errors (often an afterthought) are part of the user/developer experience, too. This article is about writing effective error handling for developers.

Learning from personal experience

I recently built a lightweight, vanilla JavaScript plugin to improve my understanding of JavaScript. It’s a responsive navigation plugin called KoalaNav and it makes menus easier to build. To complete the plugin I needed some of my peers to do a code review. One item we focused on that I did not expect was error handling and how to fail gracefully.

I had some error handling built in, but only a few reports to the console for invalid options. If an option had an invalid value the plugin would fail, but the developer could find more information in the console. My peers suggested a couple ways to improve on my error handling. The suggestions they gave could be summed up into one, simple rule:

Give developers the benefit of the doubt, but when you can’t, error gracefully.

After refactoring the plugin with their suggestions I believe this rule is fully satisfied. Here is the way I’ll approach error handling in the next plugin/application/whatever I write.

Think about how developers will break your code

This is the first step in writing good error handling. It doesn’t do developers any good to create detailed errors for situations that rarily happen. It’s important to think about how your code could commonly break.

For example, KoalaNav is written in JavaScript and doesn’t use jQuery. I use document.getElementById to target the navigation element. A developer may be tempted to use an ID selector with a # at the beginning. A value like #main-navigation would cause the document.getElementById to fail.

Another example is KoalaNav uses an integer to determine when the navigation should swap between mobile devices and larger devices. By default this is 500 (pixels), but a developer can modify this number. What happens if they entered this value as "400px"? It would fail because we’re looking for an integer, not a string.

These are some common errors that developers could run into with my plugin. Error handling is contextual and it’s important to think about how your code could commonly break.

Fix the error for the developer

Using the examples above, we could just let the code fail and throw an error to the console. The errors could be printed out as such:

[js] KoalaNav: You used an invalid wrapper. Do not use a "#" in your selector.
KoalaNav: You used an invalid value for your breakpoint. "400px" must be written as an integer.
[/js]

This would certainly inform the developer of what specifically went wrong instead of failing and letting them turn to the documentation again.

Jordan Kasper, one of my peers, made a great suggestion. Rather than fail and give information why, what if we could fix this error for the developer? We do have ways to determine if strings contain specific characters and what type of variable we’re working with.

We can fix the first error if we drop the first character of the wrapper if it starts with a #. This can be easily corrected with the following JavaScript:

[js] // If our wrapper starts with a "#" character
if (wrapper.charAt(0) === "#") {

// Remove the first character in the string
wrapper = wrapper.substr(1);

}
[/js]

Now a developer can accidentally use a jQuery-like selector without failure. We can apply that same “catch-and-fix” logic to our breakpoint option if "400px" was provided:

[js] // If our value is a string
if (typeof mobileWidth === "string") {

// setup a list of unit types that a developer might enter in
var badUnits = /px|em|rem/gi;

// strip out any matching units
mobileWidth = mobileWidth.replace(badUnits, "");

// convert our varible back to an integer
mobileWidth = parseInt(mobileWidth);

}
[/js]

With a little bit of code, we can take situations that would originally break our code to fix common pitfalls. This makes our code a bit more joyful to work with because we can assist the developer through potential errors.

Teach them something new

Now that we’re catching and fixing erroneous values, it’s a good idea to educate developers on the proper way to use our code. KoalaNav takes advantage of console.warn() to note the values provided have been altered.

Note: The console function does not work in older browsers. Because KoalaNav supports IE 9+, we don’t need to worry about browsers that are older than this.

Here’s an example of what that looks like if we refactored our wrapper fix:

[js] // If our wrapper starts with a "#" character
if (wrapper.charAt(0) === "#") {

// Store the old wrapper name for our warning message
var oldWrapper = wrapper;

// Remove the first character in the string
wrapper = wrapper.substr(1);

// Inform the developer of the conversion
console.warn(‘You used "’ + oldWrapper + ‘", a jQuery-like selector for your menu selector. This must be written without the "#" and has been converted to "’ + wrapper + ‘" for you.’);
}
[/js]

Now we’re fixing the error for the developer and also giving them information on what is happening to their code when the wrapper value is intercepted and modified.

Don’t force the developer to written documentation

If our plugin broke because of a bad value and we didn’t provide more details, we’d send the developer back to wiki-laden documentation and they could still miss why it isn’t working. The worst case is they get tired, give up, and use another library/plugin/etc.

This is what I mean when I use the term “reactive documentation”. Our codebase is reacting to what the developer is doing and teaching them as they use it – even if the code is being used incorrectly.

Resolve to a default value if all else fails

There are always going to be times where you can’t anticipate how your code will break.

For example, KoalaNav has an option to change if the mobile toggle button displays on the left or the right side. This means there are only two values available for this option: btnPosition: "left" or btnPosition: "right". So what happens if a developer tries to use btnPosition: "middle" or btnPosition: 500? Sometimes you must resolve to a sensible default value.

Here’s what the error handling looks like for this case:

[js] // Is btnPosition set to "left" or "right"?
if (btnPosition !== ‘left’ && btnPosition !== ‘right’) {

// If not, warn the developer
console.warn(‘You did not enter a valid btnPosition argument on #’ + wrapper + ‘. You used "’ + btnPosition + ‘" instead. ‘ + ‘Now using the default btnPosition value.’);

// Set btnPosition to the default value, "left"
btnPosition = ‘left’;

}
[/js]

Because we can’t give the developer the benefit of the doubt, we’ll error gracefully. This allows the plugin to function, but the default value is used in place of an invalid value.

Always try to error gracefully

Building this plugin helped me understand the value of good error handling. Most developers didn’t invest the time into my code like I did. It’s important that a developer gets educated (in our case, on-the-fly) as they use our code. Write as much helpful reactive documentation as you can.

Comments