Files
llm-wiki/raw/blog-topics/env-example-drift-gate-gradle-2026-06-06.md

5.6 KiB

title, source_type, status, related_branches, related_projects, tags, created, status_label, target_audience, inspiration_url, archive_url
title source_type status related_branches related_projects tags created status_label target_audience inspiration_url archive_url
blog-topic / env-example-drift-gate-gradle-2026-06-06 blog-topic raw
feature-env-driven-runtime-configuration
ca-tmpl
blog-topic
ca-tmpl
gradle
configuration
12-factor
fail-fast
developer-experience
2026-06-06 ready-for-canonical backend-engineer

blog-topic: env-example-drift-gate-gradle-2026-06-06

Layer: raw/blog-topics/ — 작업에서 나온 블로그 글감 원석. canonical 정제 전 raw 후보.

Parent / 부모

글감 한 줄

".env.example 을 추가하려다 깨달은 것 — 우리 .env 는 이미 tracked 였다. drift 게이트의 정답 소스는 템플릿이 아니라 코드가 실제로 요구하는 surface 다."

핵심 논지

  • 흔한 패턴: secret 때문에 .env 를 gitignore 하고 redacted .env.example 을 commit. 하지만 .env.example 은 "작성 시점 스냅샷"이라 새 env 가 생겨도 갱신 안 돼 drift → 신규 합류자가 복사해 띄우면 누락 env startup 실패.
  • 반전(이 프로젝트의 실제 결정): ca-tmpl 은 src/.env 자체를 git-tracked 로 둔다(로컬 dev 기본값 포함, secret 은 로컬 sentinel). 이 경우 .env.examplepassword 만 가린 중복 사본이라 가치가 거의 없다. 처음엔 D7 문언대로 .env.example + verifyEnvExample 을 만들었다가, 리뷰에서 ".env 가 이미 tracked 인데 example 이 왜 필요?"라는 지적으로 제거 → task 를 verifyEnvKeys 로 rename.
  • 결론적 게이트(custom Gradle task verifyEnvKeys)는 template 파일이 아니라 코드 surface 를 기준으로 두 방향만 강제:
    1. application.yml${VAR}(inline default 없는 것=required) 가 전부 src/.env 에 존재(누락 0).
    2. src/.env 의 모든 키가 application.yml 어딘가 ${...} 로 실제 소비됨(orphan/stale 0).
  • inputs.files(...) 선언으로 Gradle up-to-date 캐싱과 호환, checkdependsOn 연결해 CI 필수 게이트화.
  • 교훈: ".env.example drift 막기"는 수단이지 목적이 아니다. 진짜 목적은 "코드가 요구하는 env 와 운영자가 가진 env 가 일치하는가". .env 가 tracked 라면 example 은 군더더기이고, 게이트는 application.yml ↔ .env 를 직접 보는 게 맞다.

왜 registry 기준이 아니라 application.yml surface 기준인가 (설계 결정)

  • contract registry(env-keys.yaml)는 여러 미구현 branch 의 키까지 포함 → registry 와 .env 를 1:1 강제하면 코드에 없는 phantom 키 수십 개를 넣어야 함(운영자가 무시할 값).
  • "운영자가 .env 만으로 앱을 띄울 수 있는가"가 진짜 목적 → 검증 기준은 실제 config surface(application.yml placeholder) 가 맞다. registry 는 governance SSOT 로 별도 유지.
  • 교훈: drift gate 의 "정답 소스"는 빌드 가능한 표면이어야지, 미래 계약을 담은 레지스트리가 아니다.

곁가지 주제

  • 12-factor §III config 와 APP_ prefix 전면 통일(외부 의존 env 와 시각 분리)의 트레이드오프.
  • boolean true/false-only, Duration 30s-only 같은 "기계적으로는 동등하나 팀 규약으로 1택" 결정을 어떻게 문서화/강제하나.

트리거 / Trigger

글감 / Topic seed

  • 한 문장 요지: .env.example drift를 막는 목적은 example 파일 유지가 아니라 실제 config surface와 실행 env key의 정합성을 검증하는 것이다.
  • 예상 제목 후보:
    • .env.example이 아니라 실제 config surface를 검증하기
    • Gradle task로 env key drift를 막는 방법

핵심 주장 후보 / Claim candidates

  • 사실 후보:
    • ca-tmpl은 env-driven runtime configuration branch에서 env key drift gate를 다뤘다.
    • tracked .envapplication.yml placeholder의 양방향 정합을 보는 방향이 글감의 핵심이다.
  • 의견/해석 후보:
    • drift gate의 정답 소스는 미래 registry가 아니라 현재 빌드 가능한 runtime surface여야 한다.

Outline seed

  1. .env.example은 snapshot이라 drift가 생기기 쉽다.
  2. tracked .env 정책에서는 example 사본보다 key surface 검증이 더 중요하다.
  3. Gradle verifyEnvKeys가 application config와 env key를 양방향으로 확인한다.

Canonical 전환 후보 / Canonical extraction candidates

  • wiki/projects/ca-tmpl/config-and-adapter-templates.md 후보:
    • env key drift gate와 .env tracked policy.
  • 필요한 추가 검증:
    • 실제 verifyEnvKeys 구현 여부와 현재 ca-tmpl의 .env 추적 정책.

Sources / 근거 후보

미해결 / Unknown

  • 아직 확인해야 할 사실: verifyEnvKeys가 현재 ca-tmpl 코드에 존재하는지.
  • 과장하면 안 되는 부분: draft canonical 확인 전까지 구현 완료처럼 쓰지 않는다.

Decision / 처리 결정

  • 액션: promote-to-canonical
  • 이유: wiki/projects/ca-tmpl/config-and-adapter-templates.md 에 env key drift gate 글감으로 반영했다.
  • 다음 단계: target canonical이 아직 draft 이므로 blogify 전 branch-note/code evidence와 현재 .env tracked 정책을 재확인한다.