개발 slecs

매출 분석 차트에 결제 데이터 정합성 갖춘 신규 기능 추가

목차

analytics 영역에 신규 기능을 추가했다. 매출 분석 차트의 시인성·디자인 개선이 목적이었는데, 변경된 파일은 뷰/스타일 1개지만 실제로 손댄 레이어는 그보다 훨씬 많았다.

왜 쿼리부터 건드렸나

기존 화면과 API가 제공하지 않던 데이터와 동작이 필요해져서 기능을 확장했다. 처음엔 "화면에 섹션 하나 추가하면 되지 않나"라고 생각할 수 있는데, 막상 열어보면 그렇게 단순하지 않다.

analytics 화면은 집계 데이터를 다루는 특성상, 보여주는 숫자의 원천이 어디인지 명확해야 한다. 이미 다른 화면에서 보이고 있는 매출 수치와 새 차트의 수치가 어긋나면 운영팀에서 혼란이 생긴다. 이런 경우를 보면 대개 "집계 기준은 다른데 UI는 비슷해 보이는" 케이스다 — 기간 기준이 생성일인지 결제 완료일인지, 취소 건을 포함하는지 여부 같은 게 슬쩍 어긋나 있는 것. 숫자만 보면 아무도 눈치 못 채다가, 운영팀이 엑셀로 뽑은 수치와 비교하는 순간 터진다.

그래서 단순 UI 추가가 아니라 쿼리 레벨부터 설계해서 정합성을 맞추는 방향으로 갔다. 구체적으로는 관련 내부 클래스에 메서드를 추가하고, SQL 매퍼에 쿼리를 작성한 뒤 화면 렌더링과 연동했다. 기존 로직과 충돌 여부도 함께 확인했다.

설계하면서 따진 것들

데이터 정합성부터. 금융·결제 도메인에서 새 기능을 붙일 때 가장 먼저 따지는 건 "기존 데이터가 깨지지 않는가"다. 새 집계 쿼리가 기존 집계와 같은 기준인지, 같은 상태값을 필터링하는지 확인해야 한다. 기준이 다르면 어느 쪽도 틀린 게 아닌데 숫자가 달라 보이는 상황이 된다. 이게 제일 설명하기 까다롭다.

SQL 매퍼에 쿼리를 작성할 때는 실행 계획을 꼭 확인한다. 집계 쿼리는 데이터가 쌓일수록 풀스캔 위험이 있어서 인덱스 힌트나 날짜 파티셔닝 범위를 미리 체크해두지 않으면, 느려지는 시점에 다시 뜯어야 한다. 날짜 범위를 파라미터로 받을 때는 특히 조심한다.

-- 함수로 감싸면 인덱스 못 탐
WHERE DATE(payment_at) BETWEEN #{startDate} AND #{endDate}

-- 범위 비교로 풀어야 인덱스 탐
WHERE payment_at >= #{startDate}
  AND payment_at <  DATE_ADD(#{endDate}, INTERVAL 1 DAY)

컬럼을 함수 안에 넣는 순간 옵티마이저가 인덱스를 포기하는 케이스가 흔한데, 개발 환경에서 데이터가 적을 땐 티가 안 나서 프로덕션에서 뒤늦게 터지는 경우가 종종 있다. 실행 계획 확인을 배포 전 루틴으로 굳혀두는 게 맞다.

실시간 갱신 여부. 이번엔 폴링이냐 이벤트냐를 결정해야 했다. 기준으로 삼는 건 이런 것들이다.

기준 폴링 이벤트
데이터 변경 빈도 낮음 높음
지연 허용 여부 분 단위 허용 초 단위 필요
인프라 복잡도 낮음 높음
디버깅 난이도 낮음 높음

매출 분석 차트는 실시간이 꼭 필요한 화면이 아니라, 폴링이나 배치 집계로도 충분하다고 판단했다. 이벤트 방식을 넣으면 메시지 큐나 웹소켓이 따라붙는데, 그 복잡도를 감수할 만큼의 이득이 없었다. 기능을 넣을 때 항상 "지금 당장 가장 간단한 방법으로 요구사항을 만족하는가"를 먼저 따지고, 그게 실제로 부족해질 때 복잡도를 올리는 방향이 낫다.

예외 케이스 방어. 빈 데이터, 권한 없는 접근, NULL 처리는 빠뜨리기 쉬운 지점이다. 집계 결과가 NULL인 경우 화면에서 그대로 내려오면 NaN이나 '-'가 조용히 렌더링되는 게 아니라 아예 에러 화면이 뜨는 케이스가 있다. 쿼리 레벨에서 COALESCEIFNULL로 기본값을 잡고, 뷰에서도 null-guard를 겹쳐두는 게 맞다. 두 겹으로 방어하는 게 중복처럼 느껴지지만, 레이어가 다르기 때문에 각자의 역할이 있다. 쿼리가 NULL을 0으로 내려줘도 뷰에서 타입이 바뀔 수 있고, 반대로 뷰만 guard해도 다른 소비자가 같은 API를 쓸 때 raw NULL을 받는다.

검증하고 마무리하면서

구현 후에는 직접 화면에서 동작을 확인했다. 기존 데이터가 깨지지 않았는지, 관련 화면의 숫자가 일치하는지 cross-check했다. 이걸 귀찮아서 건너뛰면 "다른 화면이랑 숫자가 다른데요"라는 피드백이 꼭 들어온다. 그게 배포 다음 날이면 그나마 낫고, 한참 뒤에 "몇 달치 데이터가 이상한 것 같다"는 식으로 오면 훨씬 골치 아파진다.

개발 중에 유지하는 습관 몇 가지가 있다.

  • 변경 전 현재 동작 스크린샷이나 수치 메모해두기
  • 수정 후 같은 케이스로 다시 확인
  • 관련 화면이 있으면 숫자 cross-check
  • 커밋 메시지는 "무엇을"보다 "왜"를 담으려고 노력
  • 논리적으로 독립된 단위로 커밋을 쪼개기

작은 커밋을 자주 올리면 문제가 생겼을 때 어느 변경에서 깨졌는지 찾기 훨씬 쉽다. git bisect를 써도 되고, 그냥 로그를 읽어도 된다. 한 커밋에 "여러 가지 수정" 이 들어가 있으면 그 옵션 자체가 사라진다.

사내 서비스를 만들다 보면 기능 하나가 단순히 화면에 버튼 하나 추가하는 것으로 끝나지 않는다는 걸 계속 체감한다. SQL 집계, 상태 머신, 예외 처리, 화면 렌더링, 권한 체크가 모두 엮여 있어서 어느 하나만 빠뜨려도 숫자가 맞지 않거나 특정 사용자에게 이상한 화면이 나타난다. 금융·결제 도메인은 특히 숫자 하나가 틀리면 신뢰가 무너질 수 있어서 꼼꼼함이 기본값이어야 한다. "대충 맞는 것 같다"로 넘어가면 나중에 반드시 다시 돌아온다.

댓글 0

첫 댓글 달아줘.