🚨Error Handling & Result Management : Debugging Disasters and Tiny Victories

ALI ALHARBI - Nov 6 - - Dev Community

Image description

I’ll be real: when I first started coding, error handling was an afterthought. Errors? They were just “part of the journey,” right? But, after a few too many mystery bugs and app crashes, I finally decided to tackle error handling properly. Maybe these tips will save someone else some headaches,
......or maybe I’m just here documenting my own mess. Let’s dive in!

Early Days: Playing Whack-a-Mole with Errors 🐹

At first, my error-handling strategy was more “throw in a console.log() and hope for the best.” But as projects grew, this approach crashed and burned—literally. 💥 My app would keep breaking, and I was left guessing why. Lesson learned? Errors don’t just “disappear” Ignoring them only makes them come back stronger. 😅

Learning to Respect the try-catch 🔍

Eventually, I realized try-catch blocks could actually be lifesavers. By wrapping code in try-catch, I could see where errors happened and even fix them. Here’s what that looked like:

try {
  const data = await fetchData();
} catch (error) {
  console.error("An error happened:", error);
}
Enter fullscreen mode Exit fullscreen mode

It made debugging a lot easier! But catching errors was just the beginning—I needed to handle them properly. 🤓

Managing Results: Success or Failure? ✅❌

Next, I noticed my functions were returning... unclear results. Was null a failure? An empty result? Who knows! To avoid confusion, I started returning { success: true } for success and { success: false, error } for failures:

const result = await db.insert(data);
if (!result) throw new Error("Insert failed");
return { success: true };
Enter fullscreen mode Exit fullscreen mode

Now, it’s clear whether things went right or wrong. No more head-scratching over ambiguous returns! 🤯

Error Messages in Two Languages? 🌍

One day, I found out I needed error messages in both English and Arabic. Because, you know, why not? 🥲 So I set up a little message map:

const MSGS = {
  OTP_FAILED: { 
    en: "OTP verification failed.", 
    ar: "فشل التحقق من الرمز." 
  },
};
Enter fullscreen mode Exit fullscreen mode

It was surprisingly handy! Now I could grab MSGS.OTP_FAILED[locale] and return the right message in the right language. This little tweak was a game-changer. ✨

Putting It All Together 🧩

Eventually, I got to a setup that actually worked. I used try-catch at a high level, with each function either returning { success: true } or throwing an error. Here’s what it looked like:

export const otpCreate = async (otp, locale) => {
  const row = await db.insert(tableOtp).values(otp).returning();
  if (!row || row.length === 0) throw new Error(MSGS.OTP_FAILED[locale]);
  return { success: true, data: row };
};
Enter fullscreen mode Exit fullscreen mode

Then, I’d handle it like this:

try {
  const result = await otpCreate(otp, locale);
  if (result.success) console.log(MSGS.OTP_CREATED[locale], result.data);
} catch (error) {
  console.error(MSGS.OTP_FAILED[locale], error.message);
}
Enter fullscreen mode Exit fullscreen mode

Simple, readable, and (finally) consistent. 🙌

Final Thoughts 💡

So, that’s my journey! Here’s what I learned along the way:

  • Catch errors close to the source 🕵️ – It makes debugging so much easier.
  • Be explicit with success/failure indicators ✅❌ – No more guessing what null means.
  • Make error messages clear 🌍 – And if you’re working in multiple languages, a little planning goes a long way.

What about you? Have any other tricks for handling errors and results? I’d love to hear your ideas! And if this saves just one person from a debugging headache, I’ll call it a win. Happy coding! 🎉👩‍💻👨‍💻

. . .