아키텍처 결정은 몇 달이 지나면 결과만 남고 이유는 사라진다. ADR(Architecture Decision Record)은 결정 하나를 한 장에 배경, 대안, 결과와 함께 적어 두는 짧은 문서이고, 이 글은 언제 쓰는지부터 필드 구성, 상태 관리, 저장 위치, 리뷰 절차, 공공 SI 산출물과의 연결까지 실무에서 바로 쓸 수 있는 방식으로 정리한 것이다.

한눈에 보기
| 단계 | 하는 일 | 상태 | 남는 것 |
|---|---|---|---|
| 판단 | 이 결정이 ADR 대상인지 기준으로 거른다 | - | 대상이면 번호 하나 |
| 작성 | 배경, 고려한 대안, 결정, 결과를 한 장에 쓴다 | Proposed | docs/adr/ 아래 마크다운 파일 |
| 리뷰 | 영향받는 팀이 기한 안에 의견을 단다 | Proposed | PR 리뷰 기록 |
| 승인 | 결정권자가 승인하고 병합한다 | Accepted 또는 Rejected | 날짜와 결정자 |
| 변경 | 고치지 않고 새 ADR로 대체하거나 폐기한다 | Superseded, Deprecated | 양쪽을 잇는 링크 |

ADR 형식은 Michael Nygard가 2011년 블로그 글 "Documenting Architecture Decisions"에서 제안한 제목, 상태, 배경, 결정, 결과 다섯 칸이 출발점이다. 이후 고려한 대안과 결정 동인을 더한 MADR 같은 템플릿이 나왔다. 어떤 템플릿을 쓰든 핵심은 같다. 결정 하나에 한 장, 짧게, 바꾸지 않고 쌓는다.
ADR은 언제 쓰는가
모든 결정을 적으면 아무도 읽지 않는다. 아래 중 하나라도 해당하면 쓴다.
- 되돌리는 비용이 크다. DBMS, 세션 저장 방식, 인증 구조, 모듈 경계처럼 바꾸면 여러 화면과 배치를 같이 고쳐야 하는 결정이다.
- 대안을 두 개 이상 진지하게 비교했다. 비교했다는 사실 자체가 기록할 가치다. 기록이 없으면 석 달 뒤 같은 비교를 처음부터 다시 한다.
- 여러 팀이나 외부 기관에 영향이 간다. 연계 방식, 공통 응답 형식, 로그 형식이 여기에 든다.
- 품질 요구사항을 맞추려고 무언가를 포기했다. 응답 속도를 위해 정합성을 늦추는 결정처럼 감수하는 단점이 있는 결정이다.
반대로 변수 이름 규칙, 라이브러리의 마이너 버전 올림, 한 화면 안의 구현 방식은 ADR이 아니라 개발 표준이나 커밋 메시지에 둔다. 판단이 애매하면 "이 결정을 모르는 신규 개발자가 반대로 구현하면 문제가 되는가"를 묻는다. 문제가 되면 쓴다.
한 장을 구성하는 필드
| 필드 | 쓰는 내용 | 비어 있으면 생기는 일 |
|---|---|---|
| 번호·제목 | ADR-0012 세션 저장소를 Redis로 옮긴다처럼 결정을 문장으로 |
목록만 보고 내용을 알 수 없음 |
| 상태·날짜·결정자 | Proposed, Accepted 등과 승인일, 승인한 사람 | 아직 유효한 결정인지 알 수 없음 |
| 배경 | 결정을 강제한 사실과 제약, 수치 | 결정이 취향처럼 보임 |
| 결정 동인 | 이번 판단의 기준이 된 품질 요구사항 | 대안 비교의 기준이 흔들림 |
| 고려한 대안 | 대안마다 장단점과 기각 이유 | 같은 대안이 다시 제안됨 |
| 결정 | 무엇을 하기로 했는지 한두 문장 | 해석이 사람마다 달라짐 |
| 결과 | 생기는 일, 감수하는 단점, 후속 작업 | 단점이 나중에 장애로 발견됨 |
| 관련 문서 | 대체한 ADR, 요구사항 ID, PoC 결과 | 근거를 추적할 수 없음 |
제목은 "세션 저장소 검토"처럼 주제가 아니라 "세션 저장소를 Redis로 옮긴다"처럼 결정을 쓴다. 배경에는 "응답이 느리다"가 아니라 "피크 시간 노드 1대 재시작 때 로그인 사용자 약 1,200명의 세션이 끊긴다(예시)"처럼 확인할 수 있는 사실을 쓴다.
상태와 생애주기
상태는 다섯 개면 충분하다.
- Proposed: 작성 중이거나 리뷰 중이다. 이 상태로는 개발 기준이 되지 않는다.
- Accepted: 승인됐다. 개발자는 이 결정을 따른다.
- Rejected: 검토했지만 채택하지 않았다. 지우지 않고 남긴다. 같은 제안이 다시 나올 때 이 문서가 답이다.
- Deprecated: 근거가 사라져 더 이상 유효하지 않지만 대신할 결정은 없다. 연계 대상 시스템이 폐지된 경우가 예다.
- Superseded: 새 ADR이 이 결정을 대체했다. 상태 옆에 대체한 번호를 적는다.
승인된 ADR의 본문은 고치지 않는다. 결정이 바뀌면 새 ADR을 쓰고, 옛 ADR에는 상태와 링크만 바꾼다. 본문을 고쳐 버리면 그 시점에 왜 그렇게 판단했는지가 사라지고, 감리나 장애 분석에서 "당시 기준"을 설명할 수 없다. 오타나 깨진 링크 수정은 예외로 둔다.
저장 위치와 번호 규칙
ADR은 코드와 같은 저장소에 둔다. 위키에 두면 코드와 따로 늙는다.
docs/adr/
├── README.md # 번호, 제목, 상태 목록
├── 0001-record-architecture-decisions.md
├── 0004-use-sticky-session.md # Superseded by 0012
└── 0012-move-session-to-redis.md
- 파일 이름은 네 자리 번호와 영문 제목이다. 번호는 한 번 쓰면 재사용하지 않는다. 기각된 ADR도 번호를 유지한다.
- 0001번은 "이 프로젝트는 ADR로 결정을 기록한다"는 결정 자체로 시작하는 경우가 많다.
README.md의 목록은 상태가 바뀔 때 같은 PR에서 고친다. 목록과 파일이 어긋나면 목록을 믿지 않게 된다.- Nat Pryce의 adr-tools 같은 CLI를 쓰면 번호 매기기와 대체 링크 작성을 자동화할 수 있다. 예를 들어
adr new -s 4 "Move session to Redis"는 새 ADR을 만들면서 4번을 대체됨으로 표시한다. 옵션은 쓰는 버전의 도움말로 확인한다.
리뷰와 승인 절차
- 작성자가 Proposed 상태로 PR을 연다. PR 설명에 리뷰 기한(보통 3~5일)과 결정권자를 적는다.
- 영향받는 팀(인프라, 보안, 연계, 운영)을 리뷰어로 지정한다. 운영 담당이 빠지면 배포 뒤 운영 절차가 결정과 어긋난다.
- 의견은 PR 댓글로 받고, 반영한 내용은 본문의 대안이나 결과에 적는다. 회의에서 정했다면 회의 날짜를 관련 문서에 남긴다.
- 결정권자가 승인하면 상태를 Accepted로 바꾸고 날짜와 결정자를 적은 뒤 병합한다. 채택하지 않으면 Rejected로 바꿔 병합한다. PR을 닫기만 하면 기각 기록이 남지 않는다.
- 대체하는 경우 새 ADR과 옛 ADR의 상태 변경을 한 PR에 넣는다. 둘 중 하나만 바뀐 상태가 생기지 않게 하려는 것이다.
실전 예시
아래는 앞의 생애주기를 그대로 따른 한 장이다. 수치는 예시다.
# ADR-0012 사용자 세션을 서버 메모리에서 Redis로 옮긴다
- 상태: Accepted (2026-10-20, 결정자: 수석 아키텍트)
- 대체: ADR-0004 sticky session 사용
- 관련: 요구사항 NFR-07(무중단 배포), PoC-03 결과
## 배경
- WAS 2대(JBoss EAP)에 mod_jk sticky session으로 세션을 고정해 왔다.
- 배포 때 노드를 내리면 그 노드의 로그인 세션이 모두 끊긴다.
피크 시간 기준 약 1,200명(예시).
- NFR-07은 "업무 시간 배포 중 로그인 유지"를 요구한다.
## 결정 동인
- 배포·장애 시 세션 유지
- 운영팀이 이미 운영 중인 구성 요소를 우선한다
## 고려한 대안
1. sticky session 유지: 변경 없음. 노드 재시작 시 세션 유실이 그대로다. 기각.
2. JBoss 세션 복제(distributable): 앱 변경이 작다.
노드가 늘면 복제 트래픽이 늘고, WAS 교체 시 다시 설계해야 한다. 기각.
3. Spring Session + Redis: WAS와 세션을 분리한다.
Redis 이중화와 세션 객체 직렬화가 새로 필요하다. 채택.
## 결정
세션은 Spring Session으로 Redis에 저장한다. mod_jk sticky 설정은 제거한다.
## 결과
- 노드 재시작과 배포 중에도 로그인이 유지된다.
- 세션에 넣는 객체는 모두 Serializable이어야 한다. 개발 표준에 추가한다.
- Redis 장애가 곧 로그인 장애다. Redis 이중화와 모니터링을 운영 범위에 넣는다.
- 후속: 세션 크기 상한 정의, 운영 매뉴얼 갱신
ADR-0004 쪽은 본문을 그대로 두고 상태만 Superseded by ADR-0012로 바꾼다.
공공 SI 산출물과 연결하기
공공 SI는 정해진 산출물 체계가 있어 ADR을 따로 둘 자리가 없어 보인다. 실제로는 아키텍처 정의서와 잘 맞물린다.
- 아키텍처 정의서에는 결정의 결과(구조, 기술 스택)를 쓰고, "주요 결정" 장에 ADR 번호, 제목, 상태 목록을 둔다. 이유는 ADR에만 쓴다. 두 곳에 이유를 쓰면 하나만 고쳐져 어긋난다.
- 감리에서 "왜 이 구조를 택했는가"를 물으면 고려한 대안과 기각 이유가 바로 답이 된다. 리뷰 PR과 승인 날짜가 의사결정 과정의 증적이 된다.
- 산출물 제출 형식이 문서 파일이면 저장소의 ADR을 원본으로 두고, 제출 시점의 목록과 본문을 부록으로 묶는다. 제출본을 원본으로 삼아 고치기 시작하면 저장소와 갈라진다.
- 산출물 이름과 목차는 사업마다 다르므로, 착수 때 발주처와 "ADR 목록을 아키텍처 정의서 부록으로 낸다"는 식으로 위치를 합의해 둔다.
자주 하는 실수
- 결정이 끝난 뒤 몰아서 쓴다. 기각한 대안과 당시 수치가 기억에서 빠져 결정만 적힌 문서가 된다.
- 고려한 대안을 비워 둔다. 대안이 없으면 결정의 이유를 검증할 수 없고, 같은 제안이 다시 올라온다.
- 승인된 ADR 본문을 고친다. 당시 판단 근거가 사라지고 변경 이력은 diff를 뒤져야만 보인다.
- 결과에 장점만 쓴다. 감수하는 단점과 후속 작업이 없으면 그 단점이 운영 중에 장애로 발견된다.
- 한 장에 결정을 여러 개 넣는다. 그중 하나만 바뀌어도 문서 전체의 상태를 정할 수 없게 된다.
점검표
- ADR 대상 기준이 팀에 공유돼 있다
- 제목이 주제가 아니라 결정 문장이다
- 배경에 확인 가능한 사실과 수치가 있다
- 고려한 대안이 두 개 이상이고 기각 이유가 있다
- 결과에 감수하는 단점과 후속 작업이 있다
- 상태, 승인 날짜, 결정자가 적혀 있다
- ADR이 코드와 같은 저장소의
docs/adr/에 있다 - 대체된 ADR과 새 ADR이 서로 링크돼 있다
- 기각된 제안도 Rejected로 남아 있다
- 아키텍처 정의서의 주요 결정 목록이 ADR 목록과 일치한다
좋은 ADR은 길고 완벽한 문서가 아니라, 결정 하나를 그 당시의 이유와 함께 고치지 않고 남긴 한 장이며, 그런 한 장이 쌓여야 몇 달 뒤에도 구조가 왜 이런지 설명할 수 있다.
댓글 0개
아직 댓글이 없습니다. 첫 댓글을 남겨보세요.