DEV Community

Cover image for Backend Error Handling: Practical Tips from a Startup CTO
Victoria Johnston
Victoria Johnston

Posted on

Backend Error Handling: Practical Tips from a Startup CTO

Hey there! I’m the CTO of a web3 startup, and before that, I was a senior engineer working on infrastructure and full-stack systems at Google. I’ve learnt a few things along the way about coding, and today, I’m excited to dive into something that we often overlook until it’s too late: error handling and logging.

When I first jumped ship from Google to start my own venture, it was all about moving fast, hacking stuff together, and making things work. One thing that I initially put on the back burner was implementing a robust error handling and logging system. After all, why waste time preparing for errors when you can just code to avoid them, right? Well, fast forward to countless hours spent debugging and troubleshooting, and I’ve learnt my lesson.

In this post, I’ll share with you some practical tips and best practices on error handling and logging that I’ve picked up, alongside examples from my own experiences. If I knew back then what I know now, I would have set up error handling right from the start. But as they say, hindsight is 20/20.

Let’s get into it!

Why is Error Handling Important?

Before we dive into the practicalities, let’s take a moment to consider why error handling is important. Well, for starters, errors are inevitable. No matter how careful you are, how experienced your team is, or how thorough your QA process might be, things can and will go wrong. That’s just the reality of software development.

  1. Debugging: A proper error handling and logging system can make debugging significantly easier and faster. By having detailed error messages and logs, you can trace back the series of events that led to the error, making it easier to reproduce and fix.
  2. Resilience: Handling errors appropriately can make your system more resilient. Instead of crashing the whole system, a well-placed try/catch can contain the error and allow the system to recover and continue running.
  3. User Experience: Users don’t like seeing raw error messages or, worse, having the app crash on them. Good error handling can allow you to provide user-friendly error messages and fallbacks, leading to a better user experience.
  4. Security: Detailed error messages can reveal more about your system than you might want. You can avoid potential security risks by controlling what gets revealed in an error message.

Getting Hands-on with Error Handling

Now, let’s get down to business. How do you handle errors effectively in a backend environment? There’s no one-size-fits-all answer, as it heavily depends on your tech stack, team size, project complexity, and a dozen other factors. That being said, there are some universally good practices to adhere to.

1. Centralized Error Handling

It’s a good practice to centralize your error handling as much as possible. This approach simplifies code readability and maintainability and ensures consistency. If you’re using a framework like Express.js, you can use middleware for this.

Here’s a simplified example:

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

Enter fullscreen mode Exit fullscreen mode

This error-handling middleware would catch errors that occur in your route handlers and send a generic response. But what about sending more user-friendly messages or dealing with different error types? That’s where custom error classes come in.

2. Custom Error Classes

Custom error classes in JavaScript (or whatever language you’re using) allow you to create specific error types, each potentially having its own error handling. Here’s a simple example:

class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
    this.statusCode = 400;
  }
}

class DatabaseError extends Error {
  constructor(message) {
    super(message);
    this.name = "DatabaseError";
    this.statusCode = 500;
  }
}
Enter fullscreen mode Exit fullscreen mode

With these classes, you can throw specific errors in your code, and your error-handling middleware can behave differently depending on the error type.

app.use((err, req, res, next) => {
  if (err instanceof ValidationError) {
    res.status(err.statusCode).send(err.message);
  } else if (err instanceof DatabaseError) {
    res.status(err.statusCode).send('A database error occurred');
  } else {
    res.status(500).send('Something broke!');
  }
});

Enter fullscreen mode Exit fullscreen mode

These are just simplified examples. In a real-world scenario, you might log the errors to an external service, handle more error types, etc.

3. Proper use of Try/Catch

Try/catch blocks are your bread and butter for catching errors as they occur. It’s important only to catch errors that you can handle. If you can’t handle the error (for example, you don’t know why it would occur), it’s usually better to let it bubble up to the global error handler.

Here’s a good use of a try/catch block:

try {
  const user = await getUserFromDb(userId);
} catch (err) {
  if (err instanceof NotFoundError) {
    // We know why this error occurred and we can handle it
    return createNewUser(userId);
  }
  // We can't handle any other errors, rethrow them
  throw err;
}
Enter fullscreen mode Exit fullscreen mode

Here, we’re only catching a specific error that we know might happen and that we can handle. Any other errors get rethrown and can be handled by our global error handler.

The Importance of Good Logging

Now, while error handling is about dealing with errors as they occur, logging is about recording what happened so you can look back on it in the future. This can be extremely helpful when debugging.

There are several things you should consider when implementing logging:

  1. What to log: You want to log any information that might be useful for debugging. This can include input parameters, output results, and any intermediate variables. However, be aware of privacy and security issues. Never log sensitive information like passwords.
  2. When to log: Ideally, you want to log as much as possible, but there’s always a trade-off between detail and performance/storage. Consider using different log levels (error, warning, info, debug) to control this.
  3. Where to log: For local development, logging into the console might be sufficient. But for a production system, you’ll want to use a logging service that can handle large volumes of logs, manage retention policies, and provide search and analysis tools. This could be a cloud service like Google’s Cloud Monitoring, a self-hosted solution like Elasticsearch, or a log management service like Loggly or Datadog.

Here’s an example of how you might log a function’s input and output:

function add(a, b) {
  console.log(`add was called with ${a} and ${b}`);
  const result = a + b;
  console.log(`add result is ${result}`);
  return result;
}
Enter fullscreen mode Exit fullscreen mode

In a production scenario, you’d replace console.log with a call to your logging library or service, and you might add more detail (like a timestamp or the name of the function).

Final Thoughts

I hope this post has given you a practical insight into error handling and logging in backend development. If there’s one thing I want you to take away from this, it’s that error handling and logging are not an afterthought. They are an integral part of your code that can save you countless hours of debugging and many headaches. So, invest the time upfront to set up a good error handling and logging system. You’ll thank yourself later!

Stay tuned for future posts where I plan to delve deeper into some of these topics. If you have any questions, feel free to drop a comment or reach out to me. Happy coding!

For more coding tutorials, please subscribe to my YouTube channel: https://www.youtube.com/@CtrlAltVictoria and Twitter https://twitter.com/ctrlaltvictoria 💕🚀

Top comments (15)

Collapse
 
seungzedd profile image
Seung-zedd

that's why TDD(Test-Driven-Development)is also important. but if the company is prone to agile system, there is alternative ways to this like error handling and logging. and i think using Git to log message is an another good solution to handle it.

Collapse
 
onlinemsr profile image
Raja MSR

Thank you for sharing your experience and insights on error handling and logging. Your tips are practical and easy to follow. I especially appreciate your emphasis on the importance of error handling in improving user experience!

Collapse
 
ctrlaltvictoria profile image
Victoria Johnston

thank you :)

Collapse
 
joshuaamaju profile image
Joshua Amaju

Even though it's a contrived example, you shouldn't do logging in the add function

Collapse
 
olivia73code profile image
Olivia73-code

Thank you for this guide. I look forward to managing or supporting with implementing this in the future.

Collapse
 
shshank profile image
Shshank

Thank you so much for this helpful guide. I too skip error handling part while coding. But from now on try to handle error as much possible. Thanks for this practical guide.

Collapse
 
ctrlaltvictoria profile image
Victoria Johnston

You are welcome! Thanks for reading!

Collapse
 
codeguage profile image
Codeguage

The article was well articulated and really engaging to read. Error-handling indeed is a paramount aspect of well-designed systems. Kudos to you 👏.

Collapse
 
ctrlaltvictoria profile image
Victoria Johnston

Thank you :)

Collapse
 
tahsin52225 profile image
Tahsin Ahmed

Thank you for sharing this.

Collapse
 
ctrlaltvictoria profile image
Victoria Johnston

You're welcome! Thanks for reading :)

Collapse
 
michaeltharrington profile image
Michael Tharrington

Thanks so much for walking us through the ins and outs of backend error handling, Victoria! This a super well-written and practical guide. 🙌

Collapse
 
ctrlaltvictoria profile image
Victoria Johnston

You're welcome!! I'm glad you found it helpful :)

Collapse
 
rlgino profile image
Gino Luraschi

It was an interesting post, I'm go developer, and error handling sometimes is a huge problem, I'll try to use your suggestion for improving it 👀

Collapse
 
ctrlaltvictoria profile image
Victoria Johnston

Thank you! Let me know how it goes :)