개념
기준이 없으면 결함이 닫힌다
"네트워크 느릴 때 앱이 이상해요."
이 문장만 적힌 결함 리포트는 거의 예외 없이 재현 불가로 닫힌다. 느리다는 게 얼마나 느린 건지, 지연이 문제인지 손실이 문제인지, 아예 끊긴 건지 연결은 되어 있었는지가 없기 때문이다. 개발자는 자기 자리에서 정상 속도로 열어보고 "잘 되는데요"라고 답한다.
그래서 이 모듈의 첫 레슨은 도구가 아니라 용어 합의 다. 팀이 같은 단어로 같은 상태를 가리킬 수 있어야 그다음이 있다.
네트워크 상태 4단계
모바일 서비스 기준의 실무 기준값이다. 절대적인 수치는 아니지만, 팀이 이 표를 벽에 붙여두고 같은 이름을 쓰기 시작하는 순간 결함 리포트의 품질이 달라진다.
| 상태 | 체감 | 다운로드 대역폭 | 응답 지연(RTT) | 패킷 손실 | 테스트 목적 |
|---|---|---|---|---|---|
| 정상 | 지연 없음 | 30 Mbps 이상 | 0 ~ 60 ms | 0 % | 기본 성능 기준선 확보 |
| 저하 (느림) | 눈에 띄는 대기 | 1 ~ 10 Mbps | 100 ~ 300 ms | 0.5 ~ 5 % | 로딩 표시·타임아웃 정책 검증 |
| 사용 불가 (Limited) | 연결은 되나 실패 | 50 ~ 200 kbps | 1,000 ms 이상 | 20 ~ 50 % | 재시도·부분 로딩·오류 안내 검증 |
| 단절 | 연결 없음 | 0 | 응답 없음 | 100 % | 오프라인 처리 경로 검증 |
전통적으로 QA 가이드는 Ping 값만으로 기준을 잡아왔다 — 정상 0~60ms, 눈에 띄는 딜레이 100ms 이상, 제품 사용 불가 170ms 이상. 이 기준은 여전히 유효하지만 한 축뿐이다. 여기에 대역폭과 패킷 손실 축을 더해야 비로소 '연결은 되었으나 사용 불가'가 독립된 상태로 분리된다.
Limited Service를 왜 따로 세우는가
네 상태 중 실무에서 가장 많은 사고가 나는데 가장 적게 테스트되는 것이 Limited Service 다.
단절 Limited Service
──────────────── ─────────────────────────
소켓이 즉시 실패한다 TCP 연결은 성립한다
OS가 오프라인을 알려준다 OS는 "연결됨"이라고 말한다
앱이 오프라인 분기를 탄다 앱은 정상 경로를 탄 채로 기다린다
→ 타임아웃까지 무한 스피너
→ 재시도가 폭주한다
→ 사용자는 버튼을 연타한다앱 입장에서 단절은 오히려 쉽다. 명확한 실패 신호가 즉시 오기 때문이다. Limited Service는 신호가 애매한 채로 오래 끌기 때문에 어렵고, 그래서 중복 결제·중복 주문 같은 비싼 사고가 여기서 나온다.
지하철 환승 구간, 엘리베이터, 지하주차장 입구, 공연장, 혼잡한 카페 와이파이 — 사용자가 실제로 자주 겪는 상태가 정확히 이것이다.
네트워크 품질의 4축
상태를 수치로 말하려면 축이 필요하다. 흔히 대역폭 하나만 생각하지만 실제로는 넷이다.
① 대역폭 (bandwidth) 초당 얼마나 많이 옮기는가
→ 큰 파일·이미지·영상에 영향
→ 작은 API 호출에는 거의 영향 없음
② 지연 (latency, RTT) 한 번 왕복에 얼마나 걸리는가
→ API 호출 수가 많을수록 치명적
→ 순차 호출 5개 × 300ms = 1.5초
③ 지터 (jitter) 지연이 얼마나 들쭉날쭉한가
→ 평균은 같아도 체감이 완전히 다르다
→ 실시간(통화·게임·스트리밍)에 치명적
④ 손실 (packet loss) 패킷이 얼마나 사라지는가
→ 재전송 유발 → 지연 폭증
→ TCP에서는 손실 1%가 체감 속도를 크게 깎는다③ 지터가 실무에서 가장 자주 빠진다. 많은 테스트 조건표가 대역폭·지연· 손실 세 칸만 갖고 있다. 그런데 평균 지연 150ms로 안정된 회선과, 평균은 같지만 50ms와 400ms를 오가는 회선은 사용자 체감이 전혀 다르다. 후자에서는 애니메이션이 끊기고, 스트리밍 버퍼가 마르고, 재생이 멈춘다.
지터를 조건에 넣는 방법은 간단하다. tc netem에서 지연 뒤에 편차를 한
칸 더 적으면 된다(레슨 5에서 다룬다).
흔히 빠지는 축 ① — 상·하향 비대칭
조건표를 만들 때 업로드와 다운로드에 같은 값을 넣는 실수 가 매우 흔하다. 실제 모바일 회선은 비대칭이다. 다운로드는 쓸 만한데 업로드가 형편없는 경우가 훨씬 많다.
이게 왜 중요한가:
- 사진·영상 업로드, 파일 첨부, 로그 전송이 업로드 경로를 탄다
- 요청 본문이 큰 API (폼 제출, 이미지 포함 게시글)도 업로드 영향을 받는다
- 업로드가 막히면 화면은 "전송 중"에서 멈추는데, 다운로드 속도만 측정하면 정상으로 보인다
전형적인 실제 조건 (다운로드 ≠ 업로드)
4G 혼잡 다운 5 Mbps / 업로드 0.5 Mbps
지하철 이동 다운 2 Mbps / 업로드 0.2 Mbps
공용 와이파이 다운 10 Mbps / 업로드 0.3 Mbps업로드 경로를 가진 기능이 있다면 비대칭 조건을 최소 하나는 반드시 넣는다. 대칭 조건만으로 테스트하면 업로드 결함이 통째로 빠진다.
흔히 빠지는 축 ② — 부하 중 응답성(버퍼블로트)
속도 측정 앱은 대개 아무것도 안 하는 상태에서 속도를 잰다. 그런데 사용자의 실제 상황은 다르다. 영상이 백그라운드로 다운로드되는 중에 버튼을 누른다. 사진이 업로드되는 중에 목록을 새로고침한다.
이때 나타나는 현상이 버퍼블로트(bufferbloat) 다. 회선이 포화되면 중간 장비의 큐에 패킷이 쌓이고, 대역폭 수치는 그대로인데 지연이 수백 ms에서 수 초까지 치솟는다.
유휴 상태 RTT 30ms, 100Mbps ← 속도 측정 앱이 보는 값
부하 중 (포화) RTT 1200ms, 100Mbps ← 사용자가 실제로 겪는 값
↑
대역폭은 안 변했는데 앱은 먹통이 된다이걸 재는 표준적인 지표가 RPM(Round-trips Per Minute) — 회선을 포화시킨 "작업 부하 상태"에서 1분간 몇 번의 왕복을 처리할 수 있는지를 센다. 값은 대략 100대(나쁨)에서 수천(좋음) 범위다.
macOS·iOS에는 이걸 재는 도구가 내장돼 있다.
networkQuality -v기본 동작은 다운로드와 업로드를 동시에 포화시키고 그 상태의 응답성을 측정하는 것이라, 영상통화나 음성통화 같은 실사용 상황에 훨씬 가깝다.
QA에게 이게 주는 실용적 결론은 하나다. "속도는 잘 나오는데 앱이 느려요" 라는 제보를 받으면 유휴 속도가 아니라 부하 중 응답성을 의심한다.
상태 정의를 팀 기준으로 만드는 법
표를 만들었다고 기준이 되는 게 아니다. 세 가지가 따라와야 한다.
1. 조건에 이름을 붙인다. 저하-B, Limited-A처럼 짧은 식별자를
정한다. 결함 리포트 제목에 그대로 들어갈 수 있어야 한다.
2. 조건마다 도구 설정값을 못 박는다. "열악"이라는 단어만으로는 사람마다 다르게 설정한다. 레슨 8의 환산표가 이 역할을 한다.
3. 결함 리포트 양식에 조건 칸을 넣는다. 양식에 칸이 없으면 아무도 안 적는다. 칸이 있으면 적는다. 이 작은 변화가 재현율을 크게 바꾼다.
실무에서 왜 필요한가
재현 불가로 닫히는 결함이 줄어든다
[Before]
제목: 느릴 때 주문이 두 번 들어감
내용: 네트워크가 안 좋을 때 가끔 그럽니다
결과: 재현 불가로 종료
[After]
제목: [Limited-A] 주문 버튼 연타 시 중복 주문 생성
조건: 다운 100kbps / RTT 1,000ms / 손실 30% (tc netem, 스크립트 limited.sh)
측정: 적용 후 fast.com 0.1Mbps 확인 (스크린샷 첨부)
절차: 장바구니 → 주문하기 3회 연타 → 15초 대기
결과: 주문 3건 생성. 서버 로그상 동일 payload 3건
기대: 멱등키로 1건만 생성되어야 함
결과: 개발자가 30분 만에 원인 특정조건명과 측정값이 붙는 순간 결함이 살아난다. 이게 이 모듈 전체의 실용적 목표다.
릴리즈 판정 기준이 생긴다
"네트워크 테스트 했나요?"에 "했습니다"로 답하는 것과, "정상·저하· Limited·단절 4개 조건 × 핵심 시나리오 12개 = 48건 중 46건 통과, 미통과 2건은 결함 #481·#482"로 답하는 것은 다르다. 모듈 4에서 배운 종료 조건을 네트워크 축에도 적용할 수 있게 된다.
사용자 제보를 조건으로 번역할 수 있다
"지하철에서만 그래요"라는 제보는 그 자체로는 행동 불가다. 그런데 상태 모델이 있으면 번역이 된다 — 지하철 이동 중은 잦은 핸드오버 + 간헐적 Limited + 높은 지터 조합이다. 그 조합을 조건으로 만들어 재현하면 된다.