Murphy’s Law: cái gì sai được, sẽ sai
Junior developer code cho “happy path” — khi mọi thứ đúng. Senior developer code cho unhappy path — khi mọi thứ sai. 80% thời gian debug là xử lý case bạn không nghĩ tới.
Pattern 1: try/catch đúng cách
// File: error-handling.ts
// ❌ SAI: catch rồi nuốt lỗi
try {
await saveUser(data)
} catch (err) {
console.log(err) // Rồi sao? User thấy gì?
}
// ✅ ĐÚNG: catch → log → báo user → recover
try {
await saveUser(data)
} catch (err) {
// 1. Log chi tiết cho developer debug
logger.error("Failed to save user", {
userId: data.id,
error: err.message,
stack: err.stack,
})
// 2. Báo user message thân thiện (KHÔNG lộ stack trace)
throw new AppError(
"Không thể lưu thông tin. Vui lòng thử lại.",
500
)
}
Pattern 2: React Error Boundary
// File: ErrorBoundary.tsx
// Component lỗi → không crash cả app
import { Component, ReactNode } from 'react'
interface Props { children: ReactNode; fallback: ReactNode }
interface State { hasError: boolean }
class ErrorBoundary extends Component<Props, State> {
state = { hasError: false }
static getDerivedStateFromError() {
return { hasError: true }
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
// Gửi lên Sentry/monitoring
captureException(error, { extra: info })
}
render() {
if (this.state.hasError) return this.props.fallback
return this.props.children
}
}
// Sử dụng: component Dashboard crash → chỉ Dashboard lỗi, app vẫn chạy
// <ErrorBoundary fallback={<p>Có lỗi xảy ra</p>}>
// <Dashboard />
// </ErrorBoundary>
Pattern 3: Graceful degradation
| Tình huống | Crash (Bad) | Graceful (Good) |
|---|---|---|
| API trả 500 | Trang trắng | Hiện data cũ từ cache + banner “Đang cập nhật” |
| Ảnh load thất bại | Broken image icon | Placeholder image + retry |
| Payment timeout | “Error 500” | “Thanh toán đang xử lý, chúng tôi sẽ email xác nhận trong 5 phút” |
| Search trả 0 kết quả | Trang trống | “Không tìm thấy X. Thử tìm Y?” |
⚠ KHÔNG BAO GIỜ lộ stack trace cho user
res.status(500).json({ error: err.stack }) → TUYỆT ĐỐI KHÔNG. Stack trace chứa: đường dẫn server, tên file, library version → hacker dùng để tấn công. User chỉ cần thấy “Có lỗi xảy ra, vui lòng thử lại.”
❓ Khi catch lỗi, điều QUAN TRỌNG NHẤT là gì?
- Wrap async code trong try/catch
- Tạo class AppError với message thân thiện
- Setup React Error Boundary cho component
- Không lộ stack trace trong API response