Hook
“왜 이렇게 했지?” 6개월 전의 결정을 기억하지 못합니다. 코드에는 “무엇”과 “어떻게”는 있지만 “왜”는 없습니다. 그래서 같은 논의가 반복되고, 이미 기각된 대안이 다시 제안됩니다.
ADR (Architecture Decision Record) 은 “왜”를 기록하는 도구입니다. 세 프로젝트에서 작성된 14개의 ADR에서 가장 흥미로운 트레이드오프를 소개합니다.
TL;DR
- ADR은 “왜 이 결정을 했는가”를 기록하는 짧은 문서: Context, Decision, Rationale, Consequences 구조
- 14개 ADR 중 핵심 7개 선별: 플랫폼 선택, 파일 분할, i18n 방식, 인증 전환, 테스팅 전략 등
- 가장 중요한 교훈: “기각된 대안”을 기록하는 것이 “선택한 결정”을 기록하는 것보다 가치 있다
- 이 글은 AI 주도 개발 거버넌스 시리즈의 마지막 편입니다
Background: ADR이 필요한 순간
ADR이 필요한 경우
| 상황 | 예시 |
|---|---|
| 새 외부 의존성 | “상태 관리 라이브러리를 X로 정함” |
| DB 스키마 변경 | “users 테이블에 gender 컬럼 추가” |
| API 설계 원칙 변경 | “에러 응답 형식을 envelope 방식으로” |
| 플랫폼 변경 | “Cloudflare Workers를 주 플랫폼으로” |
| 보안 결정 | “PIN 인증 → OAuth로 전환” |
| 성능/비용 트레이드오프 | “빌드 도구 없이 순수 파일 분할만” |
ADR이 불필요한 경우
- 버그 수정
- 기존 패턴 내 기능 추가
- 동일 아키텍처 내 리팩터링
- 문서 업데이트
ADR 구조
# ADR-XXXX: 결정 제목
## Status
Accepted | Superseded by ADR-XXXX | Deprecated
## Context
왜 이 결정이 필요한가? (문제 상황, 제약 조건)
## Decision
무엇을 결정했는가? (구체적 선택)
## Rationale
왜 이 선택을 했는가? (대안 포함, 기각 이유)
## Consequences
이 결정의 결과는? (긍정/부정적 영향)
Solution: 핵심 ADR 7선
ADR 1: 엣지 우선 플랫폼 채택
Context: SaaS 에코시스템을 구축해야 하는데, 인프라 관리 부담을 최소화하면서 글로벌 배포가 필요
Decision: Cloudflare Workers(D1/R2/KV/Queues)를 주 플랫폼으로 채택. 단, 코어 로직은 추상화 계층으로 접근
기각된 대안:
- Lambda. 콜드 스타트, 복잡한 설정
- Vercel + Supabase. 비용, egress 요금
- 자체 호스팅. 인프라 관리 부담
Consequences: 글로벌 엣지 배포, 무료 티어 전 스택, 무료 egress. 트레이드오프: D1 500MB 제한, CPU 10ms
ADR 2: API 우선 개발 원칙
Context: AI 도구 기반 개발에서 “프리뷰 → 코드 → 데이터” 순서 역전이 반복됨
Decision: 도메인 → 스키마 → 컨트랙트 → UI → 디자인 순서를 4단계 게이트로 강제
Rationale: 순서 역전이 데드 버튼, 목 데이터, 상태 누락의 근본 원인으로 진단됨
Consequences: 개발 속도 일시적 저하, but 장기적 부채 급감. → 이 시리즈 (2)에서 상세히 다룸
ADR 3: 단일 파일 → 기능별 분할 전환
Context: 단일 HTML 파일이 346KB/7600줄까지 성장. AI 컨텍스트 비효율, 머지 충돌, 캐싱 비효율
Decision: 빌드 도구는 도입하지 않고 순수 파일 분할만으로 4-Phase 마이그레이션
Rationale: 빌드 도구 도입은 원래 아키텍처 결정(오프라인 PWA, 무료 호스팅)의 정신을 훼손
Consequences: AI 컨텍스트 80% 절약, Git diff 가독성 향상. 트레이드오프: 수동 파일 관리 부담. → (3)에서 상세
ADR 4: PIN 인증 → OAuth 전환
Context: 4자리 PIN 인증은 보안이 약하고, 기기 간 동기화가 안 됨
Decision: Google/Kakao OAuth 2.0 Authorization Code Flow 도입. HttpOnly 쿠키, JWT 1h/Refresh 7d
기각된 대안:
- 이메일/비밀번호. 관리 부담, 비밀번호 리셋 필요
- Magic link. 이메일 의존, 지연
Consequences: 보안 강화, 기기 간 동기화. 트레이드오프: 외부 의존성 (Google/Kakao 가용성)
ADR 5: GNU gettext 원문 키 채택
Context: 구조적 키(
t('ui.a_065'))의 가독성/관리 부담이 심각Decision: GNU gettext 원문 키 방식 채택. 듀얼 모드(점 유무로 분기)로 점진적 마이그레이션
Consequences: 키 발명 단계 제거, 296건 → 0건 마이그레이션 완료. → (4)에서 상세
ADR 6: 레이어드 테스팅 (E2E 최후)
Context: E2E 우선 테스트가 느리고(12~15분), 불안정(30% flaky)하여 CI 차단
Decision: Unit → Component → Contract → E2E Smoke 바텀업 전환. E2E는 스모크 5~10개만
Consequences: CI 시간 1~2분, flaky 5% 미만. → (5)에서 상세
ADR 7: 시간형 운동 타입 도입
Context: 플랭크 등 시간/횟수 맨몸 운동이 중량 모델에 억지로 끼워맞춰짐
Decision:
type:'timed'필드 도입. duration +5초 오버로드, 볼륨 계산 제외Rationale: 모든 운동을 “중량 × 횟수” 모델에 맞추는 것은 도메인 왜곡
Consequences: 볼륨 계산에서 시간형 제외. 오버로드 알고리즘 분기 필요
ADR 전체 목록 (14건)
전체 ADR 목록 보기
SaaS 모노레포 (5건)
| ADR | 결정 | 상태 |
|---|---|---|
| 0001 | 엣지 우선 플랫폼 채택 | Accepted |
| 0002 | API 우선 개발 원칙 | Accepted |
| 0003 | 프론트엔드 파일 분리 | Accepted |
| 0004 | GNU gettext 국제화 채택 | Accepted |
| 0005 | 레이어드 프론트엔드 테스팅 | Accepted |
AI 뉴스 서비스 (1건)
| ADR | 결정 | 상태 |
|---|---|---|
| 0001 | Cloudflare 스택 선택 (8가지 근거) | Accepted |
피트니스 PWA (8건)
| ADR | 결정 | 상태 |
|---|---|---|
| 0001 | 단일 파일 정적 PWA 아키텍처 | 부분 폐기 (ADR-0006으로) |
| 0002 | SNS OAuth 인증 도입 | Accepted |
| 0003 | 성별 기반 시작 중량 도입 | Accepted |
| 0004 | 난이도별 포즈 가이드 영상 분기 | Accepted |
| 0005 | 시간형 운동 타입 도입 | Accepted |
| 0006 | 단일 파일 → 기능별 분할 | Accepted (0001 부분 폐기) |
| 0007 | i18n 아키텍처 도입 | Accepted |
| 0008 | GNU gettext 원문 키 방식 | Accepted |
Result: ADR 도입 효과
| 지표 | ADR 도입 전 | ADR 도입 후 |
|---|---|---|
| “왜 이렇게 했지?” 질문 | 주 2~3회 | 거의 없음 (ADR 링크로 응답) |
| 같은 논의 반복 | 월 1~2회 | 0회 (기각 대안 기록) |
| 온보딩 시간 | 구두 설명 필요 | ADR 읽기로 자가 학습 |
| 결정 일관성 | 구두 합의 → 누락 | 기록된 결정 기준 |
가장 가치 있는 ADR: “부분 폐기”
ADR-0001(단일 파일 PWA)이 ADR-0006(기능별 분할)에 의해 부분 폐기된 것이 가장 instructive합니다:
ADR-0001: "단일 파일이 최고다" (2026-06-04)
↓ 2주 후
ADR-0006: "346KB가 됐다. 분할하자. 단, 빌드 도구는 안 도입한다." (2026-06-18)
Status: ADR-0001 부분 폐기
교훈: 결정을 번복하는 것은 실패가 아닙니다. 번복한 이유를 기록하는 것이 가치 있습니다. ADR-0001의 Context(오프라인 보장, 무료 호스팅)는 여전히 유효하고, ADR-0006은 그 정신을 유지하면서 부채만 해결합니다.
마치며
14개의 ADR을 돌아보며 가장 먼저 떠오른 생각은, 6개월 전의 결정 이유를 기억하지 못했던 순간들의 부끄러움이었습니다. 코드에는 “무엇”과 “어떻게”는 있지만 “왜”는 없었습니다. 그래서 같은 논의가 반복되고, 이미 기각된 대안이 다시 제안되는 일이 벌어졌습니다. ADR을 쓰기 시작하면서 깨달은 것은, 결정 자체보다 기각된 대안과 그 이유를 기록하는 것이 훨씬 더 가치 있다는 점이었습니다. “Cloudflare Workers를 선택했다”보다 “Lambda는 콜드 스타트 때문에 기각했다”가 6개월 후 더 큰 힘을 발휘합니다.
가장 인상 깊었던 학습은 ADR-0001이 ADR-0006에 의해 부분 폐기된 사례입니다. 단일 파일 아키텍처를 선택했던 결정을 번복하게 되었을 때, 처음에는 실패라고 느꼈습니다. 하지만 번복한 이유를 기록하니 그것은 실패가 아니라 진화였습니다. “단일 파일이 최고라고 생각했는데, 346KB가 되니 AI 컨텍스트가 비효율적이더라”라는 학습이 남아 있으니, 다음에도 같은 실수를 반복하지 않게 되었습니다. 결정을 번복해도 괜찮습니다. 번복한 이유만 기록하면 됩니다.
AI 주도 개발에서 ADR은 특별한 의미를 갖습니다. AI 에이전트는 이전 결정의 맥락을 모릅니다. “왜 빌드 도구를 안 쓰고 있지?”라는 의문을 가진 AI가 “Webpack을 도입하겠습니다”라고 제안할 수 있지만, ADR의 Rationale이 있으면 명확한 거부 이유를 제공할 수 있습니다. ADR은 더 이상 사람만을 위한 문서가 아니라, AI 에이전트에게도 읽혀야 하는 문서입니다. 앞으로 AI가 더 깊이 개발에 관여할수록, “왜”를 기록하는 일은 과거를 보존하는 행위를 넘어 미래의 AI와 협업하는 기반이 될 것입니다.
시리즈 마무리
이것으로 AI 주도 개발 거버넌스 시리즈 7편을 마칩니다.
| 편 | 제목 | 핵심 |
|---|---|---|
| (1) | 10가지 함정 | 순서 역전 진단 + 10원칙 |
| (2) | 4단계 디자인 게이트 | 프리뷰 역설 해법 |
| (3) | 모놀리식 HTML 분할 | AI 컨텍스트 절약 |
| (4) | gettext 원문 키 | 키 발명 종결 |
| (5) | 레이어드 테스팅 | E2E 최후의 수단 |
| (6) | 3-Tier CI 게이트 | 기계가 규칙을 지킨다 |
| (7) | ADR 14선 | “왜”를 기록하라 |
거버넌스는 살아있는 문서입니다. 새로운 문제를 겪을 때마다 원칙을 하나씩 추가하고, 그 원칙을 자동화로 뒷받침하는 과정이 중요합니다. 완벽한 거버넌스는 없지만, 진화하는 거버넌스는 있습니다.
| ← 이전 | 시리즈: AI 주도 개발 거버넌스 | 다음 → |
|---|---|---|
| (6) 3-Tier CI 게이트 | (7) ADR 14선 | , (시리즈 끝) |
게이트웨이 On-promise 제품 팀에서 시스템 모니터링 및 관리를 쉽게 다가갈 수 있도록 하기 위한 업무를 하고 있습니다.
Contact: lhjnano@gmail.com