미들웨어-퍼펙트-심포니

발행: (2025년 11월 30일 오전 11:59 GMT+9)
9 min read
원문: Dev.to

Node.js에서 오류 처리의 진화

40 년의 개발 경력을 가진 베테랑으로서, 저는 Node.js 세계에서 오류와 싸워온 긴 진화 역사를 직접 목격했습니다. 초기 Node.js 개발자라면 모두 “피라미드”에 압도당하던 두려움을 기억할 것입니다. 이 error‑first 콜백 스타일은 이론적으로는 가능하지만, 비즈니스 로직이 복잡해질수록 코드는 오른쪽으로 무한히 뻗어 죽음의 피라미드가 됩니다.

Promise: 콜백 지옥에서의 구조

Promise의 등장으로 우리는 콜백 지옥에서 구원받았습니다. .then().catch()를 사용해 더 평평하고 가독성 좋은 비동기 체인을 만들 수 있었습니다. 훨씬 나아졌죠!

하지만 새로운 문제가 생겼습니다:

  • .then() 안에서 다음 Promise를 return하는 것을 잊으면 체인이 예상치 않게 계속됩니다.
  • .catch() 안에서 오류를 다시 throw하는 것을 잊으면 조용히 실패가 발생합니다.

Async/Await: 동기식 스타일의 비동기

async/await는 비동기 코드를 마치 동기식처럼 작성하게 해 주는 신의 선물과 같습니다. 완벽해 보이죠?

하지만 여전히 프로그래머의 규율에 의존합니다. 오류가 발생할 가능성이 있는 모든 비동기 호출을 try…catch 블록으로 감싸야 합니다.

JavaScript 오류 처리의 한계

JavaScript에서 오류는 단지 무시하기 쉬운 값일 뿐입니다. nullundefined는 마치 유령처럼 코드 곳곳을 떠다닙니다. 모든 오류를 올바르게 처리하려면 다음에 의존해야 합니다:

  • 엄격한 사양
  • 린터 도구
  • 개인적인 규율

이 모든 것은 본질적으로 신뢰하기 어렵습니다.

Rust 기반 웹 프레임워크 발견

Rust‑based 웹 프레임워크를 만나기 전까지 저는 미들웨어에 대한 이해가 제한적이었습니다. 이 프레임워크는 전통적인 next() 콜백 패턴을 완전히 포기합니다. 대신 hooksdeclarative macros 시스템을 사용해 서버 혹은 특정 라우트에 직접 연결합니다. 흐름이 명시적이며, 로직이 영향을 받는 코드와 함께 위치합니다.

미들웨어 종류와 라이프사이클 훅

  • request_middleware: 라우트 핸들러 이전에 실행
  • response_middleware: 라우트 핸들러 이후에 실행
  • Connection hooks: 새로운 연결이 수립될 때 트리거
  • Panic hooks: 패닉이 발생할 때 트리거

이들은 하나의 형태 없는 체인이 아니라, 특정 작업을 위한 구체적인 도구들입니다.

로깅 및 인증 구현

이 프레임워크에서 미들웨어 함수는 속성으로 식별되는 독립적인 컴포넌트입니다. 실행 순서는 order 매개변수로 명시적으로 정의되어 모호함이 없습니다.

  • Auth 미들웨어는 더 이상 next() 콜백이 필요하지 않습니다. 대신 Context 객체를 받아서:
    • 하위 핸들러를 위한 데이터를 첨부
    • 처리를 중단하고 직접 응답을 전송

get_user_profile 함수도 더 명시적입니다. 매크로를 사용해 user_id가 컨텍스트에 존재함을 선언하므로, 컴파일 타임에 검증되는 의존성이 됩니다. 이는 코드가 스스로 문서화되고 훨씬 안전해짐을 의미합니다.

Hook‑기반 선언형 접근의 장점

  • 명확성: 전체 요청 라이프사이클이 속성으로 표현됩니다.
  • 추론 용이: 작업 순서를 쉽게 파악할 수 있습니다.
  • 재사용성: 집중된, 재사용 가능하고 테스트하기 쉬운 미들웨어를 작성할 수 있습니다.

수년간 저는 미들웨어가 강력한 기능만큼이나 어쩔 수 없이 지저분하다고 생각했습니다. 이 프레임워크는 저를 틀렸음을 증명했습니다. 강력하고 유연한 미들웨어 시스템이 명확성, 보안, 개발자 정신건강과 공존할 수 있음을 보여줍니다.

고급 미들웨어 종류

Panic Hooks

  • 런타임 오류를 우아하게 처리
  • 사후 분석을 위한 상세 오류 정보 로그
  • 연결이 끊어지는 대신 친절한 오류 페이지 반환

Connection Hooks

  • 새로운 연결이 수립될 때 초기화 작업 수행(예: 타임아웃 설정, 연결 정보 로그)

조건부 및 비동기 미들웨어

프레임워크의 미들웨어 시스템은 조건부 실행을 지원합니다. 다음을 기준으로 특정 미들웨어 실행 여부를 결정할 수 있습니다:

  • 요청 경로
  • 헤더
  • 기타 속성

모든 미들웨어는 비동기이며, 데이터베이스 조회, 파일 작업 등 다른 비동기 작업을 전체 서버를 블로킹하지 않고 수행할 수 있어 고동시성 상황에서 필수적입니다.

실제 영향

  • 복잡한 비즈니스 로직 단순화: 기존 Express 앱에서는 여러 미들웨어를 조율하려면 순서를 신중히 정하고, 상태를 수동으로 전달하며, 오류 처리를 광범위하게 해야 했습니다. 새로운 프레임워크에서는 올바른 order 파라미터만 지정하면 프레임워크가 실행을 담당합니다.
  • 감사 기능: 포괄적인 감사 로그를 구현하려면 이전에 여러 라우트에 로깅 코드를 흩뿌려야 했습니다. 단일 response 미들웨어 하나만으로 전체 감사 커버리지를 달성해 재사용성과 유지보수성이 크게 향상되었습니다.
  • 핵심 아키텍처: 몇 달간 사용한 뒤, 미들웨어 시스템은 프로젝트 아키텍처의 핵심이 되었습니다. 로깅, 성능 모니터링, 보안 검사와 같은 기능을 추가해도 기존 비즈니스 로직에 영향을 주지 않습니다.

결론

경험 많은 개발자로서 저는 아키텍처 설계의 중요성을 깊이 이해하고 있습니다. 뛰어난 미들웨어 설계를 갖춘 프레임워크를 선택하면 개발 효율이 상승할 뿐 아니라 프로젝트의 장기 유지보수성도 결정됩니다. 이 Rust‑based 프레임워크는 그 점에서 의심할 여지 없는 모델입니다.

앞으로도 미들웨어 설계를 웹 프레임워크의 핵심에 두는 기술 혁신이 계속되길 기대합니다. 이러한 변혁에 참여하고 이를 알리는 일은 영광이자 큰 흥분을 안겨줍니다.

Back to Blog

관련 글

더 보기 »