code:debug
Code Debug
Systematic debugging workflow to find and fix bugs efficiently. Never guess — always narrow down the problem through systematic elimination.
The Debugging Mindset
| Bad | Good |
|---|---|
| "I think it's..." | "Let me verify..." |
| Changing random things | Binary search narrowing |
| Hoping it'll work | Verifying each hypothesis |
| Moving on after it works | Adding regression test |
The Five-Step Workflow
Step 1: Reproduce
Create the smallest possible reproduction case.
Questions to answer:
- What exactly triggers the bug?
- Can I make it happen on demand?
- What's the minimal input that causes it?
Techniques:
- Extract exact steps from bug report
- Remove unrelated factors
- Create a minimal test case
Output: "I can reproduce the bug by [exact steps]."
Step 2: Isolate
Narrow down where the bug lives using binary search.
Binary search strategies:
- Comment out half the code → does it still fail?
- Isolate by layer: is it the UI, service, or data layer?
- Isolate by file: which file contains the bug?
- Isolate by function: which function causes the issue?
Git bisect (for regression bugs):
git bisect start
git bisect bad # current commit is broken
git bisect good <last-working-commit>
# Run tests, mark good/bad
git bisect reset # done
Output: "The bug is in [specific file/function/component]."
Step 3: Form Hypothesis
Make a testable guess about the root cause.
Good hypothesis:
- Specific: "The user ID is undefined because..."
- Testable: Can verify with a test or log
- Grounded: Based on evidence, not guess
Questions to ask:
- Why does this happen?
- What are the preconditions?
- What's the actual vs expected behavior?
- What changed recently?
Output: "I hypothesize that [root cause] because [evidence]."
Step 4: Fix
Implement the fix based on your hypothesis.
Rules:
- Make minimal changes
- Don't refactor while fixing (separate concerns)
- Write failing test first if possible
- Consider edge cases
Fix patterns:
- Missing value → Add null check or default
- Wrong value → Correct the logic
- Exception → Handle the error case
- Logic error → Fix the condition
Output: "Fix applied: [brief description]."
Step 5: Verify
Confirm the fix works and doesn't break anything.
Verification steps:
- Run the reproduction case → should pass now
- Run related tests → should pass
- Run full test suite → should pass
- Add regression test → prevents future breakage
Output: "Fix verified. Tests passing. Regression test added."
Debugging Techniques
Print Debugging
Quick and dirty, but sometimes the fastest way.
When to use:
- Quick checks in development
- When debugger isn't available
- Understanding flow in unfamiliar code
Best practices:
- Print at entry/exit of functions
- Print variable values at key points
- Remove print statements before committing
- Consider structured logging instead
Debugger
More powerful than print debugging.
When to use:
- Complex state to inspect
- Stepping through logic
- Evaluating expressions in context
See references/language-tools.md for language-specific debugger commands.
Logging
Better than print for production issues.
Strategies:
- Add context: request ID, user ID, correlation IDs
- Log at appropriate levels: DEBUG, INFO, WARN, ERROR
- Don't log sensitive data
- Structured logging (JSON) for easier parsing
See references/techniques.md for logging patterns.
Binary Search
Halving the search space.
Strategies:
- Comment out code blocks
- Test with half the data
- Compare working vs broken configurations
- Git bisect for regressions
Rubber Ducking
Explain the problem out loud (or to a rubber duck).
Process:
- Describe the problem in detail
- Explain what you expect to happen
- Explain what's actually happening
- Often the solution becomes clear mid-explanation
Common Bug Patterns
Null/Undefined Errors
Symptoms: Cannot read property X of undefined
Debug approach:
- Find where the value becomes undefined
- Trace back where it should come from
- Add guard or fix source
Fix patterns:
// Before
const name = user.profile.name;
// After
const name = user?.profile?.name ?? 'Unknown';
// or
if (!user?.profile) return;
const name = user.profile.name;
Race Conditions
Symptoms: Intermittent failures, flaky tests
Debug approach:
- Identify async operations
- Find timing dependencies
- Add delays or force ordering
Fix patterns:
- Use async/await properly
- Add proper synchronization
- Consider immutable state
Logic Errors
Symptoms: Wrong output, wrong behavior
Debug approach:
- Trace through the logic manually
- Compare expected vs actual at each step
- Find the first step that diverges
Fix patterns:
- Fix the condition
- Correct the calculation
- Update the state correctly
Performance Issues
Symptoms: Slow, memory leaks, timeouts
Debug approach:
- Measure first (don't guess)
- Identify hot paths
- Optimize the bottleneck
See code:perf skill for detailed performance debugging.
Skill Loading
Check available skills for additional debugging support:
- If dealing with performance issues → load code:perf
- If security vulnerability suspected → load code:security
- If debugging tests → load oracle:testing
Output Format
After each debugging session, summarize:
## Debug Summary
**Problem:** [One sentence]
**Root Cause:** [What actually was wrong]
**Fix:** [How you fixed it]
**Verification:** [Test results]
**Prevention:** [Regression test added?]
This helps future-you understand what happened.
More from martinffx/claude-code-atelier
python:architecture
Python application architecture with functional core, effectful shell, DDD, and data modeling. Use when designing application layers, separating pure business logic from IO, defining domain models, implementing validation, or structuring bounded contexts.
14python:monorepo
Python monorepo architecture with uv workspaces, mise, and apps/packages pattern. Use when setting up project structure, configuring workspaces, managing dependencies across packages, or designing multi-app Python repositories.
13python:build-tools
Python project tooling with uv, mise, ruff, basedpyright, and pytest. Use when setting up pyproject.toml, running builds, typechecking, configuring tests, linting, formatting, or managing Python environments.
12python:modern-python
Modern Python language features and typing patterns. Use when writing type hints, using generics, implementing pattern matching, working with async/await, or leveraging Python 3.10+ features.
12python:testing
Stub-Driven TDD and layer boundary testing with pytest. Use when writing tests, deciding what to test, testing at component boundaries, or implementing test-driven development.
12python:sqlalchemy
SQLAlchemy ORM patterns for Python database access. Use when defining models, writing queries, implementing upserts, working with JSON columns, or managing database sessions.
12