기술

배포 확인용 계좌를 잘못 골랐고, 영향 범위는 조인으로 다시 셌습니다

2026.10.069분 읽기

B2B 채권 분석 시스템의 월 원장에서 계좌 101건이 사유 없이 사라졌습니다. 전월까지 상각이 돌던 계좌인데 상각 기록도, 멈췄다는 기록도 없었습니다. 원인은 적격 여부를 월마다 다시 재는 구조였고, 판정을 계좌 참조 행이 생길 때 한 번만 하고 그 뒤로는 그때 적어 둔 '판정 결과 칸'만 읽도록 고쳤습니다.

고친 코드를 운영 서버에 올렸습니다. 남은 일은 하나였습니다. 새 코드가 실제로 그 서버에서 돌고 있는지 보는 것입니다. 배포는 됐다고 하는데, 됐다는 말과 돌았다는 사실은 다릅니다. 그래서 판별용 계좌를 하나 골라 확인하기로 했습니다.

그 계좌를 고른 것이 첫 번째 실수였습니다. 그리고 영향 범위를 세면서 두 번째로 틀렸습니다. 두 실수의 뿌리는 같았습니다.


고른 계좌가 하필 양쪽 답이 같았습니다

처음 고른 계좌의 참조 행은 판정 결과 칸이 비어 있었습니다. 옛 코드는 코드에 박아 둔 기준일 조건으로 이 계좌를 통과시킵니다. 새 코드는 '결과 칸이 비었으니 통과'라는 경로로 통과시킵니다. 경로는 다른데 답은 같습니다.

이 계좌로 상각이 찍힌 것을 봐도 알 수 있는 건 없습니다. 옛 코드가 돌아도 찍히고 새 코드가 돌아도 찍히기 때문입니다. 통과를 확인했다는 사실이 배포를 확인했다는 뜻이 되지 않습니다. 실패할 수 없는 검사를 고른 것입니다.

검사를 고를 때 저는 '이걸로 통과가 뜨나'를 먼저 봤습니다. 그 질문에는 답이 나옵니다. 문제는 그 답이 아무것도 가리지 않는다는 것입니다. 물었어야 할 질문은 하나 더 있었습니다. 이게 아니라면 무엇이 보일까. 답이 '똑같이 보인다'면 그 검사는 돌릴 이유가 없습니다.

배포 확인을 하루에 세 번 하고도 아무것도 확인하지 못했던 기록을 따로 정리해 뒀습니다. 같은 자리입니다.

응답이 200이라는 사실이 새 코드가 돌았다는 근거가 못 되는 이유를 그 글에 적었습니다.

옛 코드와 새 코드가 같은 답을 내는 계좌와 서로 다른 답을 내는 계좌를 좌우로 비교한 그림


두 코드의 답이 갈리는 계좌를 다시 골랐습니다

다시 고른 계좌는 기준일 당일 재조정으로 참조 행이 새로 생긴 건이었습니다. 그 행은 앞선 값을 물려받으면서 법비용만 조금 남고 원가는 0인 상태였습니다. 이 조합이 중요합니다.

옛 코드라면: 등록일이 기준일과 같은 날이라 박아 둔 날짜 조건을 빠져나가지 못하고, 이어서 저원가 조건에 걸려 상각이 생기지 않아야 합니다

새 코드라면: 생성 시점에 적어 둔 판정 결과 칸을 읽으므로 그대로 진행돼 상각이 생겨야 합니다

두 예측이 서로 반대입니다. 무엇이 찍히든 한쪽이 지워집니다

실제로는 중단, 재조정, 그 달 말일자 상각이 순서대로 찍혀 있었습니다. 새 코드만 낼 수 있는 흐름입니다. 배포가 실렸다고 판정한 근거는 '검사를 통과했다'가 아니라 '옛 코드라면 나올 수 없는 흔적이 찍혔다'였습니다.

갈림길이 어디였는지도 나중에 보니 제 예상과 달랐습니다. 저는 수익률 상한 조건에서 갈릴 거라고 봤는데 실제로 가른 것은 저원가 조건이었습니다. 표본이 1건일 때는 표본을 고르는 일이 곧 검사 설계입니다. 대량 데이터에서 1건을 뽑는 게 싼 이유는 건수가 적어서가 아니라 고르는 기준이 맞았을 때뿐입니다.


영향 범위를 세다 두 번째로 틀렸습니다

새 코드가 운영 서버에서 실행되는 것을 확인했으니 다음은 영향 범위였습니다. 기준을 바꿨으니 기존에 상각이 돌던 계좌 중 빠지는 것이 있는지 세야 했습니다. 이 숫자가 배포를 되돌릴지 말지를 가릅니다.

저는 '등록일이 기준시각 이전인 마지막 활성 행'이라는 조건으로 참조 행을 골랐습니다. 그중 결과 칸이 채워진 것을 '새 코드에서는 빠질 후보'로 분류했고, 그렇게 30건을 셌습니다. 30건이면 작지 않은 숫자라 되돌리는 쪽을 검토하기 시작했습니다.

그런데 그 계좌들의 그 달 원장을 실제로 몰고 있던 것은 같은 날 등록된 다른 참조 행이었습니다. 한 계좌에 참조 행이 여럿 붙을 수 있는 구조인데, 제가 조건으로 고른 행과 원장이 실제로 물고 있는 행이 달랐습니다. 그리고 실제로 물고 있던 그 행은 결과 칸이 비어 있었습니다. 어느 코드로 돌든 상각이 생깁니다. 그렇게 센 30건은 모두 잘못 집계한 값이었습니다.

조건으로 고른 참조 행과 원장이 실제로 물고 있는 참조 행이 서로 다른 구조를 그린 그림


조건이 아니라 조인으로 다시 셌더니 방향이 뒤집혔습니다

다시 센 방법은 간단합니다. 조건으로 참조 행을 고르지 않고, 그 달 상각행이 실제로 물고 있는 참조 행으로 조인했습니다. 278,155행이 전량 조인됐고, 그중 결과 칸이 채워진 행은 0건이었습니다.

세는 방법

대상 선정

결과

1차

조건으로 참조 행을 골라 분류

빠지는 계좌 30건

2차

상각행이 물고 있는 참조 행으로 전량 조인

빠지는 계좌 0건, 늘어나는 쪽만 있음

1차와 2차는 크기가 다른 게 아니라 방향이 반대였습니다. 줄어든다와 늘어난다는 되돌릴지 말지를 가르는 판단입니다. 1차 추정을 믿고 배포를 되돌렸으면 멀쩡한 작업을 되돌렸을 겁니다.

재실행 전에 기준값을 찍어 두고 전량 재실행을 시작했습니다. 그 달 원장 전체가 1,331,182행, 그중 상각 275,748행, 중단행 2,042행, 종결 856,533행, 미생성 계좌 0입니다. 기대값은 상각 +96 근처, 중단행 +278 근처, 미생성 0 유지, 상각이 사라진 계좌 0으로 잡았습니다. 기대값을 먼저 적어 두면 결과가 그럴듯해 보인다는 이유로 넘어가는 일이 줄어듭니다.

원인을 말하기 전에 재고 나서 뒤집힌 사례를 따로 적어 뒀습니다. 그쪽은 성능 이야기지만 순서는 같습니다.


두 실수의 뿌리는 하나였습니다

첫 번째에서는 두 코드가 갈리지 않는 계좌를 골랐습니다. 두 번째에서는 원장이 실제로 참조하는 행이 아니라 제가 고르기 편한 조건에 맞는 행을 골랐습니다. 둘 다 '내가 보려는 것이 이 관측으로 갈리나'를 묻지 않은 결과입니다.

더 위험했던 건 둘 다 결과가 그럴듯하게 나왔다는 점입니다. 상각이 찍혔고, 30건이라는 숫자도 나왔습니다. 틀린 검사는 아무 결과도 안 내는 게 아니라 맞는 검사와 똑같이 생긴 결과를 냅니다. 화면만 보고는 구분이 안 됩니다.


검사를 고를 때 보는 것

이게 아니라면 무엇이 보이나. 답이 '똑같이 보인다'면 그 검사는 아무것도 하지 않습니다

배포 확인은 응답이 정상이냐가 아니라 새 코드만 낼 수 있는 흔적이 있냐로 봅니다

집계는 조건으로 고른 것이 아니라 실제로 물고 있는 것으로 조인합니다. 한 키에 여러 행이 붙는 구조라면 거의 항상 이 함정이 있습니다

영향 범위는 크기만이 아니라 방향이 뒤집힐 수 있다고 보고 셉니다

표본이 1건이면 표본 선정 자체를 검사 설계로 적어 둡니다

반대로 모든 검사를 갈리는 표본으로 고를 수는 없습니다. 최소한 살아 있는지 보는 검사는 원래 실패하기 어렵게 설계된 것이고, 그건 그 자리의 목적에 맞습니다. 문제는 '살아 있나'용 검사를 '바뀌었나'의 근거로 쓸 때 생깁니다.

전량 조인이 늘 가능한 것도 아닙니다. 278,155행이라 전량이 됐지 수억 행이면 조인 자체가 비용입니다. 그때는 표본을 쓰되 선정 기준을 검사 설계로 취급해서 층을 나눠 뽑고, '이 기준으로 뽑으면 무엇이 빠지나'를 같이 적어 둡니다. 갈리는 표본이 데이터에 아예 없는 경우도 있습니다. 그럴 때는 표본을 더 뒤지는 대신 코드가 거기 있는지를 직접 봅니다. 배포된 커밋, 빌드 산출물, 새로 뜬 프로세스의 기동 시각이 그 자리입니다.

검사를 고르기 전에 던지는 두 질문과 그 결과를 위아래로 나눈 그림


남는 것

이번 건은 '결과 칸이 비었을 때도 통과'라는 설계 때문에 두 코드의 답이 겹쳤습니다. 기본값이 통과인 조건은 구조적으로 판별력을 깎습니다. 검사 설계를 손보기 전에 이쪽을 먼저 의심해 볼 여지도 있었습니다.

배포는 실렸고, 영향 범위는 빠지는 계좌 0건에 늘어나는 쪽만 있는 것으로 확정했습니다. 별개로 확인한 것이 하나 더 있습니다. 승계 재조정에서 저원가를 보지 않는 것은 의도로 정리했습니다. 원가가 0이어도 법비용이 남으면 계속 진행하고, 완전히 0원인 건은 다른 자리에서 따로 멈춥니다. 늘어난 96건 중 86건에 실제 상각액이 붙어 있어 빈 행이 아니었습니다.

확인 작업을 설계할 때는 무엇을 볼지보다 무엇이 지워지는지를 먼저 적어 두는 편이 낫습니다. 지워지는 게 없는 관측은 시간만 씁니다.

#배포검증#반증가능성#데이터검증#조인#표본선정