거래명세서 집계 구조를 결제 단일 행으로 단순화
목차
거래명세서 집계 로직을 손봤다. 변경 파일은 내부 클래스 하나, SQL 매퍼 하나, 뷰/스타일 하나 — 숫자만 보면 작은 작업이지만, 결제 단일 행으로 통일한다는 결정 자체는 생각보다 무게감이 있었음.
결제 집계처럼 금액이 직접 노출되는 영역을 건드릴 때는 "잘 돌아가고 있으니까 그냥 둔다"는 선택지가 항상 눈앞에 있다. 이번에 그걸 무시한 이유는 단순했음. 기능은 작동하는데 코드 구조가 나중에 유지보수하기 어려운 상태였고, 같은 로직이 여러 곳에 중복돼 있어서 버그 수정 한 번에 세 군데를 동시에 손대야 하는 상황이 반복됐음. 그 중 하나를 빠뜨리면 숫자가 틀리는 형태였다.
statement 집계를 단일 행으로 단순화한 배경
거래명세서 집계는 흔히 "여러 항목을 묶어서 보여준다"는 UI 요구사항에서 시작하는데, 시간이 지나면서 집계 단위가 섞이기 시작한다. 처음엔 결제 건별로 집계하다가, 요청 사항이 생기면서 항목별로 한 번 더 집계하고, 뷰에서 또 가공하는 구조가 생긴다. 각 계층이 서로를 모른 채 조금씩 계산을 거들다 보면 어디서 최종 숫자가 나오는지 추적하기가 점점 어려워짐.
이번 케이스도 비슷했다. SQL 매퍼에서 집계를 한 번 하고, 내부 클래스에서 결과를 다시 가공하고, 뷰에서 표시용으로 또 계산하는 형태였음. 결제 단일 행으로 통일하면 집계 책임이 SQL 매퍼 한 곳으로 모인다. 단순해 보이지만 이게 맞는 방향이다 — DB가 집계를 제일 잘 하고, 애플리케이션 레이어와 뷰는 그 결과를 그냥 전달하면 됨.
SQL 쪽 변경 방향을 단순하게 표현하면 이런 식이다:
-- 변경 전: 항목별로 GROUP BY 후 상위에서 다시 집계
SELECT
payment_id,
item_type,
SUM(amount) AS item_total
FROM transactions
GROUP BY payment_id, item_type
-- 변경 후: 결제 단위로만 집계
SELECT
payment_id,
SUM(amount) AS total
FROM transactions
GROUP BY payment_id
실제 쿼리는 더 복잡하지만 방향성은 이렇다. 집계 계층이 하나 줄어들면 그 결과를 받아서 가공하던 내부 클래스 쪽 코드도 따라서 단순해진다.
주요 변경 내용과 원칙
이번 리팩토링에서 건드린 것들:
- 인라인 JS를 외부 파일로 분리 — 브라우저 캐시를 쓸 수 있게 됨. 중복 함수가 뷰 안에 인라인으로 박혀 있으면 캐시도 못 쓰고 검색도 어렵다
- 중복 함수 통합 — 거의 똑같은 포매팅 함수가 두 곳에 있었음
- 변수명 명확화 —
data,result,tmp류를 실제 의미가 담긴 이름으로 - 의존성 로딩 순서 정리 — 순서가 틀려서 간헐적으로 undefined가 뜨던 케이스 방지
지켰던 원칙을 정리하면:
| 원칙 | 실제 적용 |
|---|---|
| 동작 불변 | 리팩토링 전후 화면 수치 동일 여부 직접 확인 |
| 단일 책임 | 집계는 SQL, 변환은 클래스, 렌더링은 뷰로 분리 |
| DRY | 중복 집계 로직 및 포매팅 함수 통합 |
| 최소 변경 | statement 관련 파일 3개만 건드리고 범위 확장 안 함 |
리팩토링에서 "최소 변경" 원칙이 항상 쉽지는 않다. 한 군데를 보다 보면 옆에 더 고치고 싶은 게 눈에 들어오는데, 그걸 같이 묶으면 커밋이 커지고 나중에 무엇 때문에 뭐가 바뀐 건지 추적이 힘들어진다. 이번에도 몇 가지 유혹이 있었는데 별도 커밋으로 미뤘음.
금융 도메인 리팩토링을 대하는 방식
금융/결제 영역 코드를 건드릴 때 제일 중요한 건 변경 전 기준값을 확보하는 것이다. 어떤 케이스에서 얼마가 나와야 하는지 수치를 메모하거나 스크린샷을 찍어두고, 리팩토링 이후 같은 케이스를 돌려서 숫자가 일치하는지 확인했음. 단순한 절차인데 이걸 생략하면 "대충 맞는 것 같다"로 넘어가게 되고, 그게 나중에 반드시 돌아온다.
관련 화면이 여러 개면 숫자 cross-check도 했다. 목록 화면 합계, 상세 화면 합계, SQL 직접 조회 값 이 세 가지가 일치하면 통과.
커밋 메시지는 "무엇을 바꿨다"보다 "왜 바꿨다"를 담으려고 했다. statement 집계 단순화 보다는 결제 단위 집계 중복 제거 — 유지보수성 개선 쪽이 나중에 git blame 볼 때 컨텍스트가 살아 있다.
작은 커밋을 자주 하는 습관은 결국 문제가 생겼을 때 어느 변경에서 깨졌는지 찾는 시간을 줄이는 투자다. 논리적으로 독립된 단위로 쪼개면 bisect를 썼을 때 범위가 확 좁혀진다. 사내 서비스라도 이 습관을 유지하는 게 장기적으로 낫다고 계속 느끼는 중.
사내 서비스를 만들다 보면 버튼 하나 추가하는 게 SQL 집계, 상태 처리, 예외 케이스, 권한 체크가 전부 엮여 있다는 걸 계속 체감한다. 특히 금융 도메인은 숫자 하나가 틀리면 신뢰가 무너지는 영역이라, 꼼꼼함이 선택이 아니라 기본값이어야 한다. 이번 리팩토링도 그 기본값을 지키면서 구조를 정리한 작업이었다.
댓글 0
첫 댓글 달아줘.