개념
시스템은 섬이 아니다
지금까지의 탐험은 대체로 시스템 내부를 다뤘다. 하지만 실제 서비스는 거의 항상 외부 시스템과 연결되어 있다 — 결제 게이트웨이, 이메일·SMS 발송 서비스, 지도 API, CDN, 다른 팀이 관리하는 내부 마이크로서비스 등.
그리고 우리가 통제할 수 없는 쪽이 우리를 멈출 수 있다. 결제사가 느려지면 우리 서비스가 느려지고, 메일 서비스가 죽으면 우리 가입이 반쪽이 된다. 코드는 한 줄도 안 바뀌었는데 말이다.
레슨 7에서 개체 지도를, 레슨 8에서 상태 지도를 그렸다. 이 레슨은 바깥 지도다. 셋을 다 그리면 그 제품에서 볼 것이 거의 다 나온다.
생태계 다이어그램 그리기
우리 시스템을 가운데 두고, 그것과 대화하는 외부 시스템들을 화살표로 연결해 그려본다.
[우리 서비스]
├──→ [결제 게이트웨이]
├──→ [이메일 발송 서비스]
├──→ [배송 조회 API (3rd party)]
└──→ [재고 관리 서비스 (내부, 다른 팀)]이 다이어그램 자체가 "어디를 탐험해야 할지"에 대한 지도가 된다. 화살표 하나가 차터 하나라고 보면 거의 맞다.
화살표를 그릴 때 방향을 나눠 그리는 것이 중요하다. 우리가 부르는 쪽과 바깥이 우리를 부르는 쪽은 위험의 성격이 다르다.
우리가 부른다 (나가는 쪽) 바깥이 부른다 (들어오는 쪽)
───────────────────────── ──────────────────────────
[우리 서비스] ──→ 결제 게이트웨이 결제 결과 알림 ──→ [우리 서비스]
──→ 메일 발송 배송 상태 변경 ──→
──→ 지도 API 파트너사 주문 ──→
──→ 재고 서비스(내부)나가는 쪽은 느려지거나 실패할 수 있다 — 우리가 기다리다 멈춘다. 들어오는 쪽은 언제 올지 모르고, 중복으로 오고, 순서가 뒤바뀌고, 아예 안 오기도 한다. 들어오는 쪽이 훨씬 다루기 어렵고 결함도 많다.
들어오는 쪽을 빠뜨리는 경우가 많으니 특히 챙긴다. 화면에서는 안 보이기 때문이다 — "결제 완료 알림이 두 번 오면 어떻게 되나" 같은 질문은 화면만 보고는 떠오르지 않는다.
다이어그램을 어디서 얻나
처음부터 다 알 수는 없다. 세 곳에서 모으면 한 시간이면 그린다.
| 어디서 | 무엇이 나오나 |
|---|---|
| 개발자에게 묻기 | 가장 빠르다. "바깥이랑 뭘 주고받나요" 한 문장 |
| 네트워크 탭 | 화면을 쓰면서 어디로 요청이 나가는지 눈으로 보인다 |
| 설정·환경 변수 | 외부 서비스 주소와 키가 모여 있다. 권한이 있다면 |
두 번째가 QA 가 혼자 할 수 있는 방법이다. 주요 화면을 한 바퀴 돌면서 네트워크 탭을 보면 우리 도메인이 아닌 주소가 눈에 띈다. 그것들이 바깥이고, 하나씩 "이건 뭔가요" 를 물으면 된다.
다만 나가는 쪽만 보인다는 한계가 있다. 들어오는 쪽은 브라우저를 거치지 않으므로 네트워크 탭에 안 나타난다. 그래서 개발자에게 묻는 단계를 건너뛸 수 없다.
어디까지가 "바깥" 인가
외부 서비스만 바깥이 아니다. 우리가 통제하지 못하는 것은 전부 바깥이다.
| 바깥 | 왜 통제 못 하나 |
|---|---|
| 외부 회사 서비스 | 결제사·지도·메일·문자 — 계약 관계일 뿐이다 |
| 다른 팀의 서비스 | 같은 회사여도 배포 일정과 변경을 우리가 못 정한다 |
| 사용자의 브라우저·기기 | 버전·설정·확장 프로그램이 제각각 |
| 통신망 | 끊기고 느려진다 |
| 시간 | 자정·월말이 알아서 온다(레슨 5) |
| 사용자가 넣는 데이터 | 무엇이 들어올지 모른다 |
두 번째 줄이 실무에서 가장 자주 사고를 낸다. 같은 회사라 안심하지만, 다른 팀은 우리에게 알리지 않고 배포하고 응답 형식을 바꾼다. "내부라서 괜찮다" 는 생각이 가장 위험하다.
마지막 줄도 자주 잊는다. 사용자 입력은 가장 가까이 있는 바깥이고, 그래서 입력값 검증이 모든 보안의 출발점이 된다(모듈 50).
신뢰 경계(Trust Boundary)
신뢰 경계는 데이터가 "우리가 통제할 수 있는 영역"에서 "우리가 통제할 수 없는 영역"으로 넘어가는 지점이다. 화살표 하나하나가 신뢰 경계다. 경계를 넘어오는 데이터는 우리가 기대한 형식이 아닐 수 있고, 경계 너머의 시스템은 느려지거나 멈출 수 있다 — 우리 쪽에서 그걸 어떻게 다루는지가 탐험 대상이다.
경계마다 두 방향으로 묻는다.
| 방향 | 묻는 것 |
|---|---|
| 나갈 때 | 우리가 보내는 값이 맞나. 비밀이 섞여 나가지는 않나 |
| 들어올 때 | 들어온 값을 그대로 믿고 쓰나. 검증하나 |
두 번째가 핵심이다. 경계를 넘어온 값은 우리 값이 아니다. 형식이 바뀌었을 수도, 빈 값일 수도, 악의로 조작됐을 수도 있다. 그대로 화면에 뿌리거나 저장하면 그 자리가 결함이 된다.
첫 번째도 의외로 샌다. 외부로 보내는 값에 필요 이상의 정보가 실려 나가는 경우가 흔하다 — 배송사에 주민번호까지 보내거나, 분석 도구에 주소가 섞여 나가는 식이다. 개발자 도구의 네트워크 탭에서 나가는 요청의 본문을 한 번 읽어 보는 것만으로 발견되기도 한다(레슨 4).
"만약 ~한다면?"을 생태계에 적용하기
- 만약 결제 게이트웨이가 응답하지 않고 멈춰 있다면(타임아웃)?
- 만약 이메일 서비스가 다운되어 있다면? 사용자에게는 뭐라고 보여지는가?
- 만약 배송 조회 API가 예상과 다른 형식의 응답을 준다면(필드 이름이 바뀌었거나)?
- 만약 재고 관리 서비스가 순간적으로 옛날 데이터를 준다면(캐시 지연)?
- 만약 배송 상태 알림이 순서가 뒤바뀌어 도착한다면?
- 만약 결제 완료 알림이 두 번 온다면?
- 만약 외부가 성공이라고 했는데 실제로는 처리가 안 됐다면?
일곱 개 중 뒤의 셋이 특히 안 보는 질문이다. 순서·중복·거짓은 전부 들어오는 쪽에서 생기고, 화면에는 흔적이 안 남는다.
이 질문들은 실제로 재현하기 어려울 수 있지만, 최소한 "이런 상황이면 어떻게 될지 아는 사람이 팀에 있는가?" 를 확인하는 것만으로도 가치가 있다. 개발 환경에서 외부 서비스를 흉내 낸 목(mock) 서버로 응답 지연이나 에러를 인위적으로 만들어볼 수 있다면 실제로 탐험해볼 수도 있다.
바깥이 바뀌는 것도 사건이다
고장만 보면 절반이다. 멀쩡히 돌아가는 바깥이 조용히 바뀌는 것도 사고를 만든다.
| 바뀌는 것 | 우리 쪽 영향 |
|---|---|
| 응답 형식 | 필드가 빠지거나 이름이 바뀌어 화면이 깨진다 |
| 정책·요금 | 하루 호출 한도가 생겨 어느 시점부터 안 된다 |
| 인증 방식 | 키가 만료되거나 방식이 바뀐다 |
| 서비스 종료 | 공지를 못 보고 지나간다 |
| 우리 쪽 변경 | 우리가 보내는 값을 바꿨는데 상대가 못 받는다 |
마지막 줄을 자주 잊는다. 경계는 양쪽 다 바뀔 수 있고, 우리가 바꾼 것이 상대를 깨뜨릴 수도 있다. 파트너사에 데이터를 보내는 제품이라면 우리 변경이 바깥에 미치는 영향도 시험 대상이다.
이런 변화는 갑자기 터지지 않고 어느 날 조용히 시작된다. 그래서 "지난주까지 됐는데 오늘 안 된다" 는 제보가 오면 우리가 바꾼 게 없어도 바깥을 먼저 의심하는 것이 맞다. 모듈 12의 계약 테스트가 이 문제를 자동으로 잡으려는 시도다.
사례 — 메일이 안 왔을 뿐인데
작아 보이는 경계 하나가 어떻게 커지는지 보자. 회원가입 인증 메일 한 줄이다.
상황. 메일 발송 서비스가 30분간 장애였다. 그동안 가입을 시도한 사람이 200명.
우리 쪽에서 일어난 일.
- 가입 요청은 정상 처리됐다. 계정이 만들어졌다
- 메일 발송만 실패했는데 그 실패를 아무도 안 봤다 — 화면은 "인증 메일을 보냈습니다" 를 띄웠다
- 사용자는 메일을 기다리다 다시 가입을 시도했다 → "이미 가입된 이메일입니다"
- 고객센터에 문의가 몰렸다. 상담원은 계정이 있는 것을 보고 "가입되셨는데요" 라고 답했다
- 30분 뒤 메일 서비스가 복구됐지만 밀린 메일은 재발송되지 않았다
결함은 메일 서비스가 아니라 우리 쪽에 다섯 개다. 실패를 안 본 것, 실패했는데 성공이라고 표시한 것, 재시도가 없는 것, 재발송 수단이 없는 것, 그리고 상담원이 볼 화면에 메일 발송 상태가 없는 것.
메일 서비스 장애는 우리 책임이 아니다. 하지만 위 다섯은 전부 우리 책임이다. 그리고 다섯 다 메일 서비스를 30분 꺼 보면 드러난다.
바깥이 고장나는 일곱 가지 모양
"만약 실패한다면" 이 막연하면 고장 모양을 목록으로 갖고 있으면 된다. 어느 외부 연동에나 그대로 적용된다.
| 모양 | 우리 쪽에서 확인할 것 |
|---|---|
| 느리다 | 얼마나 기다리나. 기다리는 동안 화면은? 사용자가 두 번 누르면? |
| 아예 안 온다 | 타임아웃이 있나. 그 뒤에 재시도하나, 포기하나 |
| 오류를 준다 | 사용자에게 뭐라고 보이나. "알 수 없는 오류" 는 결함이다 |
| 형식이 다르다 | 필드가 빠지거나 이름이 바뀌었을 때 화면이 깨지나 |
| 두 번 온다 | 같은 알림이 두 번 오면 두 번 처리되나 |
| 순서가 바뀐다 | "배송완료" 가 "배송중" 보다 먼저 오면? |
| 거짓을 준다 | 성공이라고 했는데 실제로는 안 됐다면 |
세 번째가 가장 자주 눈에 띈다. 외부 오류를 그대로 화면에 뿌리는 제품이 많다. 사용자는 "PG_ERR_3041" 를 보고 아무것도 할 수 없다. 무엇을 해야 하는지 알려 주는 문구인가가 판정 기준이다.
여섯 번째는 거의 안 본다. 들어오는 알림의 순서는 보장되지 않는데, 대부분의 구현은 순서대로 온다고 가정한다. 배송 상태가 뒤로 돌아가거나, 취소 뒤에 결제 완료가 들어오는 사고가 여기서 난다.
어느 경계부터 보나
연동이 열 개면 전부 볼 수는 없다. 우선순위 기준 넷을 쓴다.
| 기준 | 위로 올라가는 것 |
|---|---|
| 돈이 걸렸나 | 결제·정산·포인트가 먼저다 |
| 되돌릴 수 있나 | 메일·문자는 한 번 나가면 못 거둔다 |
| 사용자가 기다리나 | 화면 앞에서 기다리는 연동이 멈추면 바로 체감된다 |
| 최근에 붙었나 | 새 연동은 실패 처리가 덜 다듬어져 있다 |
두 번째가 자주 간과된다. 잘못된 메일·문자·푸시는 취소가 안 된다. 테스트 중에 실제 고객에게 발송되는 사고도 여기서 난다 — 개발 환경에서 실제 주소로 나가지 않는지 확인하는 것 자체가 중요한 시험 항목이다.
네 번째도 실무적으로 유용하다. 이번 릴리즈에서 새로 붙은 연동이 있으면 거기부터 본다. 오래 돌아간 연동은 이미 여러 번 장애를 겪으며 다듬어졌지만, 새 연동은 실패 경로를 아무도 밟아 보지 않았다.
외부를 실제로 고장 내 보는 법
"재현이 어렵다" 는 말은 절반만 맞다. 생각보다 쉽게 만들 수 있는 것들이 있다.
| 하고 싶은 것 | 방법 | 난이도 |
|---|---|---|
| 느리게 만들기 | 개발자 도구의 속도 제한 | 쉬움 |
| 끊기게 만들기 | 통신을 껐다 켠다. 비행기 모드 | 쉬움 |
| 오류 응답 받기 | 외부 서비스의 시험용 값을 쓴다 | 쉬움 |
| 형식 깨뜨리기 | 중간에서 응답을 가로채 바꾼다(모듈 9 레슨 10) | 보통 |
| 두 번 오게 하기 | 들어오는 알림을 수동으로 한 번 더 보낸다 | 보통 |
| 아예 안 오게 하기 | 개발 환경에서 연동을 꺼 달라고 요청 | 보통 |
세 번째 줄이 특히 쓸모 있다. 결제사·배송사는 대개 시험용 카드 번호나 시험용 운송장 번호를 공개하고, 그 값을 쓰면 실패·지연·취소 같은 상황을 의도적으로 만들 수 있다. 연동 문서에 적혀 있으니 개발자에게 "시험용 값이 뭔가요" 를 묻는 것이 시작이다.
못 만드는 것도 있다. 그럴 때는 질문이라도 남긴다 — "결제사가 10초 멈추면 어떻게 되나요" 에 아무도 답을 못 하면, 그 자체가 릴리즈 판정에 올라갈 정보다(레슨 3에서 본 것과 같다).
바깥이 느릴 때 우리가 같이 멈추는 구조
가장 흔하고 가장 큰 사고 형태라 따로 본다. 결제사 하나가 느려졌는데 서비스 전체가 멈추는 일이 실제로 일어난다.
구조는 단순하다.
사용자 100명 → 결제 요청 → [결제사가 30초 응답 없음]
↓
우리 서버가 100개 연결을 붙잡고 기다린다
↓
새로 들어온 사람은 연결을 못 얻어 **결제가 아닌 화면도 안 열린다**결제와 상관없는 상품 목록까지 안 열리는 이유가 이것이다. 기다리는 동안 자원이 묶여 있기 때문이다.
QA 가 확인할 것은 두 가지다.
- 기다리는 시간에 상한이 있나 — 타임아웃이 없으면 위 구조가 그대로 생긴다
- 한쪽이 느릴 때 나머지가 살아 있나 — 결제가 느려도 조회는 되어야 한다
두 번째를 확인하려면 느리게 만들어 놓고 다른 기능을 써 보면 된다. 개발자 도구의 속도 제한을 걸고 결제를 시도한 채, 다른 탭에서 상품 목록을 열어 보는 식이다. 간단한데 거의 아무도 안 해 본다.
이 구조를 끊는 장치들(회로 차단기·격벽 같은 것)은 모듈 14와 모듈 39에서 다룬다. 여기서는 "한 곳이 느릴 때 전체가 멈추는지" 를 확인하는 것까지가 탐험의 몫이다.
경계마다 물어 둘 다섯 질문
연동이 새로 생길 때마다 다섯 개만 물어 두면 대부분의 사고를 미리 본다. 기술 질문이 아니라 정책 질문이고, 그래서 QA 가 묻기 좋다.
- 얼마나 기다리나? — 타임아웃이 정해져 있나. 없으면 영원히 기다린다
- 실패하면 다시 시도하나? — 몇 번, 얼마 간격으로. 포기하면 어떻게 되나
- 실패를 누가 아나? — 사용자·운영팀·개발팀 중 누구에게 알려지나
- 나중에 다시 할 수 있나? — 밀린 것을 재처리할 수단이 있나
- 두 번 와도 괜찮나? — 같은 알림이 두 번 와도 한 번만 처리되나
다섯 질문의 답이 어디에도 안 적혀 있는 경우가 대부분이다. 그 자체가 발견이고, 묻는 것만으로 팀이 한 번 생각하게 된다.
특히 3번과 4번이 자주 비어 있다. 실패를 아무도 모르면 복구가 시작되지 않고, 재처리 수단이 없으면 복구된 뒤에도 피해가 남는다. 위 메일 사례가 정확히 그 경우였다.
실무에서 왜 필요한가
실제 장애 사고의 상당수는 우리 코드가 아니라 외부 의존성이 원인이다 — 결제사가 느려지자 우리 서비스 전체가 함께 멈추거나, 이메일 서비스 장애로 회원가입은 되는데 인증 메일이 영영 안 오는 식이다. 내부 로직만 탐험하는 QA는 이런 리스크를 절대 못 본다.
그리고 이 영역은 자동화가 특히 못 본다. 자동화 시험은 외부 연동을 대개 가짜로 바꿔 놓고 돌린다 — 안 그러면 느리고, 돈이 들고, 결과가 매번 달라지기 때문이다. 그래서 자동화가 전부 초록색이어도 진짜 외부와 붙었을 때의 동작은 아무도 확인하지 않은 상태일 수 있다.
레슨 5에서 본 것과 같은 구조다. 자동화는 변수를 고정하고, 탐험은 변수를 바꾼다. 외부 연동에서는 그 차이가 특히 크다. 생태계 다이어그램을 그려보는 것만으로도 "우리가 전혀 고려 안 하고 있던 실패 지점"이 눈에 보이기 시작한다. 이건 모듈 16(비기능 테스트)의 호환성·네트워크 테스트와도 연결된다.
채용시장에서의 위치
외부 연동 관점은 경력자에게 특히 많이 묻는다. 신입은 화면을 보고, 경력자는 경계를 본다는 인식이 있기 때문이다.
- "장애 대응 경험이 있나요?" — 실제 장애의 상당수가 외부 의존성에서 시작된다. 어느 경계에서 끊겼는지 가려낸 경험이 있으면 강하다
- "외부 연동 테스트는 어떻게 하셨나요?" — "시험용 값으로 실패를 만들어 봤다", "응답을 가로채 형식을 바꿔 봤다" 가 구체적인 답이다
- "타임아웃은 몇 초로 잡아야 하나요?" — 정답을 묻는 것이 아니라 그 숫자가 왜 필요한지 아는가를 본다
결제·커머스·핀테크 공고에서는 "외부 연동 검증", "PG·배송사 연동 테스트" 같은 문구로 직접 나온다. 그리고 이 역량은 운영 쪽 직무로 넓히기 좋다 — 모듈 37(운영 품질)과 모듈 14(관측성)가 같은 경계를 다룬다.