앱 심사와 단계적 출시, 되돌릴 수 없는 배포
웹은 이전 파일로 되돌리면 되지만, 사용자 기기에 설치된 앱은 거둬들일 수 없다.
스토어 심사와 단계적 출시가 어떻게 동작하는지, 그래서 어떤 값을 앱 대신 서버에 두는지 정리한다.
이 글의 목차앱의 코드는 사용자 기기에 있다6
웹 서비스만 만들다가 처음 앱을 내면 배포 화면부터 낯설다.
빌드를 올리고, 심사를 신청하고, 승인되면 언제 출시할지 고르는 칸이 나온다.
웹에서는 고친 파일을 서버에 올리면 다음 방문자부터 새 화면을 본다.
문제가 생겨도 이전 파일로 돌려놓으면 된다.
앱에서는 이 두 가지가 모두 다르게 움직인다.
앱의 코드는 사용자 기기에 있다
웹 페이지의 코드는 서버에 있다.
브라우저가 접속할 때마다 서버에서 받아 가므로, 서버의 파일을 바꾸면 사용자가 받는 코드도 바뀐다.
앱은 사용자가 스토어에서 내려받는 순간 기기에 설치되고, 그다음부터는 기기에 있는 코드가 돈다.
개발자가 서버에서 바꿀 수 있는 것은 앱이 요청했을 때 돌려주는 응답뿐이다.
앱을 기기에 넣어 주는 통로는 스토어다.
2008년 7월 iPhone용 App Store가 문을 열 때부터 업데이트가 나오면 스토어가 사용자에게 알려 주었지만, 받을지는 사용자의 몫이었다.
올린 빌드가 사용자에게 닿기까지
iPhone 앱은 Apple의 관리 사이트인 App Store Connect에 올린다.
이때 올리는 앱 파일을 빌드라고 한다.
App Store Connect는 사용자에게 보이는 버전 번호와 별도로, 빌드마다 붙는 빌드 문자열로 업로드를 구별한다.
그래서 같은 1.2.0 버전을 준비하면서 빌드를 여러 번 올릴 수 있다.
올린 빌드를 곧바로 출시하지 않아도 된다.
출시 전에 테스트용으로 먼저 배포할 수 있고, 이 기능이 TestFlight다.
Google Play에도 정식 출시 전에 테스트 참여자에게 먼저 배포하는 내부, 비공개, 공개 테스트 트랙이 있다.
빌드를 골라 제출하면 심사를 받는다.
Apple은 제출된 앱의 절반 이상을 보통 24시간 안에, 90%를 48시간 안에 심사한다고 밝힌다.
웹처럼 고치고 몇 분 만에 내보낼 수는 없다.
심사에서 자주 걸리는 항목은 앱 완성도다.
해결되지 않은 문제의 40% 넘게가 이 항목이다.
앱이 죽거나, 임시 문구가 남아 있거나, 필요한 정보가 빠진 경우다.
심각한 버그를 고친 버전이라면 빠른 심사(expedited review)를 요청할 수 있다.
빠른 심사도 순서를 당겨 줄 뿐 심사를 건너뛰게 해 주지는 않는다.
심사를 통과해도 바로 모두에게 반영되지는 않는다.
기기가 새 버전을 내려받아 설치해야 하고, 자동 업데이트를 꺼 둔 사용자는 직접 업데이트하기 전까지 옛 버전을 계속 쓴다.
설치된 앱은 거둬들일 수 없다
새 버전에 큰 버그가 있다면 어떻게 될까.
웹이라면 이전 파일로 돌아가면 되지만, 사용자 기기에 깔린 앱 파일을 서버에서 되돌리는 방법은 없다.
스토어가 주는 것은 퍼지는 속도를 조절하는 기능이다.
새 버전을 일부 사용자에게 먼저 보내고, 문제가 없으면 범위를 넓히는 방식을 단계적 출시라고 한다.
Google Play의 단계적 출시에서는 개발자가 출시 비율을 정하고, 그 비율은 직접 올려야 올라간다.
문제가 보이면 출시를 중단할 수 있다.
그런데 중단해도 추가 사용자에게 퍼지지 않을 뿐, 이미 받은 사용자는 그 버전에 그대로 남는다.
Apple의 단계적 출시는 자동 업데이트를 켠 사용자 가운데 무작위로 고른 일부에게 7일에 걸쳐 1%, 2%, 5%처럼 비율을 늘려 가며 보낸다.
출시를 멈춰 둘 수 있는 기간은 모두 합쳐 30일이다.
단계적 출시 중에도 누구든 App Store에서 그 버전을 직접 내려받을 수 있다.
단계적 출시가 늦추는 것은 자동 업데이트뿐이다.
예시 기기 10대 중 2대가 새 버전을 받은 상태다.
새 배포: 진행 중
옛 버전 설치 기기8
새 버전 설치 기기2
새 배포: 진행 중
옛 버전 설치 기기6
새 버전 설치 기기4
새 배포: 중단됨
옛 버전 설치 기기8
새 버전 설치 기기2
새 배포: 중단됨
옛 버전 설치 기기6
새 버전 설치 기기4
단계적 배포를 중단해도 이미 새 버전을 받은 기기는 그 버전을 계속 사용한다. 배포 중단은 설치 취소가 아니다.
두 기기는 새 버전, 여덟 기기는 옛 버전을 사용한다.
Google Play의 단계적 출시를 기기 10대로 단순화한 예시다. 실제 배포 비율·속도가 아니며, Apple의 수동 다운로드 조건은 별도다.
결국 문제를 고치려면 고친 빌드를 다시 심사받아 올리고, 사용자가 업데이트하기를 기다려야 한다.
그동안 문제 있는 버전은 이미 받은 기기에서 계속 돈다.
바꿀 일이 생길 값은 서버에 둔다
그래서 앱을 만들 때는 어떤 값을 앱 안에 넣고 어떤 값을 서버가 정하게 할지 계속 고르게 된다.
화면 문구, 기능을 켤지 말지, 어느 서버 주소를 부를지, 응답을 몇 초까지 기다릴지 같은 값들이다.
앱 안에 넣으면 코드는 단순하다.
대신 바꾸려면 새 빌드와 심사를 거쳐야 한다.
서버가 정하게 하면 앱이 실행될 때 서버에 값을 물어봐야 해서 복잡해진다.
그 대신 문제가 생겼을 때 서버 설정만 바꿔 바로 끌 수 있다.
기능을 켜고 끄는 데 쓰는 이런 값을 기능 플래그(feature flag)라고 한다.
Firebase Remote Config 같은 서비스를 쓰면 앱 업데이트 없이 앱의 동작과 모양을 바꿀 수 있고, 설정 값을 기능 플래그로 쓸 수도 있다.
Remote Config는 앱 안에 기본값을 넣어 두고 서버에서 받은 값으로 덮어쓰는 방식이다.
네트워크가 끊겨도 앱은 기본값으로 동작해야 하므로, 서버가 정하는 값에도 앱 안의 기본값은 필요하다.
업데이트하지 않은 앱도 서버를 계속 부른다
새 앱과 옛 앱은 같은 서버를 동시에 부른다.
옛 버전이 오래 남을수록 서버도 그만큼 오래 옛 앱의 요청을 받아 줘야 한다.
응답에서 필드를 지우거나 이름을 바꾸면 새 앱은 잘 돌아도 옛 앱은 깨질 수 있다.
그래서 응답 형식은 필드를 더하는 쪽으로 바꾸고, 앱은 모르는 필드를 무시하게 만들어 둔다.
웹에서도 이미 열려 있는 탭이나 브라우저 캐시에 옛 코드가 한동안 남는다.
앱은 그 기간이 사용자가 업데이트할 때까지로 훨씬 길다.
| 비교할 것 | 웹 배포 | 앱 배포 |
|---|---|---|
| 새 코드가 닿는 방식 | 서버에 배포하면 바로 바뀜 | 심사와 기기 업데이트를 거침 |
| 되돌리기 | 이전 파일로 다시 배포 | 설치된 앱은 회수할 수 없음 |
| 옛 버전이 남는 곳 | 열린 탭과 캐시에 잠시 | 업데이트 전까지 사용자 기기에 |
필드를 지우거나 뜻을 바꿔야 할 때는 지원을 끊을 옛 버전부터 정한다.
그 버전 사용자에게 업데이트를 요구할 방법도 있어야 한다.
Android의 인앱 업데이트에는 즉시 업데이트 흐름이 있다.
사용자가 업데이트하고 앱을 다시 시작해야 계속 쓸 수 있게 하는 화면이다.
플랫폼이 이런 기능을 주지 않는다면, 앱이 서버에서 최소 지원 버전을 받아 와 직접 업데이트를 안내하게 만든다.
첫 출시 전에 넣어 둘 것
여기서 순서 문제가 하나 생긴다.
업데이트 안내든 기능 플래그든, 서버에 묻는 코드가 그 앱 안에 이미 들어 있어야 동작한다.
그런 코드 없이 나간 버전은 나중에 바꿀 길이 없다.
업데이트를 안내하는 코드마저 업데이트를 거쳐야 들어간다.
게다가 Google Play의 단계적 출시는 업데이트에만 쓸 수 있다.
Apple도 버전 업데이트를 낼 때 고르는 선택지로 두고 있어서, 첫 버전은 처음부터 모든 사용자에게 한 번에 나간다.
그래서 첫 출시 전에 최소 지원 버전 확인과, 위험한 기능을 끌 수 있는 스위치 정도는 넣어 두는 편이 안전하다.
새 기능은 그다음 업데이트부터 단계적 출시로 좁게 시작해서, 오류 보고와 지표를 보며 범위를 넓혀 간다.