소리꽃 KeyBloom TIL 25
출시하고 나서 다듬는 동안 나온 것들. 기능을 얹는 비용, 네이티브 앱다움, 그리고 코드가 아닌 운영으로 푸는 문제.
기능의 비용
같은 결과를 내는 길이 이미 있는지부터 본다
라이브 연주에 두 가지를 넣었다. 왼쪽 Shift로 페달 밟기, 스페이스로 다음 큐 넘기기. 둘 다 새 기능처럼 들리는데 실제로는 거의 공짜였다.
페달은 이미 MIDI 페달을 받는 길이 있었다. 컴퓨터 키보드 입력을 그 길에 연결만 하면 오디오 쪽은 한 줄도 안 건드린다. 큐 넘기기도 큐를 고르는 기능이 이미 있어서, 다음 것을 골라 주는 짧은 함수 하나면 끝났다.
여기서 가져갈 건 견적을 보는 눈이다. 기능의 비용은 기능이 커 보이느냐가 아니라 “같은 결과를 내는 길이 이미 있느냐”로 갈린다. 화면에 버튼 하나 늘리는 일이 며칠 걸리기도 하고, 새 입력 방식을 통째로 추가하는 일이 반나절에 끝나기도 한다. 그러니 “이거 얼마나 걸려요”를 물을 때 같이 물어야 할 건 “지금 있는 것 중에 이거랑 같은 일 하는 게 있나요”다.
앱다움
네이티브 앱이 브라우저처럼 굴면 앱으로 안 보인다
이 앱의 네이티브 버전은 속을 웹 기술로 돌린다. 그래서 F5를 누르면 새로고침이 되고 F12를 누르면 개발자 도구가 열렸다. 사용자가 보기엔 앱인데 브라우저 습관이 그대로 먹으니 정체가 애매해진다. 실수로 F5를 눌러 작업이 날아갈 수도 있다.
막을 때 방향이 둘이었다. “우리가 만든 키만 허용”하는 허용 목록(whitelist)이거나, “브라우저 키만 차단”하는 차단 목록(denylist)이다. 앞쪽이 깔끔해 보이는데 위험하다 — 복사·붙여넣기·전체선택처럼 입력창에서 당연히 되어야 할 것까지 같이 막히고, 뭘 빠뜨렸는지는 사용자가 불편을 겪은 뒤에야 안다. 그래서 차단 목록 쪽으로 갔다. 빠뜨리면 브라우저 키 하나가 살아 있을 뿐, 앱이 망가지지는 않는다.
무언가를 막을 때는 “빠뜨렸을 때 어느 쪽이 덜 아픈가”로 방향을 고른다. 허용 목록은 빠뜨리면 정상 기능이 죽고, 차단 목록은 빠뜨려도 원래 상태로 남는다.
이 잠금은 프로덕션 빌드(사용자에게 나가는 출시본)에만 걸었다. 웹에서는 브라우저 키가 그대로 먹는 게 사용자 기대에 맞고, 개발 중에는 새로고침과 개발자 도구가 있어야 일이 된다. 같은 코드가 상황에 따라 다르게 굴어야 할 때가 있다.
업데이트라는 기능의 특이한 점
업데이트 관련 수정은 한 박자 늦게 효과가 난다
자동 업데이트에서 설치를 눌러도 한동안 화면에 아무 표시가 없어 멈춘 것처럼 보였다. 60MB를 받는 동안 아무 말이 없으니 그럴 만하다. 진행률을 띄우게 고쳤다.
여기 함정이 있다. 앞선 TIL 23의 확인창 버그와 같은 구조로, 업데이트를 실행하는 건 지금 깔려 있는 옛 버전이다. 새 버전에 진행률 표시를 넣어도, 옛 버전에서 새 버전으로 올라오는 그 업데이트에는 안 보인다. 이 버전을 받은 사람이 그다음 버전으로 올라갈 때부터 보인다.
업데이트 흐름을 손보는 일은 전부 이렇다. 고쳐 놓고 바로 확인할 수가 없고, 효과는 한 버전 뒤에 나타난다. 그래서 사용자 불만이 들어와도 “다음 업데이트부터 좋아진다”고 안내해야 하고, 업데이트 관련 개선은 미룰수록 사람들이 겪는 기간이 길어진다. 다른 기능보다 먼저 처리할 이유가 여기 있다.
코드로 풀 문제와 운영으로 풀 문제
언제 나가느냐는 배포 설정으로 통제한다
출시하고 나니 웹 버전이 문제였다. 개발 커밋이 올라갈 때마다 자동 배포돼서, 만들다 만 기능이 바로 공개 사이트에 올라갔다.
이걸 코드로 막을 방법을 찾을 뻔했는데, 배포 설정으로 푸는 게 맞았다. 공개 사이트가 바라보는 배포 브랜치를 따로 만들고, 개발은 다른 브랜치에서 한다. 웹을 갱신하고 싶을 때만 옮겨 붙인다. 코드는 한 줄도 안 바뀐다.
“만들다 만 게 나가면 안 된다”처럼 시점에 관한 문제는 대체로 코드가 아니라 운영으로 푼다. 코드로 풀려고 하면 조건 분기가 늘고, 그 분기 자체가 나중에 버그가 된다.
빌드가 외부 서비스에 기대면 조용히 실패한다
업데이트 내역을 판매 페이지에 보여주려고, 사이트를 빌드할 때마다 GitHub Releases API에 물어보게 했다. 편하긴 한데 그 API에는 IP당 시간당 횟수 제한이 있고, 빌드 서버는 여러 사용자와 IP를 나눠 쓴다.
실제로 뒤에 이게 터졌다. 재배포를 반복하다 제한에 걸렸고, 실패했다는 표시 없이 업데이트 내역 섹션만 조용히 사라졌다. 결국 내용을 저장소 안에 파일로 두고 그걸 읽는 방식으로 바꿨다.
배포 결과가 남의 서비스 상태에 달려 있으면, 같은 코드로 만들어도 결과가 매번 다를 수 있다. 그 실패가 에러도 없이 “그 부분만 안 보임”으로 나타나면 며칠씩 모른 채 지나간다. 빌드에 외부 호출을 넣기 전에 “이게 실패하면 티가 나는가”를 먼저 봐야 한다.
요약
- 기능 비용은 크기가 아니라 “같은 결과를 내는 길이 이미 있나”로 갈린다
- 막을 때는 빠뜨렸을 때 덜 아픈 방향으로 — 허용 목록은 빠뜨리면 정상 기능이 죽는다
- 업데이트 흐름 수정은 옛 버전이 실행하므로 한 버전 뒤에 효과가 난다 — 그래서 먼저 고쳐 둔다
- “언제 나가느냐”는 코드가 아니라 배포 설정으로 통제한다
- 빌드가 외부 서비스에 기대면 티도 안 나게 실패한다 — 실패가 보이는지부터 확인한다