PH pullh
입문 블로그 / 에러 메시지를 처음 읽는 사람을 위한 순서
첫걸음 6분 Beginner

에러 메시지를 처음 읽는 사람을 위한 순서

에러 화면을 보면 마음이 급해지지만, 사실 읽는 순서만 잡아도 절반은 해결된다. 초보자용 독해 순서를 정리했다.

에러 읽기 커버 이미지

에러 메시지를 처음 보면 내가 뭘 크게 망쳤나라는 느낌부터 든다. 하지만 대부분의 에러는 코드 전체가 아니라 아주 작은 지점을 가리킨다.

문제는 초보자가 그 작은 힌트를 어디서 읽어야 하는지 모른다는 데 있다. 그래서 화면을 전부 해석하려다가 더 혼란스러워진다.

에러 화면은 감정을 담은 글이 아니라 서식이 정해진 보고서다. 서식을 알고 나면 같은 화면을 읽는 데 걸리는 시간이 몇 분에서 몇 초로 줄어든다.

항상 같은 순서로 본다

첫째, 어떤 파일의 몇 번째 줄인지 확인한다. 둘째, 실제 문제 단어가 무엇인지 찾는다. 셋째, 지금 고치려는 줄이 원인인지 아니면 증상인지 생각한다.

이 순서가 몸에 붙으면 에러가 무섭기보다 문제 위치를 알려 주는 메모처럼 느껴지기 시작한다. 반대로 순서 없이 화면을 훑으면, 가장 눈에 띄는 낯선 단어를 붙잡고 엉뚱한 곳을 고치게 된다.

화면에서 정보가 실제로 있는 자리

파이썬 트레이스백은 위에서 아래로 갈수록 호출이 깊어진다. 그래서 초보자에게는 맨 아래 두 줄이 가장 밀도가 높다. 마지막 줄이 에러의 종류와 이유, 그 바로 위가 그 일이 벌어진 파일과 줄 번호다. 중간에 낀 프레임들은 대개 라이브러리 내부이고, 내가 고칠 수 있는 코드가 아니다.

TRACEBACK

Traceback (most recent call last):
  File "main.py", line 12, in <module>
    print(summary(scores))
  File "main.py", line 8, in summary
    return total / len(scores)
ZeroDivisionError: division by zero

읽는 자리는 두 곳이다. 마지막 줄 ZeroDivisionError와, 그 바로 위 main.py 8번째 줄.

여기서 8번 줄을 고치려고 len(scores)에 1을 더하면 에러는 사라지지만 계산은 틀린다. 진짜 물음은 왜 scores가 비었는가이고, 그 답은 12번 줄 위쪽, 즉 리스트를 채우는 코드에 있다. 에러가 난 줄과 원인이 있는 줄은 같지 않을 때가 훨씬 많다.

언어가 달라도 읽는 자리는 비슷하다

자바스크립트는 순서가 반대라 첫 줄에 에러 종류와 이유가 나오고, 그 아래 at으로 시작하는 줄들이 호출 경로다. 위치는 다르지만 찾는 정보는 똑같다. 무슨 종류의 에러인지, 어느 파일 몇 번째 줄인지, 그리고 그 사이에 내가 쓴 파일 이름이 보이는지다.

NODE

TypeError: Cannot read properties of undefined (reading 'name')
    at renderUser (/app/src/user.js:14:24)
    at /app/src/index.js:7:3

undefined의 name을 읽으려 했다는 뜻이다. name이 아니라 그 앞의 객체가 없는 것이다.

이 메시지에서 초보자가 자주 놓치는 단어는 undefined다. 문제는 name이라는 속성이 아니라, 그 속성을 가진 객체가 아예 오지 않았다는 사실이다. 그러면 다음 질문은 자연스럽게 정해진다. renderUser에 무엇을 넘겼는가, 그 값은 어디서 왔는가.

읽는 요령

에러 문장에서 명사 하나와 동사 하나만 뽑아 보십시오. division by zero는 나누기와 0, Cannot read properties of undefined는 읽기와 undefined입니다. 이 두 단어가 그대로 다음에 확인할 대상이 됩니다.

문법 에러와 실행 에러는 신호의 종류가 다르다

에러를 크게 두 종류로 나눠 두면 대응이 훨씬 빨라진다. 하나는 코드를 읽는 단계에서 나는 문법 에러이고, 다른 하나는 코드가 돌다가 나는 실행 에러다. 문법 에러는 프로그램이 한 줄도 실행되지 않았다는 뜻이고, 실행 에러는 거기까지는 잘 돌았다는 뜻이다. 이 차이만 알아도 어디를 볼지가 갈린다.

SYNTAX

  File "main.py", line 5
    if score > 80
                 ^
SyntaxError: expected ':'

캐럿 기호가 가리키는 자리는 잘못된 곳이 아니라, 파서가 더 못 읽고 멈춘 곳이다.

문법 에러에서 초보자가 자주 헤매는 지점이 여기다. 표시된 줄에 아무 문제가 없어 보인다면 대개 원인은 바로 위 줄에 있다. 괄호나 따옴표를 닫지 않으면 파서는 다음 줄까지 계속 읽다가 거기서 포기하기 때문이다. 5번 줄이 멀쩡한데 SyntaxError가 났다면 4번 줄의 열린 괄호부터 세어 보는 것이 순서다.

반대로 실행 에러는 그 줄까지는 정상적으로 도달했다는 정보를 준다. 그래서 이때는 문법이 아니라 값을 의심해야 한다. 그 줄에 등장하는 변수 하나하나에 대해 지금 여기에 무엇이 들어 있나를 묻는 것이, 코드를 다시 읽는 것보다 훨씬 빠르다.

에러를 봤을 때 바로 해볼 일

  • 문제가 난 줄의 위아래 3줄만 먼저 본다.
  • 변수 이름 오타, 괄호 누락, 따옴표 누락을 먼저 확인한다.
  • 트레이스백에서 내가 쓴 파일 이름이 나오는 가장 아래 줄을 찾는다.
  • 에러 문장에서 종류 이름과 핵심 명사 하나를 따로 뽑아 적는다.
  • 방금 바꾼 부분이 있다면 그 부분만 되돌려 보며 비교한다.
  • 검색할 때는 에러 문장 전체보다 핵심 구문 위주로 찾는다.

이 순서가 통하지 않을 때

모든 에러가 친절한 것은 아니다. 컴파일 언어에서는 문법 오류 하나가 수십 개의 에러로 번지는 일이 흔하다. 이때 열두 번째 에러부터 읽는 것은 시간 낭비다. 첫 번째 에러만 고치고 다시 실행하면 나머지가 통째로 사라지는 경우가 많다.

반대로 화면에 아무 에러도 없는데 결과만 틀린 경우도 있다. 이건 독해의 문제가 아니라 관찰의 문제라서, 이 글의 순서로는 풀리지 않는다. 그때는 중간값을 찍어 보며 어디까지 정상인지 경계를 찾는 쪽으로 방법을 바꿔야 한다. 순서를 지키는 것과 순서를 고집하는 것은 다르다.

주의

에러 문장을 그대로 검색해 나온 코드를 통째로 붙여 넣으면 에러는 사라져도 원인은 남습니다. 붙여 넣기 전에 그 코드가 무엇을 바꾸는지 한 문장으로 설명할 수 있어야 합니다.

에러는 실력 부족의 증거가 아니라 현재 상태를 보여 주는 안내문에 가깝다.

첫걸음

더 볼 것

언어마다 에러를 던지고 잡는 방식이 조금씩 다릅니다. 파이썬 예외 처리 가이드와 자바스크립트 에러 처리 가이드에서 같은 상황을 어떻게 다르게 표현하는지 비교해 보면, 메시지가 왜 그런 모양인지도 함께 이해됩니다. 언어별 대조는 에러 처리 비교에 정리해 두었습니다.

이 글의 포인트

  • 에러 메시지는 파일, 줄 번호, 핵심 단어 순서로 읽는다.
  • 에러가 난 줄과 원인이 있는 줄은 다를 때가 더 많다.
  • 처음부터 전체 코드를 보지 말고 문제 난 주변 몇 줄부터 본다.
  • 에러가 우수수 쏟아지면 첫 번째만 고치고 다시 실행한다.
  • 반복되는 독해 순서가 생기면 에러 공포가 많이 줄어든다.

Next Read

튜토리얼을 끝내도 코드가 안 써질 때

따라 칠 때는 이해한 것 같았는데, 혼자 하려면 아무것도 안 나오는 순간이 있다. 그 답답함을 넘는 연습법을 정리했다.