대량 상태 전환 작업을 앞두고 외부 API를 경유하는 느린 경로와 DB를 직접 고치는 빠른 경로를 놓고 골라야 했다. 직접 경로를 고르려다 멈춘 것은 그 선택이 무엇을 함께 없애는지를 뒤늦게 봤기 때문이다.
Table of contents
Open Table of contents
경유 경로에 내장된 되먹임
외부를 경유하면 응답이 오고 그 응답이 내 전제를 반증할 수 있다. 이 상품들이 아직 마켓에 살아 있다는 전제로 대량 수정을 걸었는데 실제로 몇몇이 이미 삭제됐다면 그 마켓이 삭제된 상품은 수정할 수 없다는 응답을 돌려준다.
이 응답이 오면 시스템이 스스로 그 건을 연동 해제하므로 내가 아무것도 안 해도 전제가 틀렸다는 사실이 실행 중에 드러난다. 전제 검증이 경로 안에 내장돼 있는 것이다.
직접 경로가 없애는 채널
DB를 직접 고치면 그 응답이 오지 않는다. 애초에 외부에 묻지 않으므로 반증이 들어올 자리가 아예 없는 것이다.
그래서 전제가 틀려도 전량이 성공으로 끝난다. 갱신된 행 수가 나오고 오류는 0이며 로그도 깨끗하게 남는다. 이것을 순환논리라고 부르려다 말았다. 순환논리는 최소한 논리 안에서 순환이라도 하는데 이것은 틀렸다는 사실이 도달할 통로 자체를 내가 닫은 것이라 순환보다 나쁘다.
전제와 근거의 순환
직접 경로를 고른 근거는 이 건들이 어차피 외부에 없으니 호출이 불필요하다는 것이었다. 그런데 그 판단의 근거가 곧 검증하려던 전제였다. 외부에 없다는 것을 확인하는 방법이 호출인데 없다고 가정하고 호출을 뺀 것이다.
그런데 실제로는 외부에 남아 있는 것이 있었다. 그것들에 대해서는 호출이 불필요하다는 전제가 틀렸고 그 틀림이 드러날 방법도 함께 사라졌을 것이다.
같은 형태의 다른 사례
예외를 삼킨 경우가 있었는데 알림 발행 경로의 예외를 가드로 감쌌더니 권한이 회수돼도 발행만 실패하고 나머지는 정상이라 함수가 성공으로 끝났다. 호출 횟수는 정상이고 오류는 0이며 자기 감시 경보도 정상이었다. 정확히 탐지하면서 영원히 배달하지 못하는 상태가 무기한 지속됐다.
가드를 넣기 전에는 같은 실패가 예외로 올라가 오류 경보가 울렸고 그 경보는 실제로 배달됐다. 가드 하나가 그 통보 경로를 끊은 것이다.
성공 문구가 남은 경우도 있었는데 잡 로그에 저장 성공이 찍혀 있으면서 실제로는 등록이 되지 않았다. 마지막으로 통과한 중간 단계의 메시지가 남은 것인데 로그로 성공 건을 집계하면 실패가 성공으로 섞여 들어간다.
확인할 것
이 경로에 내 전제를 반증할 응답이 있는지를 먼저 묻는다. 없다면 그 경로는 내가 옳다는 전제 위에서만 동작하는 것이다.
빠른 경로를 고를 때 무엇이 함께 사라지는지 센다. 속도의 대가가 검증 채널이면 비싼 거래다. 직접 경로를 꼭 써야 하면 검증을 경로 밖에 만든다. 실행 전에 표본으로 외부 상태를 조회하고 실행 후에 다른 방식으로 되읽는 것인데, 경로 안에 없으면 밖에 두면 된다. 예외를 삼킬 때는 보상 통제가 있는지 보고 없으면 예외를 올려 경보가 울리게 두는 편이 낫다.
결국 고른 것
결국 느린 경유 경로로 갔고 예상대로 시간이 걸렸으며 실패도 나왔다.
그런데 그 실패가 전제가 틀린 지점을 알려 줬고 그 수가 예상보다 많았다. DB로 갔으면 전부 성공으로 찍히고 몇 주 뒤에 다른 증상으로 돌아왔을 것이다.
정리
- 경유 경로에는 전제를 반증하는 되먹임이 내장돼 있다
- 직접 경로는 빠른 대신 그 채널을 없앤다
- 전제가 틀려도 전량 성공으로 끝난다
- 이것은 순환논리가 아니라 자기봉인이고 순환보다 나쁘다
- 빠른 경로를 고를 때 무엇이 함께 사라지는지 센다
- 직접 경로가 필요하면 검증을 경로 밖에 만든다
- 예외를 삼킬 때 보상 통제를 먼저 확인한다