사이드프로젝트 slecs

결제 소스별 토글 제거로 채팅방 알림 콜백 응답 개선

목차

메신저 채팅방 기반 결제 플랫폼에서 사용자가 채팅방에 진입할 때 간편결제/계좌이체 소스별로 개별 토글이 켜져 있는지 확인하던 분기 로직을 v3.1에서 전부 들어냈다. 작업 자체는 크지 않았지만, 제거 전후의 맥락을 정리해두는 게 나중에 비슷한 결정을 내릴 때 도움이 될 것 같아서 남긴다.

왜 그 토글이 생겼고, 왜 문제가 됐나

소스별 토글은 전형적인 "세밀한 제어가 좋겠지" 판단에서 나온 기능이다. 간편결제 알림은 끄고 계좌이체 알림만 받고 싶은 사용자가 분명 있을 거라는 가정. 기획 단계에서는 타당해 보인다. 알림 선호는 개인마다 다르고, 결제 소스마다 알림의 성격이 다를 수 있으니까.

문제는 가정과 실제 사용 패턴의 괴리였다. 운영 데이터를 열어보니 소스별로 따로 끈 사용자가 전체의 0.4% 미만이었다. 사용률이 낮다는 것 자체가 제거의 충분조건은 아니다 - 소수를 위한 기능도 가치가 있을 수 있으니까. 진짜 문제는 그 0.4%조차 의도적으로 쓴 게 아니라는 점이었다. CS 인입 패턴을 보면 "왜 알림이 안 와요"가 반복됐고, 파고 들어가면 본인이 소스별 토글을 끈 채 잊어버린 케이스였다. 기능이 사용자를 돕는 게 아니라 혼란에 빠뜨리고 있었다.

여기에 기술적인 비용이 더해졌다. 채팅방 진입 시점에 소스별 토글 상태를 조회하는 로직이 결제대행사 콜백 응답 경로 위에 얹혀 있었다. 콜백은 보통 타임아웃 제약이 빡빡하다. 외부 PG사에서 쏘는 콜백이 처리되는 동안 DB 조회가 한 단계 더 들어가면, 요청이 몰리는 구간에서 RT가 눈에 띄게 늘어난다.

소스별 토글이 만들어낸 비용을 정리하면:

  • 사용자 혼란 유발 - 기억 못 하는 설정이 CS를 만들어냄
  • CS 인입 증가 및 반복 패턴
  • 콜백 처리 경로에 불필요한 DB 조회 추가
  • 코드 분기 복잡도 상승

이걸 다 합치면 그 기능이 제공하는 가치보다 운영 비용이 훨씬 컸다.

제거하면서 신경 쓴 것

기능을 제거할 때 가장 중요한 건 기존 사용자에게 어떤 영향이 가는가다. 소스별 토글을 쓰던 사용자가 - 아무리 적어도 - 기능 제거 후에 원치 않는 알림을 받게 되면 그건 잘못된 제거다.

항목 처리 방식
기존에 소스별 토글 끈 사용자 채팅방 단위 마스터 토글로 흡수, 알림 차단 상태 유지
알림 수신 동의 자체 건드리지 않음 - 법적 요건, 별도 관리
파트너 어드민 노출 영역 채팅방 마스터 토글만 남기고 소스별 입력 폼 숨김 처리
소스별 토글 DB 컬럼 즉시 드랍 안 하고 dead column으로 유지, 다음 릴리즈에서 제거 예정

마이그레이션에서 핵심은 "소스별 토글 중 하나라도 꺼져 있는 사용자"를 채팅방 마스터 토글 OFF로 보수적으로 흡수하는 것이었다. 어느 한 소스 알림이라도 원치 않았다면 전체를 끄는 게 의도에 더 가깝다는 판단이다.

컬럼을 즉시 드랍하지 않은 건 배포 직후 문제가 생겼을 때 롤백 경로를 열어두기 위해서다. 코드에서 참조가 완전히 사라진 걸 확인하고 나서 다음 릴리즈에 드랍 마이그레이션을 태운다. 배포와 동시에 컬럼을 날리면, 뭔가 터졌을 때 되돌리기가 훨씬 번거로워진다.

수신 처리 흐름이 달라진 걸 코드로 보면 이렇다:

// 변경 전
if (chatroom.notificationEnabled) {
    if (payment.source === 'simple' && user.simplePayToggle) {
        notify(...)
    } else if (payment.source === 'transfer' && user.transferToggle) {
        notify(...)
    }
}

// 변경 후
if (chatroom.notificationEnabled) {
    notify(...)
}

조건문이 절반 가까이 사라졌다. 채팅방 마스터 토글 하나만 보면 되니까 분기 자체가 필요 없어진다. 코드 리뷰나 테스트 커버리지도 한층 단순해지는 건 덤이다.

기능 제거를 결정하는 기준

"사용률이 낮으면 제거"는 너무 단순한 기준이다. 이번 케이스에서 제거 판단을 굳힌 건 여러 조건이 동시에 충족됐기 때문이다. 기능이 의도한 대로 쓰이지 않고 있었고, 기능의 존재 자체가 CS 비용을 만들어냈고, 기능이 성능 크리티컬 경로 위에 불필요한 레이턴시를 추가하고 있었다.

비슷한 상황에서 판단 근거로 쓸 수 있는 체크포인트:

  • 기능을 끈 사용자가 그 사실을 기억하고 있는가, 아니면 잊어버리는가
  • CS 인입 중 그 기능과 연관된 패턴이 반복되는가
  • 해당 기능이 성능 크리티컬 경로 위에 얹혀 있는가
  • 기능을 제거했을 때 흡수할 수 있는 더 단순한 대체 경로가 있는가

이번은 네 항목 전부 해당이었다. 배포 후 콜백 RT가 눈에 띄게 떨어졌고, CS에서 "토글 어디서 켜요" 패턴이 거의 사라졌다.

기능을 잘게 쪼개는 게 항상 사용자 경험을 좋게 만들지 않는다. 사람이 이해하고 기억할 수 있는 수준의 단순함이 더 나을 때가 분명히 있고, 이번이 딱 그 케이스였다. 들어내는 작업이 추가하는 작업보다 만족도가 높을 때가 가끔 있는데, 이번처럼 수치로 확인되면 더욱 그렇다.

댓글 0

첫 댓글 달아줘.