등산하며 깨달은 코드의 의미
회사에서 현업을 하다 보니 필히 과거에 전임자가 작성했던 코드를 보게 되고
발생하는 에러가 있으면 과거 코드를 보고 그 의미를 파악해서 수정하기도 한다.
다행히 전에 코드를 작성하신 분이 아주 잘 작성해주셔서 그 의미를 파악하는데 크게 어렵지 않게 작업하고 있다.
이번에 토스 결제 에러가 발생하면서 그 원인을 찾아 해결하기 위해 코드를 조금 수정하면서
이해되지 않았던 부분을 등산을 통해 이해하게 되어 기록을 남겨본다.
const tossPayments = window.TossPayments(
process.env.NEXT_PUBLIC_TOSS_CLIENT_KEY
);
tossPayments
.requestPayment(PaymentTypes[paymentType], order)
.catch((error: any) => {
if (error.code === 'USER_CANCEL') {
.....
});
}
});
대충 과정만 떠올려보자면, 토스에 클라이언트 키를 제공하고 페이먼츠 객체를 가져온다.
그리고 사전에 약속된 주문 양식 (변수명 order)를 requestPayment메서드를 사용해 요청한다.
여기까지 문제가 없으면 토스에서 제공한 엘리먼트 안에 주문 결제창이 뜨고 토스에서 결제를 하게 된다.
만약 에러가 있으면 catch문에서 받는데, user_cancel이라고 유저가 중간에 결제를 취소한 경우도 catch문에서 에러코드로 받는다.
이런 로직인데, 아주 드물게 런타임 에러가 나서 페이지가 망가져버리는 상황이 있었다.
토스 측에 문의해본 결과 자신들의 서버에 잠깐 문제가 있었다는 답변을 들었다.
그리고 기획팀에서는 전에도 이런 일이 있어서 대책을 세웠었는데, 토스 요청을 하고 10초간 정상적인 응답이 없다면
재시도를 하거나 문의를 하거나 취소를 할 수 있는 컴포넌트를 띄우기로 하고 조치를 취했는데 똑같은 일이 발생했다고 한다.
아래와 같다.
const timerId = setInterval(() => {
timer += 1;
const tossDimer = document.getElementById('___tosspayments_dimmer___');
if (timer < 10) {
.....
} else if (!tossDimer) {
.....
}
}, 1000);
코드를 분석해보고 내가 분석한 원인은 다음과 같다.
1. 토스에 api 요청하고 엘리먼트를 가져오는 과정은 동기적이다. (tossDimmer의 존재 유무에 대해 우리가 판단할 필요가 없다)
2. setInterval은 비동기 함수라서 위의 코드가 돌아가는 동안 아래 코드가 실행된다.
3. setInterval은 1초에 1번, 총 10번 tossDimmer의 존재 유무를 판단한다.
4. 아래 코드에서 에러가 발생하면 catch문으로 받게 되는데, 토스 측에서 에러코드를 던질 때 10초씩이나 걸릴 리가 없다.
5. 비동기 코드가 10초를 기다리는 동안 catch문에 어떤 에러가 발생했고,
우리는 USER_CANCEL 말고는 에러 처리가 없기 때문에 런타임 에러가 발생했다.
즉, 내 결론은 이전에 작성되어있던 setInterval은 헛바퀴도는 코드라서 필요가 없고 에러 처리만 잘해주면 된다!
catch((error: any) => {
if (error.code === 'USER_CANCEL') {
......
}
window.postMessage({ .... });
docs를 봤지만 토스 측에서 던진 에러가 어떤 에러였는지 도무지 예측할 수 없었다.
그래서 모든 에러에 대응하는 코드를 작성했다(이렇게 해도 되는지 모르겠다.)
대신 에러코드도 같이 받아서 로그를 쌓아 추후에 또 이런 에러가 발생하면 들여다보고 정확한 코드로 리팩터링을 하려고 한다.
그리고 헛바퀴도는 setInterval은 지워버렸다!
등산 중에 깨달은 코드
등산을 하는데 초밥이 너무 먹고 싶어서 가까운 초밥집을 검색하는데 네트워크가 너무 느렸다.
네트워크가 느리다?
만약 토스에 api를 요청하고 tossDimmer를 가져오는 게 동기적인데, 네트워크가 느리면 계속 기다려야 하나?
유저는 10초 이상 기다리게 되면 에러가 났다고 생각해서 서비스를 떠나거나
기다리는 동안 마음이 변해서 구매를 다시 고려하게 될 수 있지 않을까?
내가 지워버렸던 그 코드는 모든 게 정상적인 환경을 위한 코드가 아니라 산 중턱이나 창고같이 통신이 느린 환경에 있는
유저를 위한 코드였구나....
토스에 요청을 보내고 10초 이상 기다리게 되면 나중에 재시도할지 문의를 할지
UX를 위해 한번 소통해주는 코드였구나.
결론은 둘 다 필요하다. 상황에 맞는 에러 처리도 필요하고
10초간 비동기적으로 작동해서 유저를 배려하는 코드도 필요하다.