일기 slecs

hold 정책 변경에 맞춰 stale 안내 문구 정정

목차

hold 정책이 2h에서 2h 10m으로 바뀌었다. 실제 로직은 이미 반영됐고, 배치나 상태 머신도 문제없이 돌아가고 있었다. 근데 화면에 뜨는 안내 문구가 여전히 "2시간"을 가리키고 있었다. 사소해 보이는 불일치인데, 사용자 입장에서는 "분명히 2시간이라고 나왔는데 왜 아직 hold야?"라는 민원 포인트가 된다. 특히 결제나 운영 도메인에서 숫자가 화면에 틀리게 보이면 신뢰 문제로 튄다.

이번 패치에서 손댄 파일은 네 개였다.

파일 종류 역할 변경 내용
뷰/스타일 파일 (2개) 사용자에게 보이는 안내 문구와 스타일 "2시간" → "2시간 10분"
내부 클래스 (1개) hold 만료 시간 계산 하드코딩된 120 → 130 (분)
SQL 매퍼 (1개) 만료 기준 쿼리에 박힌 INTERVAL 값 분 단위 정정

파일 수가 많아 보여도 이게 사실 문제의 본질이다. 정책 값 하나가 바뀌었는데 네 군데를 손봐야 했다는 것 자체가, 이 값이 단일 출처 없이 여러 레이어에 흩어져 있다는 증거다.

hold 시간이 여러 레이어에 박히는 이유

처음 기능을 만들 때 이런 패턴이 흔하다.

// 내부 클래스
private static final int HOLD_MINUTES = 120;
<!-- SQL 매퍼 -->
WHERE created_at < NOW() - INTERVAL 120 MINUTE
<!-- 뷰 템플릿 -->
<p>hold는 2시간 후 자동 해제됩니다.</p>

각각은 합리적인 선택처럼 보인다. 클래스에서는 상수, SQL에서는 인라인, 화면에서는 자연어. 근데 정책이 바뀌면 세 군데를 다 찾아서 고쳐야 한다. 하나라도 빠지면 로직과 표시가 불일치한다. 이번처럼.

이상적인 구조는 이 값을 한 곳에 두고 나머지가 참조하게 만드는 것이다. 설정 파일이나 DB 상수 테이블에 HOLD_MINUTES = 130 하나를 두고, 뷰는 그걸 받아서 렌더링하고 매퍼는 파라미터로 바인딩하는 방식. 그러면 정책 변경이 설정 파일 한 줄로 끝난다.

현실에서는 항상 가능하진 않다. SQL INTERVAL 값은 동적 바인딩이 까다롭고, 화면 문구는 기획/디자인 쪽에서 직접 수정하는 경로를 선호하기도 한다. 그래서 트레이드오프가 생긴다.

방식 장점 단점
각 레이어에 직접 값 빠르게 짜기 쉬움 정책 변경 시 다중 수정, 불일치 위험
중앙 설정에서 참조 단일 수정으로 전파 초기 설계 비용, 동적 바인딩 복잡도
DB 상수 테이블 런타임 변경 가능 캐시 관리, 조회 비용 추가

지금 상황에서 전면 리팩터는 오버엔지니어링이다. 정책이 자주 바뀌는 값이라면 단일 출처로 옮기는 게 맞겠지만, 그렇지 않다면 이번처럼 정정하면서 주석이라도 달아두는 게 현실적인 차선책이다.

// [정책값] hold 만료 기준 — 변경 시 SQL 매퍼(HoldMapper.xml)·뷰(hold-status.html, hold-detail.html)도 함께 수정
private static final int HOLD_MINUTES = 130;

이것만 해둬도 다음에 바꾸는 사람이 어디를 찾아야 하는지 알 수 있다. 주석 한 줄이 다음 PR 하나를 막아준다.

stale 문구가 생기는 흐름과 예방

문구 불일치는 보통 이런 경로로 만들어진다.

  • 백엔드 정책 값이 먼저 바뀜 (상수, 배치 스케줄 등)
  • 화면 문구는 "다음 배포 주기에 고치자"고 했다가 누락
  • SQL 매퍼는 쿼리 담당자가 별도로 반영하거나 아직 미반영

각 레이어가 다른 팀이나 다른 배포 단위에 속할수록 이런 드리프트가 생기기 쉽다. "기능은 제대로 동작하니까 화면 문구는 다음에 고쳐도 되지 않을까"라는 판단이 조금씩 쌓이면, 결국 사용자에게 틀린 정보가 노출되는 시간이 길어진다.

뷰와 로직이 같은 배포 단위에 묶여 있다면 정책 상수를 바꾸는 PR에 뷰 변경도 같이 묶어서 리뷰받는 게 제일 안전하다. 그게 어렵다면 정책 값 주석에 영향 범위를 명시하는 것만으로도 다음 사람이 빠뜨릴 가능성을 낮출 수 있다. 체크리스트를 별도로 만들어서 관리하는 팀도 있는데, 그 정도까지 필요한지는 해당 정책 값이 얼마나 자주 바뀌는지에 달려 있다.

사내 서비스를 만들다 보면 기능 하나가 화면 버튼 하나로 끝나지 않는다는 걸 계속 체감하게 된다. SQL 집계, 상태 머신, 예외 처리, 화면 렌더링이 전부 엮여 있어서 어느 하나만 빠뜨려도 숫자가 맞지 않거나 특정 상황에서 이상한 화면이 나온다. 이번 작업이 딱 그 케이스였고, 매퍼까지 확인하지 않았다면 화면 문구만 고쳐진 채로 배포됐을 거다. 화면은 2시간 10분이라 나오는데 만료 처리는 2시간 기준으로 돌아가는 상태.

작업 방식과 후기

이런 유지보수 작업을 할 때 지키는 루틴이 있다.

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

커밋을 논리적으로 작은 단위로 쪼개는 습관도 유지 중이다. 문제가 생겼을 때 어느 변경에서 깨졌는지 찾기 훨씬 쉬워진다. 이번처럼 문구 정정과 로직 상수 수정이 같은 정책 변경에서 비롯된 거라면 같은 커밋에 묶는 게 맞고, 그것과 독립적인 작업이 있다면 커밋을 분리하는 게 맞다.

chore 타입 커밋은 사용자에게 직접 보이는 변화가 없어서 우선순위에서 밀리기 쉽다. 근데 이런 작업을 꾸준히 하는 팀과 안 하는 팀의 차이는 6개월 뒤에 드러난다. 설정 값이 하나 드리프트되면 다음 정책 변경 때 또 하나가 불일치하고, 그게 누적되면 어느 순간 어떤 값이 진짜 기준인지 아무도 자신 있게 말 못하는 상태가 된다. 금융/결제 도메인에서는 숫자 하나가 틀리면 신뢰가 흔들릴 수 있어서, "대충 맞는 것 같다"로 넘어가면 나중에 반드시 다시 돌아온다. 작은 정정이라도 제때 하는 게 맞다.

댓글 0

첫 댓글 달아줘.