惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
GbyAI
GbyAI
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 叶小钗
U
Unit 42
Engineering at Meta
Engineering at Meta
aimingoo的专栏
aimingoo的专栏
Y
Y Combinator Blog
Google DeepMind News
Google DeepMind News
Vercel News
Vercel News
美团技术团队
雷峰网
雷峰网
Recent Announcements
Recent Announcements
有赞技术团队
有赞技术团队
D
DataBreaches.Net
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Apple Machine Learning Research
Apple Machine Learning Research
J
Java Code Geeks
罗磊的独立博客
MyScale Blog
MyScale Blog
博客园_首页
IT之家
IT之家
F
Fortinet All Blogs
博客园 - Franky

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Your trycatch sucks - lets fix it
Shuvo · 2026-05-21 · via DEV Community

You're not handling errors. You're hiding them.

Every app crashes. Every API fails. Every database hiccups at 2am on a Friday.
The difference between a good dev and a great one? What happens next.

Let's roast your error handling — then make it legendary.


🤦 Level 0: The "Trust Me Bro" Dev

No try/catch at all. Just vibes.

const data = await fetchUserData(userId);
console.log(data.profile.name); // 💥 TypeError: Cannot read properties of undefined

Enter fullscreen mode Exit fullscreen mode

The crime: One bad response nukes the entire app. Users see a white screen. You get a 3am Slack ping.


🐣 Level 1: The Junior — "I Googled try/catch"

try {
  const data = await fetchUserData(userId);
  setUser(data);
} catch (err) {
  console.log(err); // 👈 and... that's it. shipped.
}

Enter fullscreen mode Exit fullscreen mode

What's wrong here?

  • console.log in production helps nobody — users still see a broken UI
  • No distinction between a 404 and a 500 — every error is treated the same
  • The error disappears into the void (or a DevTools tab nobody has open)
  • err might be null, a string, or an Error object — you're not checking

The mindset: "At least it won't crash." — Yeah, it just silently breaks instead. Cool.

GitMission Preview


📈 Level 2: The Mid-Level — "I've Been Burned Before"

Now we're thinking. You've seen production fires. You have trust issues with APIs. Good.

2a — Typed errors, real messages

try {
  const data = await fetchUserData(userId);
  setUser(data);
} catch (err) {
  if (err instanceof NetworkError) {
    showToast("Connection lost. Check your internet.", "warning");
  } else if (err.status === 404) {
    showToast("User not found.", "error");
  } else {
    showToast("Something went wrong. We're on it.", "error");
    logger.error("[fetchUserData]", { userId, err }); // 👈 goes to Sentry/Datadog
  }
}

Enter fullscreen mode Exit fullscreen mode

✅ Users get useful feedback, not a frozen screen
✅ Engineers get structured logs, not a haystack of console.logs


2b — Undo previous operations (the "atomic mindset")

Imagine you're updating a user's profile and their avatar. Step 1 succeeds. Step 2 fails.
Congrats — your user now has a corrupted half-state.

let previousProfile = null;

try {
  previousProfile = await getProfile(userId); // snapshot
  await updateProfile(userId, newProfileData); // step 1
  await uploadAvatar(userId, newAvatar);        // step 2 💥 fails here
} catch (err) {
  logger.error("Profile update failed", { err });

  // ↩️ Roll back step 1 since step 2 failed
  if (previousProfile) {
    await updateProfile(userId, previousProfile);
  }

  showToast("Update failed. Your profile has been restored.", "warning");
}

Enter fullscreen mode Exit fullscreen mode

✅ Users never see broken half-state
✅ Rollback is explicit, not accidental


2c — Wrap it in a clean utility (stop repeating yourself)

Tired of writing try/catch 50 times? Make a helper:

// utils/tryCatch.js
export async function tryCatch(fn, fallback = null) {
  try {
    const result = await fn();
    return [result, null];
  } catch (err) {
    return [fallback, err];
  }
}

// Usage — clean, flat, readable
const [user, err] = await tryCatch(() => fetchUserData(userId));

if (err) {
  showToast("Couldn't load user.", "error");
  return;
}

setUser(user);

Enter fullscreen mode Exit fullscreen mode

✅ No more deeply nested try/catch pyramids
✅ Forces you to handle the error at call site — can't ignore it


🧠 Level 3: The Senior — "I've Seen Things"

You don't just catch errors. You anticipate them. You build systems that heal themselves.

3a — Retry queue with exponential backoff

Networks are flaky. Don't give up on the first failure.

async function fetchWithRetry(fn, { retries = 3, delay = 500 } = {}) {
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      const isLast = attempt === retries;
      const isRetryable = err.status >= 500 || err instanceof NetworkError;

      if (isLast || !isRetryable) throw err; // don't retry 401s or 404s

      const backoff = delay * 2 ** (attempt - 1); // 500ms → 1s → 2s
      logger.warn(`Attempt ${attempt} failed. Retrying in ${backoff}ms...`);
      await sleep(backoff);
    }
  }
}

// Usage
const data = await fetchWithRetry(() => fetchUserData(userId));

Enter fullscreen mode Exit fullscreen mode

✅ Temporary blips are invisible to users
✅ Smart: retries server errors, not client errors (no point retrying a 401)


3b — Circuit breaker (stop hammering a dead service)

A retry queue is great — unless the whole service is down. Then you're just DDoS-ing a corpse.

class CircuitBreaker {
  constructor(threshold = 5, timeout = 30_000) {
    this.failures = 0;
    this.threshold = threshold;
    this.timeout = timeout;
    this.state = "CLOSED"; // CLOSED = healthy, OPEN = tripped, HALF_OPEN = testing
    this.nextAttempt = Date.now();
  }

  async call(fn) {
    if (this.state === "OPEN") {
      if (Date.now() < this.nextAttempt) {
        throw new Error("Circuit open — service unavailable");
      }
      this.state = "HALF_OPEN";
    }

    try {
      const result = await fn();
      this.reset();
      return result;
    } catch (err) {
      this.recordFailure();
      throw err;
    }
  }

  recordFailure() {
    this.failures++;
    if (this.failures >= this.threshold) {
      this.state = "OPEN";
      this.nextAttempt = Date.now() + this.timeout;
      logger.error("🔴 Circuit breaker TRIPPED");
    }
  }

  reset() {
    this.failures = 0;
    this.state = "CLOSED";
  }
}

// Usage
const userServiceBreaker = new CircuitBreaker();
const data = await userServiceBreaker.call(() => fetchUserData(userId));

Enter fullscreen mode Exit fullscreen mode

✅ Failing fast is kind — users get an error immediately, not after 10s of retrying
✅ Gives the downstream service a breather to recover


3c — Structured error classes (errors that mean something)

Stop throwing raw strings or generic Errors. Give your errors context.

class AppError extends Error {
  constructor(message, { code, statusCode = 500, context = {}, retryable = false } = {}) {
    super(message);
    this.name = "AppError";
    this.code = code;
    this.statusCode = statusCode;
    this.context = context;
    this.retryable = retryable;
    this.timestamp = new Date().toISOString();
  }
}

// Subclass for specificity
class AuthError extends AppError {
  constructor(message, context) {
    super(message, { code: "AUTH_ERROR", statusCode: 401, context, retryable: false });
  }
}

class ServiceUnavailableError extends AppError {
  constructor(service, context) {
    super(`${service} is unavailable`, { code: "SERVICE_DOWN", statusCode: 503, context, retryable: true });
  }
}

// Throwing
throw new ServiceUnavailableError("UserService", { userId, attempt: 3 });

// Catching
catch (err) {
  if (err instanceof AuthError) {
    redirectToLogin();
  } else if (err instanceof AppError && err.retryable) {
    retryQueue.add(err);
  } else {
    logger.error(err.code, err.context);
    showToast("Unexpected error. Engineers notified.");
  }
}

Enter fullscreen mode Exit fullscreen mode

✅ Catch blocks can make decisions, not just log and pray
✅ Every error carries its own context — no more guessing what happened


🗺️ The Full Picture

What you do Junior Mid Senior
Catch errors
Inform the user
Send to a logger
Typed/structured errors ⚠️ partial
Rollback on failure
Retry transient errors
Circuit breaker
Errors are self-describing

✅ The Golden Rules

  1. Never swallow errors silently. A hidden bug is a time bomb.
  2. Always tell the user something. Frozen UI is worse than an error message.
  3. Log with context, not just a message — what failed, who triggered it, when.
  4. Not all errors are equal — 404 ≠ 500 ≠ NetworkError. Handle them differently.
  5. Retryable ≠ always retry — client errors (4xx) should fail fast.
  6. Leave the system in a valid state. Roll back or compensate when operations are partial.
  7. Your catch block is business logic — treat it that way.

"The mark of a great engineer isn't writing code that never fails.

It's writing code that fails gracefully."

Now go fix your try/catches. 🛠️

GitMission Preview