Giao diện
Chiến thuật Debug 🔍
Debugging không phải nghệ thuật; nó là khoa học. Ngừng đoán mò.
Tip 1: Rubber Duck Debugging
Problem
Bạn stuck với bug hàng giờ, không biết bắt đầu từ đâu.
Solution
Rubber Duck Debugging: Giải thích code của bạn, từng dòng một, cho một vật vô tri (con vịt cao su).
Example
javascript
// Bug: Function trả về undefined
function calculateDiscount(price, coupon) {
if (coupon.type === 'percentage') {
return price * (coupon.value / 100); // ← Giải thích: "Nếu coupon là %, tính..."
} else if (coupon.type === 'fixed') {
return price - coupon.value; // ← "Nếu fixed, trừ đi..."
}
// ← "Ồ! Không có return cho case khác! Đó là bug!"
}Why It Works
Bằng cách buộc bản thân phải diễn đạt logic, bạn kích hoạt một phần khác của não bộ. Bạn thường sẽ tìm ra bug trước khi giải thích xong.
Pro Tips
- Không có vịt? Nói chuyện với màn hình, đồng nghiệp, hoặc thú cưng
- Viết ra giấy cũng hiệu quả tương tự
- Giải thích cho junior developer - teaching forces clarity
Tip 2: Binary Search Debugging (Git Bisect)
Problem
Bug không có ở tuần trước. Bây giờ nó ở đây. 50 commits đã xảy ra kể từ đó.
Solution
git bisect: Binary Search cho Git history - tìm commit gây bug trong O(log n).
Example
bash
# Start bisect
git bisect start
# Mark current commit as bad
git bisect bad
# Mark last known good commit
git bisect good abc123
# Git checkouts middle commit
# Test the code → Bug có không?
# If bug exists
git bisect bad
# If bug doesn't exist
git bisect good
# Repeat until Git finds the culprit commit
# Git will output: "abc123 is the first bad commit"
# End bisect
git bisect resetPro Tips
- Automate testing:
git bisect run npm test - Works with any binary condition (performance regression, etc.)
- Combine với automated tests cho maximum efficiency
Tip 3: Wolf Fence Algorithm
Problem
Bug ở đâu đó trong file 2000 dòng. Không biết bắt đầu từ đâu.
Solution
Wolf Fence: Đừng tìm sói khắp rừng. Xây hàng rào ở giữa.
Example
javascript
// File 2000 dòng, bug ở đâu đó
function processData(data) {
// ... 500 dòng code
console.log('CHECKPOINT 1: data =', data); // ← Hàng rào 1
// ... 500 dòng code
console.log('CHECKPOINT 2: data =', data); // ← Hàng rào 2
// ... 500 dòng code
}Logic:
- Nếu lỗi xảy ra trước CHECKPOINT 1 → Bug ở 500 dòng đầu
- Nếu giữa CHECKPOINT 1 và 2 → Bug ở 500 dòng giữa
- Lặp lại cho đến khi tìm thấy dòng chính xác
Pro Tips
- Dùng debugger breakpoints thay vì console.log
- Binary search: Luôn chia đôi search space
- Remove checkpoints sau khi tìm thấy bug
Tip 4: Reproduce First, Fix Later
Problem
Bug xuất hiện ngẫu nhiên, không reproduce được.
Solution
Quy tắc vàng: Không fix bug không reproduce được. Nếu không reproduce được, bạn không biết đã fix chưa.
Example
javascript
// Bad: Fix ngay mà không hiểu
function getUser(id) {
// Sometimes returns null, add fallback
return users.find(u => u.id === id) || {}; // ← Band-aid fix
}
// Good: Reproduce first
function getUser(id) {
const user = users.find(u => u.id === id);
if (!user) {
// Log để hiểu khi nào bug xảy ra
console.error('User not found:', { id, availableIds: users.map(u => u.id) });
throw new Error(`User ${id} not found`);
}
return user;
}Pro Tips
- Write a failing test that reproduces the bug
- Document reproduction steps
- If can't reproduce: Add logging và wait for more data
- Intermittent bugs: Often race conditions hoặc timing issues
Tip 5: Divide and Conquer với Breakpoints
Problem
Code phức tạp với nhiều function calls, không biết function nào gây bug.
Solution
Đặt breakpoints ở các điểm chiến lược, inspect state từng bước.
Example
javascript
function checkout(cart, user, payment) {
debugger; // ← Breakpoint 1: Inspect inputs
const total = calculateTotal(cart);
debugger; // ← Breakpoint 2: Verify total
const discount = applyDiscount(total, user);
debugger; // ← Breakpoint 3: Verify discount
const result = processPayment(discount, payment);
debugger; // ← Breakpoint 4: Verify payment
return result;
}Workflow:
- Run code với debugger
- Inspect variables tại mỗi breakpoint
- Identify nơi data becomes incorrect
- Focus vào function đó
Pro Tips
- Conditional breakpoints: Chỉ break khi condition true
- Logpoints: Log without stopping execution
- Watch expressions: Monitor specific variables
- Call stack: Trace function call chain
Tip 6: Isolate the Problem
Problem
Bug xảy ra trong hệ thống phức tạp với nhiều dependencies.
Solution
Isolate code thành smallest reproducible example.
Example
javascript
// Complex system
class UserService {
constructor(db, cache, logger, emailService) { ... }
async updateUser(id, data) {
// Bug somewhere in 50 lines
}
}
// Isolated test
function testUpdateUser() {
// Mock dependencies
const mockDb = { update: jest.fn() };
const mockCache = { invalidate: jest.fn() };
const service = new UserService(mockDb, mockCache, null, null);
// Test specific scenario
service.updateUser(123, { name: 'Test' });
// Verify behavior
expect(mockDb.update).toHaveBeenCalledWith(123, { name: 'Test' });
}Pro Tips
- Remove dependencies one by one
- Create minimal reproduction in separate file
- Share minimal repro when asking for help
- Often the process of isolating reveals the bug
Tip 7: Read Error Messages Carefully
Problem
Panic khi thấy error message dài, không đọc kỹ.
Solution
Đọc từ dưới lên: Stack trace thường có framework code ở trên, YOUR code ở dưới.
Example
Error: Cannot read property 'name' of undefined
at React.createElement (react.js:123)
at renderComponent (react-dom.js:456)
at Component.render (react-dom.js:789)
at UserProfile.render (UserProfile.jsx:42) ← START HERE!
at App.render (App.jsx:15)Reading Strategy:
- Đọc error message: "Cannot read property 'name' of undefined"
- Scroll xuống stack trace
- Tìm file BẠN viết:
UserProfile.jsx:42 - Mở file đó, line 42
- Inspect: Variable nào là undefined?
Pro Tips
- Framework errors ở trên: Bỏ qua
- YOUR code ở dưới: Focus vào đây
- Line numbers: Exact location của bug
- Error message: Tells you WHAT went wrong
Tip 8: Use Debugger, Not console.log
Problem
console.log everywhere, phải rebuild và refresh mỗi lần thay đổi.
Solution
Dùng debugger để inspect state real-time, không cần rebuild.
Example
javascript
// Bad: console.log debugging
function processOrder(order) {
console.log('order:', order);
const total = calculateTotal(order.items);
console.log('total:', total);
const tax = calculateTax(total);
console.log('tax:', tax);
return total + tax;
}
// Good: Debugger
function processOrder(order) {
debugger; // ← Pause here, inspect everything
const total = calculateTotal(order.items);
const tax = calculateTax(total);
return total + tax;
}Debugger Advantages:
- Inspect ALL variables, không chỉ những gì bạn log
- Step through code line by line
- Modify variables on the fly
- No rebuild needed
Pro Tips
- Browser DevTools: F12 → Sources → Set breakpoints
- VS Code: F5 → Start debugging
- Node.js:
node --inspect-brk app.js - Conditional breakpoints: Break only when condition true
Tip 9: Check Your Assumptions
Problem
Bug tồn tại vì assumptions của bạn sai.
Solution
Question everything: Verify mọi assumption bằng data.
Example
javascript
// Assumption: API always returns array
function displayUsers(users) {
return users.map(u => u.name); // ← Crashes if users is null/undefined
}
// Verify assumption
function displayUsers(users) {
console.assert(Array.isArray(users), 'users must be array', users);
if (!Array.isArray(users)) {
console.error('Invalid users data:', users);
return [];
}
return users.map(u => u.name);
}Common False Assumptions:
- "API always returns 200"
- "User always logged in"
- "Array always has items"
- "Database always available"
- "Network always fast"
Pro Tips
- Add assertions to verify assumptions
- Defensive programming: Validate inputs
- Fail fast: Throw errors early
- Document assumptions in comments
Tip 10: Take a Break
Problem
Stuck với bug hàng giờ, càng debug càng confused.
Solution
Step away: Đi dạo, uống cà phê, làm việc khác 15-30 phút.
Why It Works
- Einstellung Effect: Fixation on wrong solution blocks correct solution
- Fresh perspective: Brain processes information subconsciously
- Reduced stress: Stress impairs problem-solving
- Diffuse thinking: Allows creative connections
Example
10:00 AM - Start debugging
11:30 AM - Still stuck, frustrated
12:00 PM - Take lunch break ← CRITICAL
12:30 PM - Return to code
12:35 PM - "Oh! The bug is obvious now!"Pro Tips
- Set time limit: If stuck > 1 hour, take break
- Physical activity: Walk, stretch, exercise
- Context switch: Work on different problem
- Sleep on it: Overnight often brings clarity
- Pair programming: Fresh eyes see what you miss
📋 Quick Reference
| Strategy | When to Use | Benefit |
|---|---|---|
| Rubber Duck | Stuck, don't know where to start | Forces clear thinking |
| Git Bisect | Bug appeared recently | Find culprit commit fast |
| Wolf Fence | Large codebase | Narrow down location |
| Reproduce First | Intermittent bugs | Ensure fix works |
| Breakpoints | Complex logic | Inspect state step-by-step |
| Isolate | Many dependencies | Simplify problem |
| Read Errors | Stack traces | Find exact location |
| Debugger | Any bug | Better than console.log |
| Check Assumptions | Mysterious bugs | Find false beliefs |
| Take Break | Stuck > 1 hour | Fresh perspective |