메트로놈 Simple Metronome TIL 8
우리 화면 안에서 되는 것과 시스템이 대신 그려 주는 것은 다른 계약이다
메트로놈 알림에는 이미 재생·정지 버튼이 있었다. 그런데 잠금화면이나 시스템의 미디어 조작 패널, 블루투스 이어폰의 재생 버튼은 아무 반응이 없었다. 같은 재생·정지인데 되는 곳과 안 되는 곳이 갈렸다.
이유는 통로가 달라서였다. 알림 안의 버튼은 우리가 그린 것이라 우리 알림 안에서만 동작한다. 반면 잠금화면 컨트롤은 시스템이 그려 준다. 시스템이 그려 주려면 지금 무엇이 재생 중이고 어떤 조작을 받을 수 있는지를 시스템이 알아야 한다.
그 통로가 미디어 세션이다. 앱이 지금 무엇을 재생 중인지, 어떤 버튼을 허용하는지, 화면에 뭐라고 표시할지를 시스템에 등록해 두는 표준 창구다. 여기에 상태를 올리자 잠금화면과 미디어 패널에 컨트롤이 생겼고, 이어폰 버튼도 같은 창구로 들어왔다.
일반화하면 이렇다. 플랫폼이 제공하는 자리에 얹히고 싶으면 우리 쪽 기능이 잘 도는 것만으로는 안 되고, 그 자리가 요구하는 형식으로 상태를 알려 줘야 한다. 기능이 있느냐가 아니라 신고했느냐의 문제다.
시스템에 얹히면 신고 의무가 따라온다
화면만 얻은 게 아니었다. 백그라운드에서 소리를 내는 앱은 그 목적을 앱 설정에 명시해야 하고, 스토어 심사에도 왜 그 권한이 필요한지 따로 신고해야 한다. 안 하면 심사에서 막힌다.
플랫폼 기능을 쓰는 값은 코드 분량이 아니라 이런 절차로 돌아온다. 기능을 정할 때 구현 시간만 보지 말고 신고·심사에 드는 시간도 같이 잡아야 한다.
자산을 늘리는 대신 있는 것에서 파생시킨다
박자에 강약을 넣으려면 강박에 쓸 높은 음이 필요했다. 오디오 파일을 하나 더 만들어 넣는 게 첫 생각이었다.
대신 이미 있는 클릭 소리를 더 빠르게 다시 읽어 음을 올렸다. 같은 소리를 다른 속도로 다시 읽어 음높이를 바꾸는 것을 리샘플링이라고 한다. 속도를 올리면 음이 높아진다. 새 파일이 안 늘었고, 원래 클릭과 음색이 같으니 두 소리가 같은 악기처럼 들린다.
자산을 하나 늘리면 용량만 느는 게 아니라 관리할 것이 하나 는다. 나중에 클릭 소리를 바꾸면 강박 소리도 따로 다시 만들어야 했을 것이다. 파생시켜 두면 원본만 바꿔도 둘 다 따라온다.
한 요소에 여러 상태를 겹치려면 시각 축을 나눈다
박 표시 점 하나에 정보 셋을 담아야 했다. 지금 이 박이 울리고 있는지, 이 박이 강박으로 지정됐는지, 음소거됐는지다.
처음엔 강박 표시를 점 색으로 넣으려다 문제를 만났다. 재생 중 지금 울리는 박을 알리는 것도 색이라, 박이 울릴 때 강박 표시가 덮여 사라졌다. 한 축에 두 정보를 실으면 하나가 다른 하나를 지운다.
그래서 축을 셋으로 갈랐다.
- 지금 울리는 박은 색으로
- 강박 지정은 테두리 링으로
- 음소거는 흐리게(투명도)
셋이 서로 다른 축이라 동시에 표시해도 안 부딪힌다. 한 요소가 여러 상태를 나타내야 할 때는 상태 수만큼 시각 축을 확보하는 게 먼저다. 축이 모자라면 요소를 나누거나 정보를 줄여야 한다.
선택지가 셋이면 탭 순환으로 처리할 수 있다
강박·일반·음소거를 정하는 별도 설정 화면을 만들지 않았다. 박 점을 누를 때마다 셋이 돌아가게 했다.
이게 되는 조건이 있다. 현재 상태가 화면에 항상 보여야 한다는 것이다. 위에서 축을 나눠 둔 덕분에 지금 이 박이 어느 상태인지 점만 봐도 알 수 있어서, 순환식이 성립했다. 상태가 안 보이는 채로 순환만 시키면 사용자가 몇 번을 눌러야 할지 몰라 헤맨다.
설정은 그것이 의미를 갖는 조건과 함께 저장한다
4/4에서 첫 박과 셋째 박을 강박으로 정해 뒀다가 3/4로 바꾸면 그 설정을 그대로 쓸 수 없다. 박 수가 다르니 셋째 박이 아예 없을 수도 있다.
그래서 강박 패턴을 박 수별로 따로 저장했다. 4/4에서 정한 것과 3/4에서 정한 것이 각자 남고, 박자표를 오갈 때 그 박 수에 맞는 것을 불러온다.
어떤 설정은 특정 조건 아래서만 의미가 있다. 그런 설정을 조건과 분리해 하나로 저장하면, 조건이 바뀌는 순간 틀린 값이 되거나 조용히 사라진다. 조건을 키로 삼아 나눠 두면 둘 다 살아남는다.
데이터 출처가 늘 네트워크일 필요는 없다
앱 소개 페이지에 버전별 업데이트 내역을 붙이려 했다. 다른 앱은 공개 저장소의 릴리스 기록을 페이지를 만들 때 불러와 쓰는데, 이 앱의 코드 저장소는 비공개라 인증 없이는 못 읽는다.
공개 저장소를 새로 파거나 인증 토큰을 빌드 설정에 심는 건 이 크기의 문제에 비해 과했다. 대신 내역을 적은 파일을 소개 사이트 저장소 안에 두고, 페이지를 만들 때 그 파일을 읽게 했다. 외부 호출도 인증도 없어졌고, 새 버전이 나오면 파일에 한 덩이 이어붙이면 끝난다.
가져올 데이터의 출처를 정할 때 반사적으로 네트워크를 떠올리는데, 배포되는 단위 안에 함께 넣어 두면 호출·인증·실패 처리가 통째로 사라진다. 자주 안 바뀌고 우리가 직접 쓰는 데이터면 이쪽이 대개 낫다.
요약
- 우리 화면 안에서 되는 것과 시스템이 대신 그려 주는 것은 다른 계약이다. 플랫폼 자리에 얹히려면 그 자리가 요구하는 형식으로 상태를 알려야 한다.
- 플랫폼 기능을 쓰는 값은 구현 시간이 아니라 신고·심사 절차로 돌아온다. 일정에 같이 잡는다.
- 자산을 늘리기 전에 있는 자산에서 파생시킬 수 있는지 본다. 파생시키면 원본만 고쳐도 따라온다.
- 한 요소에 여러 상태를 겹치려면 상태 수만큼 시각 축을 확보한다. 같은 축에 두면 하나가 다른 하나를 지운다.
- 선택지가 셋이면 탭 순환으로 줄일 수 있다. 단 현재 상태가 항상 보여야 성립한다.
- 특정 조건에서만 의미 있는 설정은 그 조건을 키로 삼아 나눠 저장한다. 안 그러면 조건이 바뀔 때 틀린 값이 되거나 사라진다.
- 데이터 출처가 늘 네트워크일 필요는 없다. 배포 단위 안에 두면 호출·인증·실패 처리가 통째로 사라진다.