정산 수수료 차감이 조용히 스킵되던 버그 수정
목차
confirmPendingSettlement 안에서 수수료 차감이 조용히 스킵되고 있었다. 로그에 에러 하나 없고, 예외도 터지지 않으니 겉으로는 정상 흐름처럼 보이는데 숫자만 틀리게 쌓이는 상황. 증상이 즉각적이지 않아서 파악하는 데 시간이 걸렸다.
왜 이런 버그가 생기나
정산 플로우는 상태 전이가 여러 단계에 걸쳐 있다. pending → confirmed 전환 시점에 수수료를 차감해야 하는데, 내부 클래스 로직에서 특정 조건 분기가 누락되거나 예외가 소리 없이 삼켜지면 차감 자체가 실행되지 않고 그냥 흘러간다. 호출 측에서는 성공 응답을 받으니 문제를 감지할 기회가 없다.
이런 버그가 특히 위험한 이유는 "실패처럼 보이지 않기 때문"이다. 서버는 멀쩡히 돌고, 로그엔 아무것도 없고, 기능 자체는 작동하는 것처럼 보인다. 그런데 DB를 열어보면 balance가 줄어 있어야 할 곳에 그대로다. 누적될수록 정합성이 무너지는 유형이라 발견하면 빠를수록 낫다.
문제의 전형적인 패턴 두 가지:
// 패턴 A: 예외를 삼키고 아무것도 하지 않음
try {
feeDeductionService.deduct(settlement);
} catch (Exception e) {
// 로깅도 없음, 재시도도 없음, 그냥 통과
}
// 패턴 B: 특정 케이스가 분기에서 아예 빠짐
if (settlement.getType() == SettlementType.STANDARD) {
deductFee(settlement);
}
// PARTNER 타입이거나 null이면 아무것도 안 함
// — 의도인지 누락인지 코드만 봐선 알 수 없음
패턴 B가 더 찾기 어렵다. 예외가 없으니 스택 트레이스도 없고, 분기 자체가 작성 당시 의도였는지 실수였는지 코드만 봐선 판단이 안 된다. 이번 케이스는 이 두 패턴이 섞인 형태였다.
수정 방향과 탐색 범위
내부 클래스 하나를 수정하는 것으로 끝났지만, 그 전에 한 작업이 더 많았다. 같은 패턴이 다른 경로에도 있는지 먼저 탐색했고, 위험해 보이는 케이스는 같이 묶어서 처리했다. 하나만 고치고 나머지를 "나중에"로 미루면 그 나중이 잘 오지 않는다.
수정할 때 기준으로 삼은 것들:
- 예외는 삼키지 말 것. catch 블록이 비어 있거나 로그만 찍고 흘려보내는 구조면 일단 의심한다. 금융 도메인에서 수수료 차감 실패는 최소한 알람이나 error 레벨 로그가 남아야 한다. 흘려보낼 거라면 명시적으로 그 결정을 주석이나 코드로 드러낼 것.
- 분기 누락인지 의도인지 명시. 특정 타입을 건너뛰는 게 올바른 동작이라면
// intentional: PARTNER type has no fee같은 주석이 있어야 한다. 그냥if로 감싸고 else 없이 끝나면 리뷰어도 나중에 유지보수할 사람도 판단하기 어렵다. - 수정 범위는 최소화, 단 같은 위험 패턴은 같이 잡을 것. 한 파일만 고치면서 동일한 냄새가 나는 코드를 옆에 두면 다음 사람이 같은 길을 걷게 된다.
수정 후 로직은 명시적 실패 처리를 포함하도록 바꿨다. 차감이 불가능한 상황이면 호출 측에서 인지할 수 있게, 그리고 로그에 흔적이 남게.
검증 - 숫자 정합성까지
버그 수정 후 검증에서 어떤 방식을 가져가느냐가 중요하다. 단순히 "돌아가는 것 같다"로 끝내면 같은 자리에서 다시 오는 경우가 생긴다.
| 확인 항목 | 방법 |
|---|---|
| 버그 재현 가능 여부 | 동일 조건으로 재현 후 수정 전/후 동작 비교 |
| 정상 케이스 회귀 | 기존에 정상이던 플로우가 깨지지 않는지 확인 |
| 숫자 정합성 | 관련 화면/API 응답과 DB 값 비교 |
| 중복 패턴 탐색 | 동일 로직이 다른 경로에도 있는지 탐색 |
이번엔 차감 후 partner balance 수치를 관련 화면 두 곳에서 같이 확인했다. 한 곳에서만 보면 렌더링 레이어의 버그인지 DB 레이어의 버그인지 구분이 안 되는 경우가 있어서, 가능하면 두 곳 이상에서 cross-check하는 편이다.
엣지 케이스를 꼼꼼히 따지는 게 귀찮아 보여도, 나중에 같은 버그로 다시 오는 시간 비용이 훨씬 크다. 재현-수정-검증 사이클을 제대로 한 번 도는 게 두 번 어설프게 도는 것보다 낫다.
금융/정산 도메인에서 계속 상기하는 것들
파트너 정산처럼 돈이 직접 오가는 도메인은 "대충 맞는 것 같다"가 가장 위험한 상태다. UI는 멀쩡해 보이는데 내부 숫자는 조금씩 어긋나 있는 상황이 이번처럼 조용히 쌓인다. 신뢰는 한 번 무너지면 회복하기 어렵고, 그 시작이 수수료 몇 건 누락 같은 작은 데서 비롯된다.
사내 서비스는 기능 하나가 SQL 집계, 상태 머신, 예외 처리, 화면 렌더링, 권한 체크가 전부 엮인 채로 돌아가는 경우가 많다. 어느 한 곳에서 조용히 빠져나가면 어디서 새는지 찾는 게 제일 힘들다. 이번 버그가 그 케이스였고, 로그 하나 안 남기고 스킵되던 게 결국 핵심이었다.
이 도메인에서 코드를 만질 때 스스로 지키려는 습관:
- 변경 전 현재 수치 메모 또는 스크린샷 - 수정 후 비교 기준을 미리 확보
- 커밋 메시지는 "무엇을 바꿨다"보다 "왜 바꿨다" 위주로 - 나중에
git blame찍었을 때 맥락이 있는 게 훨씬 낫다 - 논리적으로 독립된 단위로 커밋을 쪼갬 - 무언가 깨졌을 때 어느 변경에서 깨졌는지 추적하기 위해
작은 커밋 습관이 실제로 도움됐던 건 이번이 처음이 아니다. 넓게 묶어서 커밋하면 나중에 bisect하거나 revert할 때 선택지가 줄어든다. 조금 귀찮더라도 논리 단위로 쪼개는 게 장기적으로 낫다는 걸 계속 확인 중이다. 이번 수정도 별도 커밋으로 분리해서 히스토리에 맥락을 남겼다.
댓글 0
첫 댓글 달아줘.