April 24, 2026

좋은 오류 메시지가 시간을 절약하다

개발자는 자주 오류를 보고 오류의 메시지를 읽어야 해요. 그래서 나쁜 오류 메시지 시간 많이 필요할 수 있잖아요. 오류의 안내가 없으면 사람들 추측하기 시작해야 돼요.

나쁜 오류 예: - 프로세스는 비정상 종료 코드만 하하지마! 제발, 표준 에러에 오류를 설명해주세요! - 파일을 못 찾았다고요. 끝. 무슨 파일!, 무슨 파일 못 차았어요? - 등

근데 진짜 좋은 예도 있어요: Babashka HTTP client.

Babaska 선생님
Figure 1. Babaska 선생님

REPL에서:

(http/post "http://gamlor.info/nowhere"
           {:headers {"Authorization" "Bearer open-sesame"}})
=> Execution error (ExceptionInfo) at babashka.http-client.interceptors/fn (interceptors.clj:251).
Exceptional status code: 404

근데, 오류 정보를 더 잘 살펴보면 정보 많이 생기다:

REPL에서:

*e
=>
#error
{:cause "Exceptional status code: 404",                                                         ; 우류 매시지
 :data {:status 404,                                                                            ; HTTP 대답의 코드
        :body "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">                             ; HTTP 대답의 본문
               <html><head>
               <title>404 Not Found</title>
               </head><body>
               <h1>Not Found</h1>
               <p>The requested URL was not found on this server.</p>
               <p>Additionally, a 404 Not Found
               error was encountered while trying to use an ErrorDocument to handle the request.</p>
               </body></html>
               ",
        :version :http2,                                                                        ; 어느 HTTP 버전
        :headers {":status" "404",                                                              ; HTTP 대답의 헤더
                  "content-length" "315",
                  "content-type" "text/html; charset=iso-8859-1",
                  "date" "Mon, 20 Apr 2026 19:24:09 GMT",
                  "server" "Apache"},
        :uri #object [java.net.URI 0x5a3fadf4 "https://gamlor.info/nowhere"],                   ; 어느 URI를 사용샜어요. HTTP 리디렉션이 URI를  바꿀 수 있어요.
        :request {:headers {:accept "*/*",                                                      ; HTTP 요청의 헤더
                            :accept-encoding ["gzip" "deflate"],
                            :user-agent "babashka.http-client/0.4.23",
                            "Authorization" "Bearer open sesame"},
                  :uri #object [java.net.URI 0x5a3fadf4 "http://gamlor.info/nowhere"],          ; 어느 URI 요청 시작했기. HTTP 리디렉션이 URI를  바꿀 수 있어요.
                  :method :get}},                                                               ; 어느 HTTP 동사
 :via [{:type clojure.lang.ExceptionInfo,                                                       ; 중첩된 Exception 정보. 이 예에 중첩 안 됬어요.
        :message "Exceptional status code: 404",
        :data {:status 404,
               :body "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">
                      <html><head>
                      <title>404 Not Found</title>
                      </head><body>
                      <h1>Not Found</h1>
                      <p>The requested URL was not found on this server.</p>
                      <p>Additionally, a 404 Not Found
                      error was encountered while trying to use an ErrorDocument to handle the request.</p>
                      </body></html>
                      ",
               :version :http2,
               :headers {":status" "404",
                         "content-length" "315",
                         "content-type" "text/html; charset=iso-8859-1",
                         "date" "Mon, 20 Apr 2026 19:24:09 GMT",
                         "server" "Apache"},
               :uri #object [java.net.URI 0x5a3fadf4 "https://gamlor.info/nowhere"],
               :request {:headers {:accept "*/*",
                                   :accept-encoding ["gzip" "deflate"],
                                   :user-agent "babashka.http-client/0.4.23",
                                   "Authorization" "Bearer open sesame"},
                         :uri #object [java.net.URI 0x5a3fadf4 "https://gamlor.info/nowhere"],
                         :method :get}},
        :at [babashka.http_client.interceptors$fn__11817 invokeStatic "interceptors.clj" 251]}], ; 스택 트레이스
 :trace [[babashka.http_client.interceptors$fn__11817 invokeStatic "interceptors.clj" 251]
         [babashka.http_client.interceptors$fn__11817 invoke "interceptors.clj" 246]
         [babashka.http_client.internal$then invokeStatic "internal.clj" 296]
         [babashka.http_client.internal$then invoke "internal.clj" 290]
         [babashka.http_client.internal$request$fn__11936 invoke "internal.clj" 329]
         [clojure.lang.PersistentList reduce "PersistentList.java" 146]
         [clojure.core$reduce invokeStatic "core.clj" 6964]
         [clojure.core$reduce invoke "core.clj" 6947]
         [babashka.http_client.internal$request invokeStatic "internal.clj" 327]
         [babashka.http_client.internal$request invoke "internal.clj" 303]
         [babashka.http_client$request invokeStatic "http_client.clj" 125]
         [babashka.http_client$request invoke "http_client.clj" 100]
         [babashka.http_client$get invokeStatic "http_client.clj" 132]
         [babashka.http_client$get invoke "http_client.clj" 127]
         [user$eval15344 invokeStatic "form-init8076736335536322939.clj" 1]
         [user$eval15344 invoke "form-init8076736335536322939.clj" 1]
         ...

이 오류는 개발자의 꿈 이예요. 정보가 다 있어요:

  • 혹시 HTTP 대답의 본문나 헤더 오류가 있어요? 정보 있어요.

  • 혹시 잘못된 HTTP 헤더 보냈어요? 정보 있어요.

  • 혹시 HTTP 리디렉션이 URI를 바꿨어요? 정보 있어요.

  • 어떻게 이 오류에 도착했어요? 정보 있어요.

그럼, 다음에는 우리가 오류를 쓰면 Babashka HTTP client 기억하고 정보를 충분히 추가하자!

Tags: 한국어 Development