개발 slecs

비회원 파트너 영수증 자동생성

목차

pay/receipt 영역은 손댈 때마다 긴장이 따라온다. 숫자 하나가 틀리면 그게 UI 버그가 아니라 "정산이 잘못됐다"는 민원으로 돌아오는 도메인이기 때문이다.

이번 작업은 비회원 파트너 대상 영수증 자동생성 로직을 추가하고, 기능 없이 지나간 과거 건들을 백필하는 것이었다. 변경 파일 기준으론 내부 클래스 2개, SQL 매퍼 2개, SQL 파일 1개로 파일 수는 많지 않다. 그런데 막상 펼쳐보면 손댄 레이어가 꽤 많다.

쿼리 레벨부터 설계한 이유

기존 화면과 API가 비회원 파트너 케이스를 명시적으로 고려하지 않은 채 구성돼 있었다. 회원 파트너 기준으로만 조회하거나, 발급 이력 테이블과의 조인이 누락된 구간이 있었다. 단순히 화면에 뭔가를 더 그리는 수준이 아니라, 쿼리부터 다시 설계하지 않으면 정합성을 보장할 수 없는 구조였다.

SQL 매퍼를 손대는 시점이 되면 고려해야 할 게 한 번에 쏟아진다.

  • 기존 쿼리의 집계 기준이 새 케이스에서도 동일하게 적용되는지
  • LEFT JOIN vs INNER JOIN 선택이 결과 행 수에 미치는 영향
  • NULL이 섞였을 때 SUM, COUNT 결과가 기대값과 달라지는 케이스
  • 인덱스가 새 조건에서도 타는지, 실행 계획을 미리 뽑아 확인

특히 발급 이력 테이블 연동 부분에서 NULL 처리를 빠뜨리면 "영수증 발급 0건"이 아니라 아예 조회 결과에서 빠지는 상황이 생긴다. 집계 화면에서 카운트가 맞고 상세 화면에서 다르게 보이면, 그게 곧 "숫자가 틀렸다"는 신고로 이어진다.

-- 발급 이력이 없는 파트너도 누락되지 않도록
SELECT
    p.partner_id,
    p.partner_name,
    COALESCE(SUM(r.amount), 0)  AS total_amount,
    COUNT(r.receipt_id)         AS receipt_count
FROM partner p
LEFT JOIN receipt r
    ON r.partner_id = p.partner_id
    AND r.issued_yn = 'Y'
WHERE p.member_yn = 'N'   -- 비회원 파트너만
GROUP BY p.partner_id, p.partner_name

COALESCE로 NULL을 방어하는 건 기본 중에 기본인데, 이걸 안 쓰면 SUM이 NULL로 나와서 화면에 -이나 공백이 표시된다. 그 공백 하나가 "금액이 사라졌다"는 리포트를 만든다.

백필 작업의 현실

기능이 없던 기간의 데이터를 소급 생성하는 건, 신규 기능 개발보다 조심해야 할 때가 많다. 이미 운영 중인 데이터에 손을 대는 거니까.

백필 SQL을 작성할 때 내가 지키는 원칙은 몇 가지 있다.

단계 내용
사전 COUNT 백필 대상이 몇 건인지 먼저 확인
드라이런 SELECT로만 먼저 돌려서 예상 결과 검증
트랜잭션 분리 한 방에 전체를 커밋하지 않고 배치 단위로
롤백 시나리오 확인 중간에 실패하면 어디서부터 재시작할지
운영 적용 후 대조 숫자가 기대한 범위 안에 들어오는지 즉시 확인

이번엔 과거 건 수가 그리 많지 않아서 트랜잭션 단위 분리까지 갈 필요는 없었지만, 원칙은 지켰다. SELECT 먼저, 예상 건수 확인, 적용, 결과 대조. 그냥 UPDATE 한 방 날리고 "됐겠지"는 절대 금물이다.

검증과 개발 습관

구현 후에는 직접 화면을 밟았다. 상세 페이지에서 영수증으로 이어지는 동선, 비회원 파트너 케이스에서 정상 표시되는지, 기존 회원 파트너 화면에 영향이 없는지. 숫자는 관련된 다른 화면과 cross-check했다. 집계 화면의 합산이 상세 화면의 각 건을 더한 값과 같은지, 발급 이력 개수가 맞는지.

개발 방식도 조금씩 굳어지고 있다. 변경 전에 현재 동작 수치나 화면을 메모해두고, 수정 후 같은 케이스로 다시 확인한다. 커밋 메시지는 "무엇을 바꿨다"보다 "왜 바꿔야 했는지"를 담으려 한다. 두 달 뒤에 git log를 뒤질 때, fix receipt query 보다 비회원 파트너 영수증 조회 시 이력 없는 케이스 누락 방어 쪽이 훨씬 빠르게 컨텍스트를 복원해준다.

작은 커밋으로 쪼개는 것도 계속 유지하고 있다. 클래스 변경, 매퍼 변경, 백필 SQL을 하나의 커밋에 묶어버리면, 나중에 "백필 이후로 뭔가 달라졌다"는 이슈가 생겼을 때 어디서 깨진 건지 찾기가 배로 어려워진다. 논리적으로 독립된 단위로 나누면 git bisect든 단순 로그 탐색이든 훨씬 빠르다.

금융/결제 도메인에서 오래 작업하다 보면 "대충 맞는 것 같다"는 감각을 경계하게 된다. 그 감각이 맞을 때도 있지만, 틀렸을 때의 비용이 다른 도메인보다 크다. 꼼꼼한 게 느린 게 아니라, 결국 덜 돌아가는 길이다.

댓글 0

첫 댓글 달아줘.