ADR(Architecture Decision Record) 실전 작성법

· 약 9분 읽기 · 조회 3 #아키텍처#ADR#AA#설계 문서#SI

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

안경 쓴 항해사가 해도와 나침반 옆에서 두꺼운 항해일지에 기록을 적는 선실

한눈에 보기

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

ADR 상태 흐름: 제안된 ADR은 리뷰를 거쳐 승인되거나 기각되고, 승인된 ADR은 새 ADR에 대체되거나 근거가 사라지면 폐기된다

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번을 대체됨으로 표시한다. 옵션은 쓰는 버전의 도움말로 확인한다.

리뷰와 승인 절차

  1. 작성자가 Proposed 상태로 PR을 연다. PR 설명에 리뷰 기한(보통 3~5일)과 결정권자를 적는다.
  2. 영향받는 팀(인프라, 보안, 연계, 운영)을 리뷰어로 지정한다. 운영 담당이 빠지면 배포 뒤 운영 절차가 결정과 어긋난다.
  3. 의견은 PR 댓글로 받고, 반영한 내용은 본문의 대안이나 결과에 적는다. 회의에서 정했다면 회의 날짜를 관련 문서에 남긴다.
  4. 결정권자가 승인하면 상태를 Accepted로 바꾸고 날짜와 결정자를 적은 뒤 병합한다. 채택하지 않으면 Rejected로 바꿔 병합한다. PR을 닫기만 하면 기각 기록이 남지 않는다.
  5. 대체하는 경우 새 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개

아직 댓글이 없습니다. 첫 댓글을 남겨보세요.

댓글 쓰기

← 목록으로 돌아가기