What is it
Debug (or debugging) is the systematic process of finding and fixing errors in code. The name comes from “de-bug” = removing bugs.
It includes:
- Reproduce the problem
- Isolate the root cause
- Understand why it happens
- Fix the code
- Verify the solution works
Pronunciation
IPA: /diːˈbʌɡ/
Sounds like: “dee-buhg” - two syllables, emphasis on the second
Common mistakes:
- ❌ “deh-bug” (the first ‘e’ is long like in “see”)
- ❌ “de-boog” (the ‘u’ sounds like the ‘u’ in “cup”)
Variants:
- Debug (verb): “I need to debug this”
- Debugging (noun/gerund): “Debugging is an art”
- Debugger (tool): “Open the debugger”
Debugging Techniques
1. Print Debugging (The most basic)
function calculateTotal(items) {
console.log('Items received:', items); // 👈 Debug
let total = 0;
for (const item of items) {
console.log('Processing item:', item); // 👈 Debug
total += item.price;
console.log('Partial total:', total); // 👈 Debug
}
console.log('Final total:', total); // 👈 Debug
return total;
}
Pros: Quick, works anywhere Cons: Need to clean up after, no pause capability
2. Debugger with Breakpoints (The most powerful)
function calculateTotal(items) {
debugger; // 👈 Code will pause here
let total = 0;
for (const item of items) {
total += item.price; // You can set breakpoint here
}
return total;
}
Pros: Inspect variables live, step through execution Cons: Requires learning the tool
3. Structured Logging (The most professional)
import logger from './logger';
function calculateTotal(items) {
logger.debug('Starting calculation', { itemCount: items.length });
try {
const total = items.reduce((sum, item) => sum + item.price, 0);
logger.info('Calculation completed', { total });
return total;
} catch (error) {
logger.error('Error in calculation', { error, items });
throw error;
}
}
Pros: Persistent, searchable, doesn’t modify behavior Cons: More initial setup
The Debugging Process
┌─────────────────────────────────────────────────────────────┐
│ DEBUGGING CYCLE │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. REPRODUCE 2. HYPOTHESIZE 3. TEST │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Does it │ → │ What could│ → │ Add logs │ │
│ │ always │ │ cause │ │ or │ │
│ │ fail? │ │ this? │ │breakpoints│ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ ↑ ↓ │
│ │ │ │
│ 6. VERIFY 5. FIX 4. ANALYZE │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Does fix │ ← │ Modify │ ← │ Was the │ │
│ │ work? │ │ the code │ │ hypothesis│ │
│ │ No │ │ │ │ correct? │ │
│ │ regression│ │ │ │ │ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Debug Tools by Language
| Language | Tool | Command/Shortcut |
|---|---|---|
| JavaScript | Chrome DevTools | F12 → Sources |
| Python | pdb / debugpy | import pdb; pdb.set_trace() |
| Java | IntelliJ Debugger | Shift+F9 |
| C# | Visual Studio | F5 |
| Node.js | VS Code Debugger | F5 |
| React | React DevTools | Chrome Extension |
Real-World Example: Debugging a Login
The problem
“Users can’t log in. The form doesn’t do anything when submitted.”
Step 1: Reproduce
// Try to login and observe in console
form.addEventListener('submit', handleLogin);
Step 2: Add strategic logs
async function handleLogin(event) {
console.log('1. Submit event fired'); // Does it execute?
event.preventDefault();
console.log('2. preventDefault executed');
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
console.log('3. Data:', { email, password: '***' });
try {
console.log('4. Sending request...');
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ email, password })
});
console.log('5. Response:', response.status);
const data = await response.json();
console.log('6. Data:', data);
} catch (error) {
console.error('7. Error:', error); // 🐛 Here it is!
}
}
Step 3: Find the bug
Console:
1. Submit event fired
2. preventDefault executed
3. Data: { email: "user@test.com", password: "***" }
4. Sending request...
7. Error: TypeError: Failed to fetch // 🐛 FOUND IT!
Step 4: Investigate further
// The error indicates a network/CORS problem
// Check Network tab → Request blocked by CORS
Step 5: Fix
// Backend needs CORS headers
// Or use proxy in development
const response = await fetch('/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json' // 🔧 This header was missing
},
body: JSON.stringify({ email, password })
});
Advanced Techniques
Rubber Duck Debugging
Explain the problem to an object (like a rubber duck). By verbalizing the problem, you often find the solution.
Binary Search Debugging
If you have a bug in 1000 lines of code:
- Comment out half (lines 500-1000)
- Does the bug persist? → It’s in lines 1-500
- Comment out half of that range
- Repeat until you find the exact line
Time-Travel Debugging
Some tools allow you to “go back in time”:
- Redux DevTools (JavaScript)
- rr (C/C++)
- Chronon (Java)
Debugging Anti-patterns
| Anti-pattern | Problem | Best practice |
|---|---|---|
| Random changes | ”Let me try this and see if it works” | Form a hypothesis first |
| Ignoring stack trace | Googling without reading the error | Read the complete message |
| Not reproducing first | Assuming you know the problem | Always reproduce first |
| Debugging in production | Modifying live code | Use staging/local |
| Not writing tests | The bug comes back later | Add failing test before the fix |
The Debugger’s Mantra
"Don't guess. Observe."
"If you can't reproduce it, you can't fix it."
"The code does exactly what you told it, not what you wanted."
Related terms
- [[Bug]] - The error we’re looking for
- [[Breakpoint]] - Point where we pause execution
- [[Stack Trace]] - Trail of calls leading to the error
- [[Logging]] - Event recording for analysis
Remember: Debugging is a skill that improves with practice. The best debuggers aren’t those who know the most, but those who ask and observe the best.