Crafting Error Messages: The Unsung Hero of the Developer's Toolkit

August 22, 2023 5 mins read

Crafting Error Messages: The Unsung Hero of the Developer's Toolkit

Cloud computing, Java, TypeScript—whatever technology you’re diving into—there’s one constant that remains: errors. It’s an inevitable part of software engineering. But, are all error messages created equal? The answer is a resounding ‘No’.

In our exploration today, not only will we delve into the art of constructing meaningful error messages, but we’ll also introduce an innovative approach—crafting a custom exception class. This technique promises to elevate the clarity and actionability of our errors, positioning them as invaluable tools rather than mere nuisances. This post shines a spotlight on an often-overlooked pillar of the software lifecycle and unveil methods to truly make errors work in our favor.

The Anatomy of a Good Error Message

At the core, a useful error message should:

  1. Identify the fault: What went wrong?
  2. Explain the cause: Why did it go wrong?
  3. Provide a potential solution: How can it be fixed?

Striking the right balance in these three elements transforms a mere notification into a powerful tool for developers.

Example of a Good Error Message

Imagine we’re developing a cloud infrastructure with a CI/CD pipeline and our system throws the following error:

Error: File not found.

Now, that’s clear, but is it helpful? Let’s delve into the anatomy of a good error message.

  1. Identifying the fault: The error message already does this. A file is missing.
  2. Explaining the cause: Why is the file missing? Was it expected in a specific directory? Was it accidentally deleted?
  3. Provide a potential solution: Guide the developer on what to do next. Should they check a certain directory, or is there a specific naming convention they missed?

Let’s refine our error message keeping these in mind:

Error: Configuration file 'config.yaml' not found in '/app/config/'. 
Ensure the file exists in the correct directory and adheres to naming conventions.

With this revised message, the developer knows exactly which file is missing, where it was expected, and what they can do to resolve the issue.

CI/CD: A Perfect Realm for Good Error Messages

Suppose you have a script that fetches translations from your codebase and pushes them to a third-party translation management platform. The script expects to find a file with translations in a specific format, say translations.json.

Now, imagine that this script fails. An unclear error might be:

Error: Unable to export translations.

This doesn’t give the developer much to go on. Is the problem with the file, its format, the third-party platform, or perhaps network connectivity?

Let’s utilize our trifecta approach:

  1. Identifying the fault: The script can’t export translations.
  2. Explaining the cause: Why? Perhaps the translations.json file is absent or malformed.
  3. Provide a potential solution: The developer should check the existence and format of the file, and if both are correct, they should then verify connectivity to the third-party platform.

Our refined error message could be:

Error: Failed to export to ThirdPartyTranslationService. 'translations.json' either 
not found or is malformed in '/app/translations/'. Ensure the file exists, has the 
correct format, and the connection to https://my-translation-service.com/api/ is stable.

With this, the developer gets a clear indication of where the problem might be and actionable steps to resolve the issue.

If you’re diving deep into CI/CD, do check out The Art of Writing Scripts for CI/CD. It’s an insightful guide on the subject and also touches upon the importance of clarity in scripts, which, as you’ve guessed, extends to error messages.

Boosting Actionability with Exception Classes

When interfacing with third-party systems, like a CMS, understanding the exact source of a problem can save a developer countless hours. This is where specialized exception classes come into play.

Consider interactions with Contentful, a popular headless CMS. Let’s explore how an enhanced exception class can transform the debugging experience:

import { Entry } from 'contentful';

export class ContentfulError extends Error {
    
  constructor(message: string, affectedEntry?: Entry<any>) {
    super(`${message}\n${ContentfulError.affectedEntryDetails(affectedEntry)}`);
    this.name = 'Contentful Data Error';
  }

  private static affectedEntryDetails(entry: Entry<any> | undefined): string {
    if (!entry?.sys) {
        return 'Affected Entry: Unknown';
    }
    return `
Affected Entry:
  Entry ID:      ${entry.sys.id}
  Content Type:  ${entry.sys.contentType.sys.id}
  Edit in Contentful: https://app.contentful.com/spaces/${process.env.CONTENTFUL_SPACE_ID}/environments/${process.env.CONTENTFUL_ENVIRONMENT_ID}/entries/${entry.sys.id}`;
  }
}

The ContentfulError class is a specialized exception tailored for interactions with the Contentful CMS. It not only states the error message but also provides specific details about the affected Contentful entry. By including the entry’s ID, content type, and a direct link to it within the Contentful dashboard, the class turns a generic error into an actionable guide. This design facilitates faster debugging and remediation by leading developers directly to the source of the problem. Such a targeted approach is invaluable in complex systems, reducing the time spent searching and ensuring more efficient error handling.

Using the ContentfulError Class

Imagine a scenario where we attempt to render a “hero” section for a website. This “hero” is expected to have a prominent title image, but there are cases where the image might be missing due to a content error in Contentful.

function renderHeroSection(heroEntry: Entry<any>) {
  if (!heroEntry.fields.titleImage) {
    throw new ContentfulError("Hero entry does not have a title image set.", heroEntry);
  }
  // ... rendering logic ...
}

If the heroEntry does not have a title image, the ContentfulError exception is thrown. This error message not only highlights the problem but also provides direct context and a link to the affected entry in Contentful. This is a game-changer for developers: instead of having to search for the problematic entry manually, they can jump directly to it and address the issue.

Conclusion: Crafting Actionable Errors for Enhanced Software Engineering

By enriching our error classes with actionable insights, like with the ContentfulError class, we transform debugging from a potentially tedious task into an efficient process, empowering developers to directly address issues at their root. In a field where every minute is precious, streamlined processes significantly bolster productivity, ensuring swift resolutions and a refined developer experience.

Moreover, while the core of our applications is undeniably important, we must not overlook the profound impact of well-crafted error messages. These messages act as guiding beacons, ensuring software development remains smooth and cohesive. Always aim for clarity, precision, and actionable guidance in your error messages. By adhering to this trifecta—identifying the fault, elucidating the cause, and suggesting a solution—you elevate not just a single software project but the broader discipline of software engineering itself.

Comments

👋 I'd love to hear your opinion and experiences. Share your thoughts with a comment below!

comments powered by Disqus