개발 slecs

실시간 폴링 시 결제수단 목록 미갱신 버그 수정

목차

실시간 폴링과 결제 도메인 화면이 얽히면 사소해 보이는 버그 하나가 꽤 골치 아픈 문제로 번진다. 이번엔 폴링 응답을 받아도 결제수단 breakdown 목록(<ul>)이 갱신되지 않는 버그를 잡았다. 시점 라벨 여백도 같이 손봤다. 변경된 파일은 내부 클래스 3개, SQL 매퍼 2개, 뷰/스타일 1개.

원인 파악

증상은 단순했다. 폴링이 성공 응답을 받고 있는데도 화면의 목록이 갱신되지 않음. 처음엔 폴링 자체가 실패하거나 렌더링 함수가 호출되지 않는 문제를 의심했다.

네트워크 탭을 열어보니 폴링은 정상적으로 응답을 받고 있었고, 렌더링 함수도 호출되고 있었다. 원인을 찾아 내려가다 보니 결국 JSON 키 이름 불일치였다. 서버가 내려주는 응답 구조와 프론트가 기대하는 키가 달랐던 것.

// 서버 응답 구조
{ "paymentMethodList": [ ... ] }

// 프론트가 읽으려는 키
response.data.paymentMethods  // → undefined

undefined를 조건으로 거는 코드가 렌더링을 그냥 스킵해버린다. 에러가 나지 않아서 로그만 봐선 멀쩡해 보이는 게 이 버그의 특징이었음. 증상이 "에러"가 아니라 "무반응"으로 나타나서 디버깅 경로 잡는 게 조금 까다로웠다.

수정 범위와 검증

키 이름만 고치면 끝날 것 같지만, 실제 수정 범위는 조금 더 넓었다.

  • 내부 클래스 3개: 응답 DTO 매핑 로직과 서비스 레이어 처리 수정. 키 불일치 외에도 빈 목록 처리 분기가 빠져 있는 부분이 있었음.
  • SQL 매퍼 2개: 집계 쿼리 조건이 의도한 범위를 벗어나고 있어서 같이 정리했다. breakdown 목록 합계와 상위 집계가 맞아야 하는데, 일부 조건이 어긋나 있었음.
  • 뷰/스타일 1개: breakdown <ul> 렌더링 함수와 시점 라벨 여백.

결제 도메인 특성상 화면에 표시되는 숫자가 항상 DB 집계와 일치해야 한다. 그래서 키 이름 수정만 하고 끝내지 않고 SQL 조건도 들여다봤다. 건드린 김에 숫자 검증을 해보면 미세한 조건 차이가 발견되는 경우가 종종 있다.

수정 후엔 버그를 직접 재현해서 정상 동작을 확인했고, 관련 화면과 숫자도 cross-check했다. 버그 수정 때 쓰는 루틴이 있는데, 이 정도를 기본으로 가져간다.

항목 이유
같은 로직 중복 여부 확인 한 곳만 고치면 나머지에서 같은 버그 재발
정상 케이스 회귀 여부 수정이 기존 동작을 망가뜨리는 경우가 생각보다 많음
실제 동작 직접 확인 코드가 맞아도 환경 차이로 빗나갈 수 있음
관련 화면과 숫자 cross-check 결제 도메인은 숫자 정합이 기본

엣지 케이스를 꼼꼼히 따지는 게 귀찮아 보여도, 나중에 같은 버그로 다시 오는 시간 비용이 훨씬 크다. 특히 금융/결제 도메인은 숫자 하나가 틀리면 신뢰가 흔들릴 수 있어서 "대충 맞는 것 같다"로 넘어가면 안 된다.

폴링 응답 갱신에서 자주 밟는 함정

이 구조에서 반복적으로 보이는 문제 패턴이 몇 가지 있다.

응답 구조 변경 추적 실패. 서버 API가 키 이름을 바꾸거나 구조를 리팩토링했는데 프론트가 따라가지 못하는 케이스. 타입스크립트를 쓰면 어느 정도 컴파일 타임에 잡히지만, any가 끼어 있거나 DTO를 느슨하게 정의해두면 런타임까지 살아남는다.

빈 배열과 undefined 구분 문제. []undefined를 같은 "비어 있다"로 처리하면 세 가지 상태를 구분하기 어려워진다. 초기 로드 중, 폴링 갱신 실패로 인한 이전 값 유지, 실제로 빈 목록 - 이 셋은 UI 처리가 달라야 하는데 뭉뚱그려지기 쉽다.

렌더링 조건부 스킵. 응답이 왔어도 특정 조건에서 렌더링을 건너뛰는 코드가 있으면 에러 없이 조용히 화면이 멈춘다. 이번 버그의 핵심이 여기 있었음.

// 이 패턴이 undefined 때문에 false로 떨어짐
if (data.paymentMethods?.length) {
  renderList(data.paymentMethods)
}
// 렌더링 호출 자체가 사라지고, 에러도 없음

이런 버그는 개발 환경에서 초기 로드만 확인하고 넘어가는 경우가 많아서, 폴링 갱신 경로를 실제로 테스트해보지 않으면 늦게 발견된다. QA나 스테이징에서도 "첫 진입 동작"만 확인하는 경우엔 마찬가지로 통과되는 케이스다.

사내 서비스를 계속 만들다 보면 기능 하나가 SQL 집계, 상태 처리, 예외 분기, 화면 렌더링, 권한 체크를 모두 가로지른다는 걸 거듭 체감한다. 어느 하나만 빠뜨려도 숫자가 맞지 않거나 특정 상황에서 이상한 화면이 나온다. 변경 전에 현재 동작을 메모해두고, 수정 후 같은 케이스로 재확인하고, 관련 화면이 있으면 숫자 cross-check하는 루틴이 결국 시간을 아끼는 방법이 된다.

커밋 단위도 이번에 신경 썼다. SQL 조건 수정, DTO 매핑 수정, 렌더링 수정을 한 덩어리로 밀어 넣으면 나중에 뭔가 깨졌을 때 어느 변경이 원인인지 찾기가 어려워진다. 논리적으로 독립된 단위로 쪼개는 게 귀찮더라도 나중 디버깅 비용을 낮춘다. 커밋 메시지도 "무엇을 했다"보다 "왜 했다"를 담으려고 하는데, fix: 결제수단 목록 갱신 안 됨보다 fix: 폴링 응답 JSON 키 불일치로 breakdown ul 미갱신 수정이 나중에 git blame 뒤졌을 때 훨씬 가치 있다.

댓글 0

첫 댓글 달아줘.