디버깅 2026.02.08 📖 16분 분량

버그 찾기의 기술: 콘솔과 디버깅 도구 활용법

에러를 친구로 만드는 개발자의 필수 스킬

디버깅이 뭔가요?

코드를 작성하면 필연적으로 버그(에러)가 발생합니다. 디버깅은 이 버그를 찾아서 고치는 과정입니다. 처음에는 에러 메시지가 무섭게 느껴지지만, 익숙해지면 문제를 해결하는 단서가 됩니다.

"좋은 개발자는 에러가 없는 코드를 작성하는 사람이 아니라, 에러를 빠르게 찾아 해결하는 사람입니다."

1. Console.log - 디버거의 베스트 프렌드

기본 사용법

// 변수 값 확인
let name = "홍길동";
console.log(name);  // "홍길동"

// 여러 값 확인
let age = 25;
console.log("이름:", name, "나이:", age);

// 객체 확인
let person = { name: "홍길동", age: 25 };
console.log(person);  // {name: "홍길동", age: 25}

고급 활용

// 1. console.table - 배열이나 객체를 표로 표시
let users = [
    { name: "철수", age: 20 },
    { name: "영희", age: 22 }
];
console.table(users);

// 2. console.error - 에러 표시
console.error("심각한 에러 발생!");

// 3. console.warn - 경고 표시
console.warn("주의: 값이 비어있습니다");

// 4. console.time - 실행 시간 측정
console.time("반복문");
for (let i = 0; i < 100000; i++) {
    // 어떤 작업
}
console.timeEnd("반복문");  // "반복문: 2.345ms"

// 5. console.assert - 조건이 false일 때만 출력
let score = 50;
console.assert(score >= 60, "점수가 60점 미만입니다");

2. Chrome 개발자 도구

Console 탭 활용

F12를 눌러 개발자 도구를 열고 Console 탭으로 이동합니다.

// 콘솔에서 직접 JavaScript 실행 가능
document.querySelector('h1').textContent
// 결과: "심리 테스트 허브"

// 변수나 함수 확인
testController
// Controller 객체 확인 가능

에러 메시지 읽기

// 전형적인 에러 메시지
Uncaught TypeError: Cannot read property 'textContent' of null
    at script.js:15

// 해석:
// - Uncaught TypeError: 잡히지 않은 타입 에러
// - Cannot read property 'textContent' of null: null의 textContent를 읽을 수 없음
// - at script.js:15: script.js 파일의 15번째 줄에서 발생

// 원인: 요소를 찾지 못했거나 잘못된 선택자
const element = document.querySelector('#wrongId');
console.log(element);  // null
element.textContent = "안녕";  // ← 여기서 에러!

자주 보는 에러들

1) ReferenceError

// 선언하지 않은 변수 사용
console.log(userName);  // ReferenceError: userName is not defined

// 해결: 변수 먼저 선언
let userName = "홍길동";
console.log(userName);

2) SyntaxError

// 문법 오류
let name = "홍길동;  // SyntaxError: 따옴표 안 닫음

// 해결: 문법 수정
let name = "홍길동";

3) TypeError

// 잘못된 타입 사용
let number = 5;
number.toUpperCase();  // TypeError: number.toUpperCase is not a function

// 해결: 올바른 타입 사용
let text = "hello";
text.toUpperCase();  // "HELLO"

3. Breakpoint로 디버깅하기

코드 실행을 중간에 멈추고 변수 값을 확인할 수 있습니다.

사용 방법

  1. Chrome 개발자 도구에서 Sources 탭 열기
  2. 왼쪽에서 JavaScript 파일 선택
  3. 중단하고 싶은 줄 번호 클릭 (파란 점 생성)
  4. 페이지 새로고침 또는 코드 실행
  5. 해당 줄에서 실행이 멈춤
  6. 변수에 마우스 올려서 값 확인

디버거 버튼

  • Resume (▶): 다음 breakpoint까지 계속 실행
  • Step Over (↷): 다음 줄로 이동
  • Step Into (↓): 함수 안으로 들어가기
  • Step Out (↑): 함수에서 나오기

코드에서 breakpoint 설정

function calculateTotal(price, quantity) {
    debugger;  // ← 여기서 자동으로 멈춤
    let total = price * quantity;
    return total;
}

calculateTotal(1000, 5);

4. 흔한 버그 패턴과 해결법

패턴 1: 요소를 찾지 못함

// 문제
const button = document.querySelector('#myButton');
button.addEventListener('click', handleClick);
// TypeError: Cannot read property 'addEventListener' of null

// 원인
// 1. ID가 틀림: #myButton vs #myBtn
// 2. HTML에 요소가 없음
// 3. JavaScript가 HTML보다 먼저 실행됨

// 해결 1: ID 확인
const button = document.querySelector('#myBtn');

// 해결 2: 존재 여부 확인
const button = document.querySelector('#myButton');
if (button) {
    button.addEventListener('click', handleClick);
} else {
    console.error('버튼을 찾을 수 없습니다');
}

// 해결 3: DOMContentLoaded 사용
document.addEventListener('DOMContentLoaded', () => {
    const button = document.querySelector('#myButton');
    button.addEventListener('click', handleClick);
});

패턴 2: 함수가 실행되지 않음

// 문제
button.addEventListener('click', handleClick());
//                                         ↑ 괄호가 문제!

// 괄호를 붙이면 함수를 즉시 실행함
// 이벤트가 발생했을 때가 아니라 지금 바로 실행됨

// 해결
button.addEventListener('click', handleClick);  // 괄호 제거
button.addEventListener('click', () => handleClick());  // 또는 화살표 함수로

패턴 3: 무한 루프

// 문제
let i = 0;
while (i < 10) {
    console.log(i);
    // i++를 잊어버림!
}
// 페이지가 멈춤

// 해결
let i = 0;
while (i < 10) {
    console.log(i);
    i++;  // 증가 코드 추가
}

5. 체계적인 디버깅 프로세스

1단계: 에러 재현하기

어떤 상황에서 에러가 발생하는지 정확히 파악합니다.

2단계: 에러 메시지 읽기

콘솔의 에러 메시지를 자세히 읽습니다. 어떤 파일의 몇 번째 줄인지 확인합니다.

3단계: console.log로 추적

function processData(data) {
    console.log('1. 함수 시작, data:', data);
    
    const filtered = data.filter(item => item.active);
    console.log('2. 필터링 완료, filtered:', filtered);
    
    const result = filtered.map(item => item.name);
    console.log('3. 매핑 완료, result:', result);
    
    return result;
}

4단계: 이진 탐색으로 범위 좁히기

코드의 절반씩 주석 처리하며 어디서 문제가 발생하는지 찾습니다.

5단계: 구글 검색

에러 메시지를 그대로 구글에 검색하면 대부분 해결책이 나옵니다.

// 검색 팁
"TypeError: Cannot read property 'textContent' of null" javascript
"JavaScript array forEach not working"
"How to fix CORS error"

6. 예방이 최선

1) 한 번에 조금씩 작성하기

// ❌ 나쁜 습관: 100줄 작성 후 테스트
// 에러가 어디서 발생했는지 찾기 어려움

// ✅ 좋은 습관: 5-10줄 작성 후 테스트
// 문제가 생겨도 방금 작성한 코드만 확인하면 됨

2) 의미 있는 변수명 사용

// ❌ 나쁜 예
let x = document.querySelector('#a');
let y = x.textContent;

// ✅ 좋은 예
let nameInput = document.querySelector('#nameInput');
let userName = nameInput.value;

3) 주석 활용

// ✅ 복잡한 로직에는 주석 추가
// 사용자 입력값 검증
if (input.value.trim() === '') {
    // 빈 값이면 경고 표시
    showWarning('값을 입력하세요');
    return;
}

🐛 디버깅 체크리스트

  • □ 콘솔에 에러 메시지가 있는가?
  • □ 변수에 예상한 값이 들어있는가?
  • □ 요소를 제대로 선택했는가?
  • □ 함수가 실행되는가?
  • □ 타입이 올바른가? (숫자 vs 문자열)
  • □ 괄호, 중괄호, 따옴표를 닫았는가?
  • □ 철자가 정확한가?
"에러 메시지는 적이 아니라 문제를 알려주는 친절한 가이드입니다. 두려워하지 말고 천천히 읽어보세요!"

디버깅 실력은 경험을 통해 늡니다. 에러를 만나도 당황하지 말고, 차근차근 원인을 찾아가 보세요. 다음 글에서는 Git을 사용한 버전 관리를 배워보겠습니다.