본문으로 건너뛰기

결정을 남기다, ADR - 두 개의 아키텍처 정의서 ep.04

코드는 무엇을 했는지 보여준다. 무엇을 하지 않기로 했는지는 어디에도 남지 않는다.

다이어그램은 “무엇이 어떻게 연결되는가”를 보여줍니다. 그러나 “왜 이렇게 했는가”는 보여주지 못합니다. 그 빈자리를 채우는 것이 ADR(Architecture Decision Record) 입니다. 이번 편은 내부용 정의서의 심장을 다룹니다.


다이어그램이 답하지 못하는 질문

스폿의 컨테이너 뷰를 다시 봅니다. LLM API로 가는 화살표가 큐와 워커를 거쳐 점선으로 연결되어 있습니다. 그림은 “이렇게 연결되어 있다”고 말합니다. 하지만 누군가는 묻습니다. 왜 그냥 동기로 부르지 않았나요.

이 질문에 그림은 답하지 못합니다. 6개월 뒤 새 팀원이 같은 질문을 하고, 답을 아는 사람이 퇴사했다면, 그 결정은 미스터리가 됩니다. 최악은 누군가 “비효율적이네”라며 비동기를 동기로 되돌리고, 묻어둔 장애가 다시 살아나는 것입니다. ADR은 이 사고를 막습니다.


ADR 한 장의 구조

ADR은 짧습니다. 한 결정을 한 장에 담고, 네 부분으로 나눕니다. 맥락, 결정, 대안, 결과입니다.

ADR 한 장의 구조를 보여주는 카드. 헤더에 ADR-002라는 식별자, Accepted 상태 배지, 그리고 'LLM 요약을 큐 기반 비동기로 처리한다'는 제목이 있다. 그 아래 네 개의 섹션이 색 막대와 함께 세로로 쌓인다. 맥락(Context)은 LLM 요약이 느리고 실패가 잦아 동기 호출 시 기록 저장 응답이 지연된다는 배경이다. 결정(Decision)은 저장과 요약 생성을 분리해 저장 시 요약 작업을 큐에 넣고 워커가 비동기로 처리한다는 내용이다. 대안(Alternatives)은 동기 호출과 저장 직후 동기 생성 후 캐싱을 고려했으나 응답 시간과 장애 격리에서 불리해 기각했다는 내용이다. 결과(Consequences)는 긍정으로 저장 응답이 빨라지고 LLM 장애가 격리된다는 점, 부정으로 요약이 즉시 보이지 않고 큐·워커 운영 부담이 생기며 최종 일관성을 받아들여야 한다는 점을 담는다.

네 부분 중 가장 중요한 것은 맥락과 대안입니다. 맥락은 “그때 우리가 무엇을 알고 있었나”를 박제하고, 대안은 “무엇을 고려했고 왜 안 골랐나”를 남깁니다. 결정만 적힌 ADR은 절반짜리입니다. 나중에 결정을 뒤집으려는 사람에게 정작 필요한 정보는 결정이 아니라 기각된 대안에 있기 때문입니다.


스폿의 결정들

지난 편들에서 도출한 드라이버가 여섯 개의 결정으로 이어졌습니다. 각 ADR은 자신을 부른 드라이버를 명시합니다.

스폿의 ADR 목록을 2열 3행 카드로 보여주는 그림. 여섯 카드 모두 Accepted 상태다. ADR-001은 외부 API를 어댑터로 격리한다이며 드라이버는 유지보수성(벤더 락인 회피), ADR-002는 LLM 요약을 큐 기반 비동기로 처리이며 드라이버는 비용·가용성(부가 기능 분리), ADR-003은 핵심 경로에 서킷 브레이커와 캐싱이며 드라이버는 가용성·성능(핵심 경로 보호), ADR-004는 이미지를 오브젝트 스토리지에 저장이며 드라이버는 확장성(이미지 트래픽 분리), ADR-005는 인증을 OAuth로 위임한다이며 드라이버는 보안(자체 인증 부담 회피), ADR-006은 모듈러 모놀리스로 시작한다이며 드라이버는 유지보수성·단순성(과설계 회피)이다.

마지막 ADR-006이 흥미롭습니다. 마이크로서비스로 시작하지 않기로 한 결정입니다. 무언가를 하지 않기로 한 결정도 ADR입니다. 오히려 이런 “안 하기로 한” 결정이야말로 시간이 지나면 이유를 잊기 쉬워 기록의 가치가 큽니다.


결정에도 수명이 있다

ADR은 한 번 쓰고 끝나지 않습니다. 그렇다고 수정하지도 않습니다. 대신 상태를 전이시킵니다.

ADR 상태 머신 다이어그램. 제안됨(Proposed)에서 승인됨(Accepted)으로 승인 전이가 있고, 제안됨에서 기각됨(Rejected)으로 기각 전이가 있다. 승인됨에서 폐기됨(Deprecated)으로 폐기 전이, 승인됨에서 대체됨(Superseded)으로 대체 전이가 있다. 승인됨 상태는 틸색으로 강조되고 폐기됨과 대체됨은 앰버색이다. 주석은 대체됨이 새 ADR을 가리키며 기존 결정은 지우지 않고 상태만 바꿔 결정의 역사가 남는다고 설명한다. 하단 설명은 ADR은 수정하지 않고 상태를 전이시키며 한 번 쓰인 결정은 삭제되지 않는다고 말한다.

핵심은 append-only라는 점입니다. 결정이 틀린 것으로 드러나도 그 ADR을 지우지 않습니다. 상태를 폐기됨이나 대체됨으로 바꾸고, 새 결정을 새 ADR로 추가합니다. 이렇게 하면 “우리가 한때 이렇게 생각했고, 이런 이유로 바꿨다”는 역사가 남습니다. 이 성질이 ep.06에서 거짓말 문제를 닫는 열쇠가 됩니다.

아래는 ADR-002를 실제 파일로 적은 모습입니다. 보통 저장소 안 docs/adr/ 같은 폴더에 마크다운 한 장으로 둡니다.

# ADR-002: LLM 요약을 큐 기반 비동기로 처리한다

- 상태: Accepted (2026-06-02)
- 관련 드라이버: 비용, 가용성

## 맥락
LLM 요약 API는 응답이 느리고 실패가 잦다. 기록 저장 요청에서
동기로 호출하면 저장 응답 시간이 LLM 응답 시간에 묶인다.

## 결정
기록 저장과 요약 생성을 분리한다. 저장 시 요약 작업을 메시지 큐에
넣고, 별도 워커가 비동기로 처리해 결과를 나중에 반영한다.

## 대안
- 동기 호출: 저장 응답이 LLM 지연에 묶여 기각.
- 저장 직후 동기 생성 + 캐시: 장애 격리가 안 되고 복잡도만 증가해 기각.

## 결과
- (+) 저장 응답이 빨라지고, LLM 장애가 본 흐름에서 격리된다.
- (−) 요약이 즉시 보이지 않는 최종 일관성을 받아들여야 한다.
- (−) 큐와 워커라는 운영 대상이 새로 생긴다.

두 문서에서의 ADR

ADR은 두 문서가 가장 크게 갈라지는 항목입니다.

내부 공유용SI 납품용
형태계속 쌓이는 append-only 로그결정 목록 + 근거 요약
상태Proposed·Accepted·Superseded로 전이Accepted만, 제출 시점에 확정
대안·트레이드오프그대로 보존(왜 안 골랐나가 핵심)요약하거나 생략, 결론 위주
추적코드·PR과 링크요구사항 ID와 매핑(REQ ↔ ADR)

내부용에서 ADR은 의사결정의 일지입니다. 매번 새 결정이 추가되고, 과거 결정은 상태만 바뀝니다. 납품용에서 ADR은 “이 시스템이 이렇게 설계된 근거”를 요구사항에 묶어 보여주는 목록입니다. 감리는 종종 묻습니다. “이 요구사항은 어느 설계로 충족됩니까.” 그 답이 요구사항 ID와 ADR을 잇는 추적표입니다. 이 추적성은 ep.07에서 본격적으로 다룹니다.


참고 자료

  • Michael Nygard. (2011). Documenting Architecture Decisions.
  • Joel Parker Henderson. Architecture Decision Record (ADR) examples and templates.
  • arc42. arc42 Documentation Template — Section 9 Architecture Decisions. https://arc42.org

다음 편 예고

ep.05 - 흩어진 정책을 모으다, 횡단 관심사

보안, 인증·인가, 관측성, 에러 처리. 이런 정책은 한 컴포넌트에 속하지 않고 시스템 전체에 걸칩니다. 흩어진 채 두면 빠지고, 모아 두면 일관됩니다. 다음 편에서는 스폿의 횡단 관심사를 한자리에 모읍니다.