파트너 포털 갭 감지 오류 수정
목차
파트너 포털의 갭 감지 로직에서 버그를 하나 잡았다. 증상은 단순했는데, 특정 파트너 데이터 조회 시 숫자가 이상하게 나온다는 것. 처음엔 쿼리 문제인가 싶었는데 파고들어 보니 내부 클래스의 비교 로직에서 엣지 케이스가 빠져 있었다.
갭 감지가 왜 틀렸나
갭 감지(gap detection)는 데이터 연속성을 검증하는 로직이다. 파트너별 정산 레코드가 날짜 순으로 이어져야 할 때, 중간에 빠진 구간이 있는지 찾아낸다. 이 로직이 제대로 작동하려면 현재 행과 이전 행을 비교할 때 "같은 파트너의 행인지"를 먼저 구분해야 한다.
문제는 여기서 나왔다. 파트너가 바뀌는 경계-즉 A 파트너의 마지막 행과 B 파트너의 첫 행이 연달아 올 때-를 비교 대상으로 포함시키고 있었다. 서로 다른 파트너 행을 같은 연속 데이터처럼 취급하니까, 없어야 할 갭이 감지되거나 반대로 있어야 할 갭이 묻히는 식으로 결과가 오염됐다.
수정은 내부 클래스 1개, 비교 조건 하나 추가로 끝났다. 파트너 식별자가 달라지면 비교 자체를 건너뛰도록.
// 수정 전: 파트너 구분 없이 이전 행과 무조건 비교
if (prev != null && hasGap(prev, current)) {
gaps.add(current);
}
// 수정 후: 같은 파트너 행끼리만 비교
if (prev != null
&& prev.getPartnerId().equals(current.getPartnerId())
&& hasGap(prev, current)) {
gaps.add(current);
}
코드 자체는 단순한데, 이 조건이 빠진 채로 꽤 오래 돌아갔다는 게 찜찜했다. 정렬 순서에 따라 증상이 재현되거나 안 되거나 했을 거고, 파트너 수가 적을 때는 경계 케이스 자체가 드물어서 눈에 안 띄었을 가능성이 높다. "특정 상황에서만 이상하다"는 버그는 이런 패턴이 많다. 데이터가 적거나 특정 배열일 때 통과했다가, 규모가 커지거나 입력 순서가 달라지면 터진다.
갭 감지 같은 연속성 체크 로직에서 이 종류의 실수가 발생하는 이유는 대개 정렬 기준과 비교 기준이 암묵적으로 연결돼 있다고 가정하기 때문이다. 정렬을 (파트너id, 날짜) 순으로 했으니까 루프 안에서 파트너 경계가 자동으로 처리될 거라는 착각. 정렬이 올바른 그룹핑을 보장해 주지는 않는다. 비교 로직은 항상 독립적으로 방어해야 한다.
수정 범위를 어디까지 잡을까
조건 하나 추가하고 끝낼 수도 있었는데, 같은 패턴을 쓰는 경로가 또 있는지 먼저 확인했다. 갭 감지를 호출하는 지점이 한 군데인지, 비슷한 반복 비교 로직이 다른 클래스나 유틸에 복사돼 있는지. 코드베이스에서 hasGap이나 비슷한 메서드명으로 훑어봤다.
버그 수정 시 내가 챙기는 체크 항목은 대략 이렇다.
| 항목 | 확인 방법 |
|---|---|
| 중복 로직 여부 | 동일 메서드/패턴 코드베이스 검색 |
| 회귀 위험 | 기존 정상 케이스 직접 재현 후 결과 비교 |
| 실제 동작 확인 | 해당 화면 or API 응답 직접 조회 |
| 숫자 정합성 | 관련 화면이나 집계 수치와 cross-check |
이번엔 같은 패턴이 다른 경로에 퍼져 있지 않았다. 그래도 확인하고 넘어가는 것과 그냥 넘어가는 건 나중에 팀 전체가 치르는 비용이 다르다. 수정할 때 한 번 찾아보는 비용은 작고, 나중에 같은 버그가 다른 경로에서 다시 터지는 비용은 크다.
엣지 케이스를 꼼꼼히 따지는 게 귀찮아 보여도, 같은 버그로 다시 돌아오는 시간 비용이 훨씬 크다는 걸 반복해서 체감하고 있다. 특히 버그 수정보다 원인 파악에 시간을 더 쓰는 게 맞다. 원인을 모르면 수정이 맞는지도 알 수 없고, 비슷한 케이스를 찾을 기준도 없다.
파트너 포털처럼 도메인이 얽힌 화면
파트너 포털 같은 화면은 단순히 테이블 하나처럼 보여도 뒤에서 SQL 집계, 상태 계산, 예외 처리, 렌더링, 권한 체크가 동시에 엮여 있다. 어느 하나만 빠져도 숫자가 틀리거나 특정 파트너에게만 이상한 화면이 나온다.
사내 서비스를 만들다 보면 기능 하나가 화면에 버튼 하나 추가하는 것으로 끝나지 않는다는 걸 계속 체감한다. 특히 정산·결제 도메인은 숫자 하나가 틀리면 신뢰가 흔들린다. 파트너 입장에서 갭 건수 하나가 다르게 표시되면 "이 시스템이 제대로 계산하고 있는 건가?"라는 의심으로 이어진다. 그래서 "대충 맞는 것 같다"는 허용 기준이 될 수 없고, 반드시 재현해서 before/after 수치를 직접 확인하는 게 기본값이어야 한다.
수정 후 버그를 직접 재현해서 갭이 올바르게 감지되는지 확인했고, 관련 화면의 집계 숫자와도 맞춰 봤다. 수치가 일치하는 걸 보고 나서야 커밋했다.
커밋 메시지에는 "파트너 경계에서 갭 비교 skip 조건 누락"이라고 적었다. 무엇을 고쳤는지보다 왜 그 버그가 생겼는지가 나중에 히스토리를 볼 때 훨씬 쓸모 있다. 변경 자체는 내부 클래스 1개, 조건 한 줄짜리지만 커밋 단위는 그 맥락을 담을 수 있어야 한다.
작은 커밋 단위를 유지하는 건 이 때문이다. 나중에 비슷한 증상이 다시 생겼을 때 git bisect나 커밋 히스토리를 따라가다 보면 어느 변경에서 문제가 시작됐는지 빠르게 잡힌다. 반대로 덩어리 커밋은 그 범위 안에서 범인을 찾느라 시간을 두 배로 쓴다. 논리적으로 독립된 단위로 커밋을 쪼개는 습관은 지금도 의식적으로 유지하고 있다.
댓글 0
첫 댓글 달아줘.