개발 slecs

설정이 빌드마다 조용히 초기화되던 버그 수정

목차

pdf2api의 converter 기본값이 명시적으로 설정되지 않아서, 빌드/배포 과정에서 설정이 자동으로 초기값으로 되돌아가는 문제를 만났다. 이 글에서는 이 종류의 버그가 왜 발생하는지, 그리고 어떻게 방지할 수 있는지 회고해본다.

조용한 오동작의 위험성

"silently revert"라는 표현이 정확히 이 버그의 핵심이다. 사용자 입장에서는 명백한 에러 메시지도, 경고 로그도 없다. 그저 특정 상황에서 기능이 예상과 다르게 작동할 뿐이다. 배포 후 로컬 테스트에서는 잘 작동했던 기능이, 빌드 프로세스를 거친 후 프로덕션 환경에서만 문제가 드러나는 식이다.

이 경우, API 라우트(extract, translate)에서 PDF 변환을 처리할 때 converter 옵션이 "live" (즉, 실시간 변환 모드)로 동작해야 하는데, 빌드 후에는 기본값(아마도 캐시된 데이터나 프리셋 기반 변환)으로 회귀하고 있었다. 사용자가 명시적으로 설정을 변경했음에도 불구하고, 배포 과정에서 그 설정이 손실되는 것이다.

명시적 기본값의 부재

이런 버그가 발생하는 근본 원인은 대부분 다음 중 하나다:

  1. 암시적(implicit) 기본값에 의존 — 코드 어딘가에서 "converter는 특별히 설정하지 않으면 live 모드가 자동으로 활성화된다"고 가정
  2. 설정 파일의 병합/덮어쓰기 — 환경 변수나 설정 객체 병합 시 순서 문제로 기본값이 명시적 설정을 덮음
  3. 빌드 시 상태 초기화 — 번들링이나 트리 쉐이킹 과정에서 런타임 설정이 손실됨

변경된 파일들(src/app/api/extract/route.ts, src/app/api/translate/route.ts, src/app/home-client.tsx)을 보면, 여러 곳에서 converter를 참조하고 있다. 각 API 라우트에서 개별적으로 기본값을 설정하는 방식이 아니라, 한 곳에서 명시적으로 기본값을 선언하고 그것을 공유하는 구조로 변경했을 것으로 추측된다.

해결 방법: 명시적 기본값 선언

가장 직관적인 해결책은 converter의 기본값을 코드에 명시적으로 박아 넣는 것이다.

// ❌ 나쁜 예: 암시적 기본값에 의존
const converter = config.converter || undefined;
// 빌드 후 config 객체가 재설정되면 undefined가 되고, 어딘가의 fallback이 작동

// ✅ 좋은 예: 명시적 기본값 선언
const converter = config.converter ?? 'live';
// 또는
const DEFAULT_CONVERTER = 'live';
const converter = config.converter || DEFAULT_CONVERTER;

이렇게 하면 런타임에 config 객체의 상태와 무관하게, 기본값이 항상 명시적으로 결정된다. 빌드 프로세스가 어떻게 변하든, 코드 자체가 의도한 기본값을 유지한다.

변경이 미친 영향

API 라우트 두 개(extract, translate)가 동시에 수정된 것은 이들이 동일한 converter 설정을 공유한다는 뜻이다. 하나의 converter 기본값이 여러 API 엔드포인트에 영향을 미칠 수 있는 상황에서, 기본값의 명시성은 더더욱 중요하다.

클라이언트 코드(home-client.tsx)의 변경은 아마도 두 가지 중 하나일 것이다:
- 현재 converter 상태를 사용자에게 표시하는 부분을 수정
- 클라이언트가 converter 옵션을 변경할 때, 그 값이 제대로 API에 전달되도록 개선

회고: 기본값을 어떻게 관리할 것인가

이 경험에서 배운 패턴들:

방식 장점 단점
환경 변수 배포 시 동적으로 변경 가능 기본값이 암시적일 수 있음
설정 파일 명확한 의도 표현 파일 병합 시 실수 가능
코드 하드코딩 가장 명시적, 빌드 후 변경 불가 환경별 차이 처리 어려움
코드 기본값 + 환경 변수 오버라이드 명시적 기본값 + 유연성 순서 관리 필요

이번 fix는 마지막 패턴을 택한 것 같다. 코드에 명시적 기본값을 두고, 필요하면 설정으로 오버라이드할 수 있는 구조.

또 하나 중요한 교훈은, "silent revert" 같은 현상을 조기에 탐지하기 위해서는 로깅이 중요하다는 것이다.

const converter = config.converter ?? 'live';
console.log(`[pdf2api] Using converter mode: ${converter}`);
// 또는 구조화된 로그
logger.info('converter_initialized', { mode: converter, source: config.converter ? 'config' : 'default' });

이런 식으로 초기화 시점에 어떤 값이 사용되는지 기록하면, 빌드 후 설정이 바뀌는 현상을 훨씬 빠르게 발견할 수 있다.

특히 팀 규모가 커질수록, 여러 사람이 같은 설정을 건드릴 수 있을수록, 이런 "조용한 버그"는 더 자주 발생한다. 초기 단계에 명시성과 관찰성(observability)을 좌표축으로 삼으면, 나중의 디버깅 고통을 많이 줄일 수 있다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.