아키텍처 결정 기록
고친 사람 github-actions[bot]
아키텍처 결정 기록은 시스템 구조를 정한 결정을 하나씩 짧은 문서로 남깁니다. 무엇을 골랐는지만 적지 않습니다. 왜 골랐는지와 그 대신 무엇을 감수하는지도 함께 적습니다. 나중에 합류한 개발자도 이 문서를 읽으면 결정이 어떤 사정에서 나왔는지 알 수 있습니다.
쉽고 빠른 이해
무슨 일을 하나 — 구조를 바꾸는 결정 하나를 문서 하나로 남깁니다. 주문 서비스와 결제 서비스를 메시지 큐로 잇기로 했다면, 그 결정이 문서 하나가 됩니다.
왜 하나 — 코드는 무엇을 골랐는지만 보여 줍니다. 왜 골랐는지는 회의에 있던 사람 머릿속에만 남습니다. 그 사람이 떠나면 뒤에 온 사람은 이유를 모른 채 결정을 따르거나 함부로 뒤집습니다.
어떻게 도나
- 결정마다 번호를 붙여 문서 하나를 씁니다
- 그 문서에 사정과 고른 것과 감수할 것을 적습니다
- 결정이 바뀌면 옛 문서는 상태 칸만 고치고 새 문서를 씁니다
대가 — 결정할 때마다 글을 쓰는 품이 듭니다. 그래서 되돌리기 어렵고 여러 부품에 걸치는 결정만 적습니다. 한 파일 안에서 끝나는 선택은 주석이나 커밋 메시지로 충분합니다. 옛 문서의 상태를 제때 안 고치면 이미 버린 결정이 살아 있는 것처럼 읽힙니다.
상세
주문을 받는 백엔드 서비스 하나를 예로 삼습니다. 결정 하나가 문서가 되는 데서 시작합니다. 그 결정이 나중에 뒤집히는 데까지 따라갑니다.
아키텍처 결정
아키텍처는 시스템을 어떤 부품으로 나누고 그 부품들을 어떻게 잇는지에 대한 큰 그림입니다. 아키텍처 결정은 이 그림을 바꾸는 선택입니다. 한번 정하면 되돌리는 데 품이 많이 듭니다.
주문 서비스 팀이 주문과 결제를 어떻게 이을지 고민한다고 해 봅시다. 주문 서비스가 결제 서비스를 바로 불러 응답을 기다리는 방법이 있습니다. 주문을 메시지 큐에 넣어 두고 결제 서비스가 꺼내 가게 하는 방법도 있습니다.
메시지 큐는 보내는 쪽과 받는 쪽 사이에서 메시지를 잠시 맡아 두는 소프트웨어입니다. 받는 쪽이 느려도 보내는 쪽은 메시지를 넣기만 합니다. 넣은 뒤에는 제 일을 계속합니다.
어느 방법을 고르느냐에 따라 장애가 번지는 모양과 응답 속도가 달라집니다. 나중에 바꾸려면 두 서비스를 함께 고쳐야 합니다. 이런 선택이 아키텍처 결정입니다. 변수 이름이나 라이브러리의 작은 버전 올림처럼 쉽게 되돌리는 선택은 여기에 들지 않습니다.
이유가 사라지는 문제
결정을 내리고 나면 결과는 코드에 남습니다. 코드를 열면 주문 서비스가 메시지 큐에 주문을 넣는 것이 보입니다. 그런데 왜 바로 부르지 않고 큐를 거치는지는 코드에 안 보입니다.
이유는 그 회의에 있던 사람 머릿속에 남습니다. 회의록이나 메신저 대화에 흩어지기도 합니다. 그 사람이 팀을 떠나면 이유를 찾을 길이 끊깁니다.
뒤에 온 개발자는 둘 중 하나를 합니다. 이유를 모르니 결정에 손대지 않고 따릅니다. 이러면 사정이 바뀌어 더는 맞지 않는 결정도 계속 짊어집니다.
아니면 이상해 보이는 구조를 걷어 냅니다. 이러면 처음 결정이 막으려던 문제가 다시 터질 수 있습니다. 큐를 걷어 내면 주문 서비스가 결제를 바로 부릅니다. 그러면 결제가 느려질 때 주문 접수도 같이 멈춥니다.
아키텍처 결정 기록은 이 이유를 결정과 함께 붙잡아 둡니다. 영어 이름을 줄여 ADR(Architecture Decision Record, 아키텍처 결정 기록)이라고 부릅니다. 결정 하나에 문서 하나입니다.
문서 하나를 이루는 다섯 칸
ADR 하나는 대개 다섯 칸으로 이루어집니다. 칸 이름은 팀마다 조금씩 다릅니다. 담는 내용은 비슷합니다.
| 칸 | 담는 것 | 없으면 생기는 일 |
|---|---|---|
| 제목 | 번호와 결정을 담은 짧은 명사구 | 목록에서 어느 결정인지 못 찾는다 |
| 상태 | 이 결정이 지금 살아 있나 | 버린 결정을 지금 규칙으로 읽는다 |
| 맥락 | 결정을 내리게 한 사정 | 사정이 바뀌었는지 가늠할 수 없다 |
| 결정 | 팀이 고른 것 | 무엇을 정했는지 흐려진다 |
| 결과 | 결정 뒤에 달라지는 것. 나빠지는 것까지 | 불편이 일부러 고른 대가인지 실수인지 모른다 |
이 가운데 맥락 칸과 결과 칸이 ADR 을 회의 결론 메모와 가릅니다.
맥락 칸은 결정을 내리게 한 사정을 적습니다. 그때 무엇이 압박이었는지 남아 있어야 합니다. 그래야 나중에 그 사정이 사라졌을 때 결정을 다시 볼 근거가 생깁니다.
이 칸은 어느 쪽 편도 들지 않는 말로 씁니다. 고른 쪽에 유리하게 사정을 적으면, 나중에 그 사정이 정말 바뀌었는지 가늠할 수 없습니다.
결과 칸에는 좋아지는 것만 적지 않습니다. 이 결정 때문에 감수하는 것도 적습니다. 주문 서비스의 예라면, 결제 결과를 주문 화면에 바로 보여 줄 수 없게 됩니다. 잃는 것을 같이 적어 두면 뒤에 온 사람이 그 불편을 알고 고른 대가로 읽습니다.
결과 칸에는 품질 속성이 자주 등장합니다. 품질 속성은 성능이나 가용성처럼 시스템이 얼마나 잘 도는지를 가리키는 성질입니다. 결정 하나가 어떤 품질 속성을 얻고 어떤 품질 속성을 내주는지가 결과 칸의 뼈대가 됩니다.
결정 칸은 「우리는 ~ 한다」처럼 팀을 주어로 한 문장으로 씁니다. 「~를 검토할 수 있다」 같은 흐린 말로는 무엇을 정했는지 안 남습니다.
다섯 칸을 채운 문서
다섯 칸을 채운 문서 하나는 아래 모양입니다. 대개 마크다운 파일 하나로 씁니다. 마크다운은 # 같은 기호로 제목을 표시하는 텍스트 형식입니다.
# 7. 주문과 결제를 큐로 잇기
## 상태
채택됨
## 맥락
결제 서비스가 자주 느려진다.
주문 서비스는 결제 응답을 기다린다.
그동안 주문 접수도 멈춘다.
## 결정
우리는 주문을 메시지 큐에 넣는다.
결제 서비스는 큐에서 꺼내 처리한다.
## 결과
결제가 느려도 주문은 계속 받는다.
결제 결과는 나중에 따로 알린다.
큐를 운영할 사람이 필요하다.
방금 본 문서는 한 화면에 들어옵니다. ADR 은 한두 쪽을 넘기지 않습니다. 길어지면 아무도 끝까지 안 읽습니다. 짧아야 결정할 때마다 부담 없이 씁니다.
번호와 상태
ADR 에는 쓴 순서대로 번호를 붙입니다. 한 번 쓴 번호는 다시 쓰지 않습니다. 그래야 「7번 결정」이라고 부르면 언제나 같은 문서를 가리킵니다.
상태 칸은 결정이 지금 어느 단계에 있는지 알려 줍니다. 처음 써서 팀에 돌릴 때는 「제안됨」입니다. 팀이 받아들이면 「채택됨」이 됩니다.
채택된 뒤에도 사정은 바뀝니다. 결정을 뒤집을 때는 새 번호로 문서를 하나 더 씁니다. 옛 문서의 본문은 고치거나 지우지 않습니다. 상태 칸만 「대체됨」으로 바꾸고 새 번호를 적습니다.
대신할 결정 없이 그냥 그만둘 때도 있습니다. 그때는 상태 칸을 「폐기됨」으로 바꿉니다. 그래야 읽는 사람이 이 결정을 더는 따르지 않아도 된다는 것을 압니다.
stateDiagram-v2
[*] --> 제안됨
제안됨 --> 채택됨: 팀이 받아들임
채택됨 --> 대체됨: 새 결정이 뒤집음
채택됨 --> 폐기됨: 대신할 결정 없이 그만둠
옛 문서를 지우지 않는 까닭은 「한때 이렇게 정했다」도 쓸모 있는 정보이기 때문입니다. 주문 서비스가 나중에 15번 결정으로 큐 대신 다른 방식을 골랐다고 해 봅시다. 7번 문서에는 「15번으로 대체됨」이 적힙니다. 둘을 나란히 읽으면 그사이 팀이 무엇을 겪었는지 보입니다.
코드 옆에 두는 까닭
ADR 은 대개 코드와 같은 저장소에 넣습니다. 저장소는 버전 관리 도구가 코드와 그 변경 이력을 함께 보관하는 곳입니다. doc/arch/adr-007.md 처럼 번호를 붙인 파일을 한 폴더에 모읍니다.
코드 옆에 두면 찾기 쉽습니다. 코드를 받은 사람은 결정 문서도 함께 받습니다. 따로 문서 사이트 주소를 몰라도 됩니다.
검토도 코드와 같은 길로 받습니다. 풀 리퀘스트는 바꾼 내용을 합치기 전에 팀에 검토를 청하는 요청입니다. 새 ADR 도 풀 리퀘스트로 올려 코드 리뷰를 받습니다. 결정을 두고 오간 의견이 그 요청의 댓글로 남습니다.
시점도 남습니다. 버전 관리 이력을 보면 그 결정이 언제 들어왔는지 나옵니다. 결정 문서와 그 결정을 따른 코드 변경을 나란히 볼 수 있습니다.
적을 결정과 안 적을 결정
모든 선택을 ADR 로 남기지는 않습니다. 적는 것은 되돌리기 어렵고 여러 부품에 걸치는 선택입니다. 어떤 데이터베이스를 쓸지, 서비스를 어디서 나눌지, 서비스끼리 어떻게 주고받을지가 그렇습니다.
한 파일 안에서 끝나는 선택은 코드 주석이나 커밋 메시지로 충분합니다. 이런 것까지 ADR 로 쓰면 문서가 너무 많아집니다. 그러면 정작 큰 결정이 그 사이에 묻힙니다.
반년 뒤 새로 온 동료가 「이건 왜 이렇게 했어요?」라고 물을 만한지 따져 봅니다. 물을 만하면 적습니다.
쓰는 데 드는 품
ADR 을 쓰려면 결정할 때마다 맥락과 결과를 글로 정리하는 시간이 듭니다. 바쁜 시기에는 이 단계를 건너뛰기 쉽습니다. 몇 건이 빠지면 기록 전체를 믿기 어려워집니다.
상태를 돌보는 일도 남습니다. 결정을 뒤집고도 옛 문서를 「채택됨」으로 두면 읽는 사람이 헷갈립니다. 이미 버린 결정을 지금 규칙으로 받아들입니다.
ADR 이 하지 않는 일
ADR 은 결정의 이유를 남길 뿐 결정을 대신 내려 주지 않습니다. 어느 쪽을 고를지 따지는 일은 여전히 팀이 합니다.
그 따짐을 돕는 평가 방법은 따로 있습니다. ATAM(Architecture Tradeoff Analysis Method)이 그런 방법의 하나입니다. 아키텍처가 성능이나 가용성 같은 품질 속성을 어떻게 얻는지, 하나를 얻으려고 다른 하나를 어디서 내주는지 따져 봅니다.
관련 항목
ADR 이 기록하는 구조 결정의 대상
소프트웨어 아키텍처 · 아키텍처 양식 · 품질 속성 · 모놀리스 · 마이크로서비스 · 메시지 큐 · 데이터베이스
ADR 과 함께 쓰이는 설계 문서 양식
설계 문서 · MADR · Y-statement · 아키텍처 기술 · C4 모델 · 4+1 뷰
ADR 을 보관하고 검토하는 도구와 절차
저장소 · 버전관리 · Git · 마크다운 · 풀 리퀘스트 · 코드 리뷰 · docs as code
결정을 따지고 평가하는 방법
ATAM · 품질 속성 시나리오 · 트레이드오프 · 아키텍처 적합성 함수
ADR 이 줄이려는 팀의 문제
기술 부채 · 지식 사일로 · 버스 팩터 · 온보딩
다른 이름: ADR · architecture decision record · Architecture Decision Record · 아키텍처 의사결정 기록 · 아키텍처 결정 레코드