화이트보드 우선 해결법: 코드 한 줄 쓰기 전에 실패 시나리오부터 그려라
코딩 전에 화이트보드로 실패 시나리오를 그리면 숨은 엣지 케이스를 드러내고, 시스템 신뢰성을 강화하며, 모던화 프로젝트의 리스크를 줄일 수 있다.
화이트보드 우선 해결법: 코드 한 줄 쓰기 전에 실패 시나리오부터 그려라
현대 시스템은 단순하고 눈에 띄는 방식으로 잘 무너지지 않는다. 서비스와 서비스 사이의 경계, 네트워크 구간, 부분 장애, 예기치 못한 트래픽 폭증 같은 이음새에서 무너진다. 그리고 이런 실패는 대개 배포가 끝난 뒤, 프로덕션에서, 모두가 압박을 받는 상황에서야 뒤늦게 드러난다.
더 나은 접근법이 있다. 코드보다 화이트보드가 먼저다. 구체적으로는, 코드 한 줄도 쓰기 전에 실패 시나리오와 의존성 맵(dependency map) 을 먼저 그리는 것이다.
이건 그냥 아키텍트들이 좋아하는 형식적인 절차가 아니다. 다음을 가능하게 하는 강력한 방법이다.
- 숨은 엣지 케이스 노출
- 연쇄 장애(cascading failure) 위험 가시화
- 모던화(modernization) 작업의 리스크 감소
- 후반 단계의 의외 상황과 급한 핫픽스 감소
이 글에서는 왜 화이트보드-우선 실패 모델링이 설계 과정의 필수 요소가 되어야 하는지, 어떻게 효과적으로 수행할 수 있는지, 그리고 데이터를 활용한 분석과 어떻게 결합할 수 있는지를 살펴본다.
왜 코딩 전에 화이트보드를 꺼내야 할까?
대부분의 팀은 코드를 쓰기 전에 뭔가를 한 번쯤은 그린다. 대략적인 시스템 다이어그램, 시퀀스 다이어그램, 박스-화살표 정도는 나온다. 하지만 이런 스케치는 너무 자주 해피 패스(happy path) 만을 전제로 한다.
문제는, 프로덕션 트래픽은 거의 해피 패스를 따르지 않는다는 점이다. 사용자는 네트워크를 이탈하고, 업스트림 제공자는 지연되고, 캐시는 식고(cold cache), 큐는 쌓여만 가고, 부분 배포는 서비스 간 버전 차이를 만든다.
화이트보드로 시작하면 팀은 다음을 강제당한다.
- 머릿속에만 두고 보기엔 너무 복잡한 복잡성을 시각화해야 한다.
- 특히 장애 처리와 관련된 가정들을 명시적으로 드러내야 한다.
- 실시간으로 협업하면서, 우려 사항을 초기에 끌어낼 수 있다.
여기에 화이트보드 시간을 실패 시나리오에 집중하면, 아키텍처 다이어그램은 단순한 의도 문서가 아니라 신뢰성을 예측하는 도구가 된다.
1단계: 실제로 동작하는 그대로 시스템을 그려라
첫 번째 규칙은 단순하다. 있다고 바라는 시스템이 아니라, 실제로 존재하는 시스템을 그려라.
화이트보드에 다음을 스케치한다.
- 사용자 진입 지점 (UI, API, 웹훅 등)
- 코어 서비스와 컴포넌트
- 데이터스토어와 캐시
- 메시지 큐와 이벤트 버스
- 외부 의존성 (결제, 인증, 서드파티 API 등)
- 운영 레이어 (로드 밸런서, 게이트웨이, 피처 플래그 등)
호출과 데이터 흐름은 화살표로 표현한다. 보기 좋은 다이어그램이 목표가 아니다. 목표는 빠짐없는 완전한 그림이다.
그다음, 각 화살표에 주석을 단다.
- 동기(sync) vs 비동기(async)
- 크리티컬(필수) vs 베스트 에포트(best-effort)
- 예상 지연(latency) 범위
- 재시도(retry) 동작 (있다면 어떻게 하는지)
이렇게 하면 실패 모델링을 위한 기본 지도가 만들어진다.
2단계: 해피 패스가 아니라 실패 시나리오를 그려라
이제부터가 진짜 시작이다. 각 컴포넌트와 의존성에 대해 스스로에게 묻는다.
이게 느려지거나, 불안정해지거나, 완전히 죽으면 어떻게 되는가?
화이트보드에서 메인 플로우에서 가지를 치며 다양한 실패 시나리오를 그려 나간다.
- 다운스트림 서비스 타임아웃
- 부분적인 네트워크 분할(partition)
- 당연히 캐시 히트라 생각했는데 캐시 미스 발생
- 큐가 처리 속도보다 빠르게 쌓이는 상황
- 외부 API의 레이트 리밋(rate limit) 초과
각 시나리오에 대해, 실패가 어떻게 전파되는지를 그린다.
- 사용자는 단순한 품질 저하(degraded experience)를 겪는가, 아니면 바로 에러를 보게 되는가?
- 재시도 때문에 장애가 다른 서비스로 연쇄 전파(cascade) 되는가?
- 데이터가 오염(corrupt)되는가, 아니면 단지 지연되는가?
각 노드(컴포넌트)별로 쓸 수 있는 간단한 템플릿
중요한 컴포넌트마다 옆에 작은 메모를 적는다.
- 느려질 때 → 무엇이 깨지는가? 누가 기다리는가? 누가 재시도하는가?
- 완전히 죽었을 때 → 무엇이 강등(degrade)되는가? 무엇을 안전하게 꺼둘 수 있는가?
- 일관성이 깨질 때 → 어떤 데이터나 의사결정이 잘못되게 되는가?
이걸 명시적으로 모델링하면, 원래라면 새벽 2시에 인시던트 채널에서 처음 보게 됐을 문제들을 미리 발견하게 된다.
3단계: 의존성을 맵으로 그려 연쇄 위험을 드러내라
복잡한 시스템은 연쇄적으로 실패한다. 단 하나의 의존성이 조용히 블라스트 레디우스(blast radius)를 증폭시키는 요인이 되기도 한다.
이제 시스템 다이어그램에서 의존성만을 집중해서 본다.
- 외부 서비스에 의존하는 모든 컴포넌트에 동그라미를 친다.
- 크리티컬 의존성(실패 시 사용자 에러나 데이터 손실로 바로 이어지는 것)에는 더 두꺼운 화살표를 그린다.
- 색깔을 나눠 그린다.
- 외부 벤더
- 내부 공유 플랫폼(예: 인증, 과금/빌링)
- 데이터 인프라(데이터베이스, 검색, 캐시 등)
그리고 이렇게 자문한다.
- 이 의존성이 실패하면, 블라스트 레디우스는 어디까지인가?
- 느려질 때 어떤 서비스들이 재시도로 몰려가서 스탬피드(대규모 폭주)를 일으키는가?
- 여기 숨어 있는 크로스 팀/크로스 서비스 결합(coupling)은 무엇인가?
이 과정을 거치면 종종 다음 같은 사실을 발견하게 된다.
- “작은” 변경이라 여겼던 공유 라이브러리나 플랫폼 서비스의 수정이 회사 절반의 시스템에 영향을 줄 수 있다.
- 복원력을 위해 넣은 재시도 정책이, 실제로는 천둥치는 무리(thundering herd) 를 만들 수 있다.
- 낮은 우선순위라 여겼던 통합(예: 분석/analytics)이 제대로 격리되지 않으면, 고우선순위 플로우 전체를 블로킹할 수 있다.
이 지점이야말로 화이트보드의 진가가 드러나는 곳이다. 시스템을 기능 모음이 아니라, 위험이 얽혀 있는 네트워크로 볼 수 있게 해주기 때문이다.
4단계: 엣지 케이스 발견을 ‘마무리 작업’이 아니라 ‘설계’로 취급하라
많은 팀이 엣지 케이스를 구현 막판에 한 번에 처리하는 “마무리 청소” 작업쯤으로 취급한다. 이때가 가장 비용이 많이 들고, 가장 위험하다.
대신 엣지 케이스 발견 자체를 1급 설계 활동(first-class activity) 으로 취급해야 한다.
- 실패 설계(failure design) 를 위한 전용 화이트보드 세션을 잡는다.
- 설계 리뷰 체크리스트에 “실패 시나리오를 다뤘는가?”를 추가한다.
- “어떻게 동작하는가?”만큼 자주 “어떻게 깨지는가?”를 묻는다.
발견한 각 엣지 케이스에 대해 의식적으로 결정한다.
- 우아하게 처리할 것인가? (예: 강등 모드, 폴백(fallback))
- 구조적으로 예방할 것인가? (예: 서킷 브레이커, 벌크헤드(bulkhead) 패턴)
- 위험을 수용할 것인가? (그리고 그 이유를 문서화할 것인가?)
목표는 모든 엣지 케이스를 없애는 것이 아니다. 실패 시의 행동을 우연이 아니라 의도된 설계 결과로 만드는 것이다.
5단계: 화이트보드 모델을 실제 데이터와 결합하라
화이트보드 세션은 강력하지만, 어디까지나 가설이다.
이 스케치를 신뢰할 수 있는 의사결정 도구로 바꾸려면, 데이터 기반 임팩트 분석과 결합해야 한다.
- 로그(Log): 지금 실제로 어떤 실패가 일어나고 있는가? 얼마나 자주? 어떤 플로우에서?
- 메트릭(Metrics): 어디에서 지연 스파이크, 에러 버스트, 리소스 포화(saturation)가 발생하는가?
- 트레이스(Traces): 어떤 경로가 가장 핫한가? 어디에서 요청이 과도하게 팬아웃(fan-out) 되는가?
- 의존성 그래프 (서비스 메쉬, 트레이싱 시스템, 내부 툴에서 가져온 것): 어떤 서비스가 무엇에 의존하는가? 얼마나 촘촘하게 연결돼 있는가?
이 데이터를 통해 다음을 수행한다.
- 화이트보드에서 스케치한 시나리오를 검증한다.
- “드물다”고 생각했던 실패가 실제로는 흔하지 않은가?
- 화이트보드에서 빼먹은 핫스팟은 없는가?
- 어떤 실패부터 설계해야 할지 우선순위를 정한다.
- 발생 빈도나 임팩트가 큰 실패 경로에 집중한다.
- 시스템에 대한 멘탈 모델을 정교하게 다듬는다.
- 데이터가 기존 가정을 뒤집을 때, 다이어그램을 업데이트한다.
시간이 지나면, 화이트보드 모델과 관측성(observability) 스택이 피드백 루프를 이룬다. 화이트보드는 어디를 봐야 할지 안내하고, 데이터는 무엇이 실제인지 확인해 준다.
모던화: 시각적 실패 모델링으로 큰 변화를 디리스킹(de-risking)하기
마이크로서비스 전환, 클라우드 마이그레이션, 데이터베이스 리플랫폼 등 모던화 작업에서 실패 모델링은 특히 큰 효과를 낸다.
컴포넌트 레벨에서 보면 단순해 보이는 변경이, 실제로 배포되면 예기치 못한 시스템 전체의 거동을 만들어낸다.
큰 모던화 단계를 밟기 전에 다음을 수행하라.
-
현재 상태를 화이트보드에 그린다.
- 지금 데이터는 실제로 어떻게 흐르는가?
- 어디에 깨지기 쉬운 통합이나 비공식 의존성이 숨어 있는가?
-
목표 상태를 화이트보드에 그린다.
- 어떤 컴포넌트가 이동하거나 쪼개지거나 사라지는가?
- 로컬 호출이던 것이 어디에서 원격 호출로 바뀌는가?
-
실패 시나리오를 겹쳐서 그린다.
- 목표 상태가 어떤 새로운 실패 모드를 만들어내는가?
- 기존 실패 모드 중 어떤 것은 분산 환경에서 더 악화되는가?
-
임팩트가 큰 실패 지점을 식별한다.
- 어떤 서비스나 데이터 저장소가 더 많은 플로우의 크리티컬 패스에 들어가게 되는가?
- 어디에 더 나은 격리, 캐싱, 백프레셔(backpressure)가 필요한가?
이걸 미리 시각화하면, 기능 파리티(feature parity)는 달성했지만 신뢰성은 오히려 퇴보한 모던화 프로젝트가 되는 일을 줄일 수 있다.
화이트보드-우선 실패 모델링을 습관으로 만드는 방법
이 접근을 팀 문화에 녹이려면, 가볍고 반복 가능하게 유지하는 것이 중요하다.
- 모든 기술 설계 문서에 “실패 설계” 섹션을 추가한다.
- 다음과 같은 간단한 질문들을 표준화한다.
- 이게 느려지면 어떻게 되는가?
- 이게 죽으면 어떻게 되는가?
- 이게 불일치/비일관 상태가 되면 어떻게 되는가?
- 화이트보드 세션의 사진이나 디지털 버전을 남겨 티켓이나 문서에 링크한다.
- 인시던트 이후에 다이어그램을 다시 꺼내 현실에 맞게 업데이트한다.
무엇보다 중요한 건, 초기 단계부터 실패에 대해 이야기하는 것을 당연하게 만드는 것이다. 엣지 케이스와 실패 경로를 찾는 것은 비관주의가 아니라 전문성이라는 인식을 공유해야 한다.
결론: 배포 전에, 먼저 ‘어떻게 망가지는지’를 그려라
코드는 곧 커밋(commit) 이고, 그림은 싸게 버릴 수 있는 시도다.
아이디어와 구현 사이에 화이트보드 한 번을 끼워 넣으면 다음을 얻을 수 있다.
- 숨은 엣지 케이스와 장애 전파 경로를 조기에 드러낸다.
- 의존성을 맵으로 그려 연쇄 장애 위험을 식별한다.
- 취약한 통합 지점을 미리 찾아 모던화 작업에 대한 자신감을 높인다.
- 실패 행동을 우연한 부산물이 아니라, 의도된 설계 결과로 만든다.
- 로그, 메트릭, 의존성 그래프를 활용해 시나리오를 정교하게 다듬고 우선순위를 정한다.
다음에 새로운 기능, 서비스, 혹은 마이그레이션을 시작하려 할 때, IDE를 열기 전에 잠시 멈춰라.
마커를 집어 들고, 어떻게 동작하는지 그려라. 그리고 곧바로, 어떻게 망가지는지도 그려라.
이것이 화이트보드-우선 해결법이다. 그리고 이 방식이야말로, 가장 혹독한 교훈을 프로덕션에서 몸으로 배우지 않게 해줄 수 있는 방법이다.