Development Basic

Debug

The process of identifying, analyzing, and fixing errors (bugs) in code. A fundamental skill for every developer.

Pronunciation

/diːˈbʌɡ/
"dee-buhg"

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:

  1. Reproduce the problem
  2. Isolate the root cause
  3. Understand why it happens
  4. Fix the code
  5. 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

LanguageToolCommand/Shortcut
JavaScriptChrome DevToolsF12 → Sources
Pythonpdb / debugpyimport pdb; pdb.set_trace()
JavaIntelliJ DebuggerShift+F9
C#Visual StudioF5
Node.jsVS Code DebuggerF5
ReactReact DevToolsChrome 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:

  1. Comment out half (lines 500-1000)
  2. Does the bug persist? → It’s in lines 1-500
  3. Comment out half of that range
  4. 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-patternProblemBest practice
Random changes”Let me try this and see if it works”Form a hypothesis first
Ignoring stack traceGoogling without reading the errorRead the complete message
Not reproducing firstAssuming you know the problemAlways reproduce first
Debugging in productionModifying live codeUse staging/local
Not writing testsThe bug comes back laterAdd 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."
  • [[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.