소리꽃 KeyBloom TIL 17
유료 기능을 붙이기 전에 뼈대부터 세웠다. 무엇을 잠글지가 아니라, 잠금을 어떻게 만들어 둬야 나중에 자유로운지에 관한 것들.
나중에 바꿀 것을 빌드에 박지 않는다
잠금은 값이 아니라 판단이어야 켤 수 있다
무료 제한을 “이 빌드는 무료판”이라는 값으로 박아 두면, 산 사람에게만 풀어 줄 방법이 없다. 그 값은 만들 때 정해져서 실행 중에 안 바뀐다.
그래서 값 대신 “지금 이 사람이 유료인가”를 그때그때 묻는 방식으로 바꿨다. 잠긴 곳들이 전부 그 하나를 본다. 결제가 확인되는 순간 앱을 다시 켤 필요 없이 다 풀린다.
여기서 가져갈 건 넓다. 나중에 상황에 따라 달라질 것은 만들 때 정하면 안 된다. 무료·유료뿐 아니라 지역, 기기, 실험 그룹 같은 것도 마찬가지다. 정하는 시점을 미룰수록 나중에 손댈 곳이 준다.
한 가지 더 얻은 게 있다. 판단이 한 곳에 모이니 “무엇이 유료인가”를 코드에서 한눈에 볼 수 있다. 흩어져 있으면 정책을 바꿀 때 빠뜨린 곳이 반드시 생긴다.
앱 밖에 둬야 하는 것
검증에 쓰는 비밀은 사용자 손에 두지 않는다
라이선스가 진짜인지 결제사(Creem)에 물으려면 API 키가 필요하다. 이걸 앱에 넣으면 앱을 뜯어본 사람이 그 키로 “유효하다”는 답을 스스로 만들 수 있다. 검증이 검증이 아니게 된다.
그래서 키는 우리 서버 — Cloudflare Worker로 띄운 프록시(앱 대신 물어봐 주는 중계 서버) — 에 두고, 앱은 그 프록시에만 묻게 했다. 프록시가 대신 결제사에 확인하고 결과만 돌려준다.
설치해서 쓰는 앱은 통째로 사용자 손에 있다. 안에 넣은 것은 언젠가 열린다고 가정해야 한다. 판단을 앱이 하되 판단의 근거가 되는 비밀은 밖에 둔다는 게 원칙이다.
남에게 의존하는 자리
결제사는 갈아끼울 수 있어야 한다
결제 처리를 맡긴 곳은 아직 신생 업체다. 서비스가 좋아서 골랐지만, 아직 규모가 작아 인수나 정책 변경 같은 일이 생길 수 있다. 그런 일이 생기면 결제가 하루아침에 멈출 수도 있다.
그래서 라이선스 확인 부분을 한 겹 감쌌다. 활성화·확인·해제 같은 동작만 규격으로 두고 특정 업체에 맞춘 부분은 그 뒤에 뒀다. 나중에 다른 곳으로 옮겨도 앱 쪽 잠금 코드는 안 건드려도 된다.
이건 값싼 보험이다. 지금 드는 비용은 한 겹 더 두는 수고뿐인데, 안 해 두면 나중에 제품 전체를 뒤져야 한다. 남의 서비스에 매출이 걸린 자리는 특히 이 보험이 싸다.
함께 알아 둔 것 — 이런 결제 대행 중에는 자기가 판매자로 나서서 나라별 세금까지 대신 처리해 주는 형태가 있다(MoR — Merchant of Record). 혼자 해외에 파는 경우 세금 처리를 직접 안 해도 된다는 게 크다. 수수료가 조금 비싸도 이 형태를 고르는 이유다.
요약
- 나중에 상황에 따라 달라질 것은 만들 때 정하지 않는다 — 유료 여부도 지역도 실험 그룹도
- 잠금 판단을 한 곳에 모으면 정책을 바꿀 때 빠뜨리는 곳이 안 생긴다
- 설치형 앱 안에 넣은 것은 언젠가 열린다. 판단은 앱이 하되 비밀은 밖에 둔다
- 매출이 남의 서비스에 걸린 자리는 갈아끼울 수 있게 한 겹 감싸 둔다 — 값싼 보험이다