환불 완료 처리를 했는데 우리 시스템에 이력이 없다는 문의를 받았고 refunds 행이 실제로 0건이었다. 없다는 사실이 확인됐으니 다음은 그것을 만드는 코드가 어디 있는지 찾는 순서였다.
Table of contents
Open Table of contents
원인 — 조기 반환이 건너뛴 처리
외부 완료 통보를 수집해 큐를 거쳐 ClaimProcessor 로 들어가는 흐름을 따라갔다. complete() 는 이미 completed 인 건에 대해 성공 표시만 남기고 곧바로 return 하고 있었다.
조기 반환하는 경로는 그 뒤의 처리를 통째로 건너뛴다. 상태를 바꾸는 markCompleted() 도 열어 보니 내부 상태 변경과 SettlementAdjusted 이벤트만 있고 refunds 를 만드는 코드가 없었다.
다른 경로에만 있던 외부 호출
마켓 환불 호출 refundToChannel() 이 언제 일어나는지도 확인하니 관리 화면의 수동 완료 처리 경로에만 있었다. 수집 경로에서는 그 호출을 하지 않는다.
JobType 열거에 REFUND_SYNC 라는 관련돼 보이는 값이 하나 더 있어 사용처를 찾았는데 정의만 있고 어디서도 쓰이지 않았다. 정의를 봤으면 사용처까지 찾아야 이것이 부르겠거니 하고 넘어가지 않는다.
판단 기준 — 우리가 실행하지 않은 환불
이 건은 마켓이 먼저 고객에게 환불하고 나중에 판매자 정산에서 차감하는 방식의 건이었다. 우리는 그 사실을 수집해 내부 상태만 바꾸고 환불을 실행하지는 않는다.
우리가 환불을 실행한 것이 아니므로 refunds 가 없는 것이 설계대로였다. 이력이 없다는 관측은 맞았고 그러므로 처리가 안 됐다는 해석이 틀린 것이었다.
조치 — 확인 범위를 넘지 않은 회신
문의한 쪽의 실제 걱정은 돈이 나갔는지였을 텐데 마켓이 이미 환불했고 정산에서 차감되므로 금액은 맞을 수 있다. 다만 그것은 settlements 쪽에서 확인해야 하는 사안이고 내가 본 것은 orders 와 claims 쪽이다.
두 가지 방법이 있었는데 금액은 정산에서 차감되니 문제없다고 한 줄로 답하는 것과 확인한 범위와 안 한 범위를 나눠 적는 것이다. 뒤쪽을 골랐다. 이유는 정산 표를 열어 보지 않은 채 맞을 것이라고 적으면 그 문장이 확인된 사실로 굳어서다. 대신 회신이 두 단락으로 길어지고 문의한 쪽이 정산 담당에게 한 번 더 물어야 하는 것을 감수했다. 그래서 refunds 가 없는 것은 정상 동작이고 정산 영향 여부는 별도 확인이 필요하다고 나눠 적었다. 확인한 범위를 넘어서 단정하면 그 문장이 다음 사람에게 근거로 쓰인다.
지금 안 고쳐도 남기는 것
레코드가 있으면 이력 조회가 되니 좋겠다는 요구가 나올 수 있어 어디를 보강해야 하는지도 적었다. 자동 생성이 필요하면 markCompleted() 를 손봐야 한다는 한 줄이다.
만드는 코드가 아예 없으면 그것은 빠뜨린 것이 아니라 설계일 가능성이 높다. 없다는 사실이 나왔을 때 결함으로 단정하지 않고 어디서 만드는지와 이 건이 그 경로를 타는지를 차례로 확인해야 한다.
정리
- 기록이 없다고 처리가 안 된 것은 아니다
- 조기 반환 경로는 뒤의 처리를 통째로 건너뛴다
- 정의만 있고 사용처가 없는 값이 있다
- 관측이 맞아도 해석이 틀릴 수 있다
- 우리가 실행하지 않았으면 기록이 없는 것이 맞다
- 확인한 범위를 넘어서 단정하지 않는다
- 지금 안 고치더라도 어디를 고칠지는 남긴다
- 만드는 코드가 아예 없으면 설계일 가능성이 높다