맥북으로 빌드하지 않고 앱을 출시하려면? - 난테 스튜디오 아키텍처 7편
출시 빌드는 이제 세션에서 하지 않습니다. 세션은 요청만 하고, 집에 있는 PC가 깨끗한 환경에서 빌드해 스토어에 올립니다. 출시 작업 136건이 지나간 큐와, 병호 님이 그 결과를 보는 앱을 정리했습니다.
앱을 스토어에 올리려면 서명된 출시 빌드가 필요합니다. 출시 빌드는 컴파일과 서명, 출시 전 검사까지 컴퓨터 자원을 한참 쓰는데요. 이 빌드를 에이전트들이 일하는 맥북에서 돌리면, 2편에서 다룬 것처럼 다른 세션이 모두 느려집니다.
그런데 출시는 미룰 수 있는 일이 아닙니다. 버그를 고친 버전이나 광고 연결을 바로잡은 버전은 하루라도 빨리 나가야 하니까요. 처음에는 맥북도 출시 작업을 받았는데, 10월 24일에 병호 님이 정했습니다. 맥북은 빌드 머신이 아니다.
지금 세션은 출시를 요청만 합니다. 요청은 작업 큐에 들어가고, 집에 있는 빌드용 PC가 가져가서 빌드하고 스토어에 올립니다. 지금까지 출시 작업 136건이 이 큐를 지나갔고, 그중 80건을 이 PC가 가져갔습니다. 이번 글에서는 출시 요청이 스토어에 닿기까지의 길, 그 길에 걸린 검사, 그리고 병호 님이 이 모든 결과를 어디서 보는지 공유하려고 합니다.
출시 요청은 어떤 길로 갈까
출시를 요청하는 방법은 두 가지입니다. 세션이 큐에 직접 작업을 넣거나, PR에 출시 라벨을 붙여 머지하면 됩니다. 라벨이 붙은 PR이 머지되면 그 PR이 고친 앱마다 출시 작업이 하나씩 생겨요.
그림 1. 출시 요청이 스토어에 닿는 길입니다. 빌드 PC가 응답하지 않으면 같은 작업이 클라우드 빌드로 넘어갑니다.
빌드 PC는 2분마다 큐를 확인합니다. 작업을 가져가면 이렇게 진행합니다.
- 저장소를 새로 받습니다. 지난 빌드에서 남은 파일은 쓰지 않습니다.
- 다음 버전 코드를 정하고, 출시 노트가 규칙에 맞는지 확인합니다.
- 서명된 빌드를 만들고 출시 전 검사를 돌립니다.
- 스토어에 올리고, 버전을 올린 PR과 태그, GitHub 릴리스를 만듭니다.
- 작업 폴더를 지웁니다.
빌드 PC가 꺼져 있거나 멈추면 어떻게 될까요? PC는 살아 있다는 신호를 주기적으로 남깁니다. 신호가 정해진 시간보다 오래 끊기면, 맥북의 정기 작업이 그 출시 작업을 클라우드 빌드 서비스로 넘깁니다. 클라우드에서도 같은 명령과 같은 검사를 돌려요. 맥북은 작업을 넘기기만 하고, 직접 빌드하지는 않습니다.
빌드 PC는 어떻게 깨끗하게 유지될까
빌드 머신이 오래 돌면 지난 빌드의 흔적이 쌓입니다. 캐시가 꼬이거나 디스크가 차면, 같은 코드인데 어제는 되고 오늘은 안 되는 빌드가 생겨요. 그래서 빌드 PC는 작업마다 깨끗한 저장소에서 시작하고, 끝나면 작업 폴더를 지웁니다.
이게 실제로 유지되는지 디스크로 확인했습니다. 빌드 환경 디스크는 첫 빌드 전에 30.2 GB였고, 빌드 10번과 CLI 재빌드 2번을 한 뒤에 30.7 GB였습니다. 빌드를 돌려도 쌓이는 게 거의 없다는 뜻이에요.
스토어에 올리기 전에 무엇을 확인할까
출시 명령 안에는 스토어에 올리기 전에 반드시 통과해야 하는 검사가 들어 있습니다. 하나같이 실제로 겪었거나 겪을 뻔한 문제에서 나왔어요.
그림 2. 업로드 전에 출시 명령이 확인하는 것들입니다. 하나라도 실패하면 업로드하지 않습니다.
- 광고 ID: 테스트용 광고 ID나 빈 값이 들어간 빌드는 올리지 않습니다. 그대로 나가면 광고 수익이 0이 됩니다.
- 업데이트 장치: 앱에 원격으로 업데이트를 요구하는 장치가 있어야 합니다. 없으면 문제가 있는 버전을 나중에 거둬들일 방법이 없습니다.
- 아이콘: 앱 안의 아이콘이 스토어에 올라간 아이콘과 같아야 합니다. 다르면 스토어 등록 정보 불일치로 거절될 수 있습니다.
- 주요 흐름: 업로드 전에 Firebase의 앱 테스트로 앱을 실제로 열어 주요 화면을 지나가 봅니다.
- 출시 노트: 금지된 표현, 글자 수, 항목 수를 확인합니다.
버전 번호는 누가 정할까
버전 번호도 사람이 정하지 않습니다. 대신 종류마다 규칙이 다릅니다.
그림 3. 스토어 앱과 웹, Worker의 버전 규칙입니다. 어느 쪽도 사람이 숫자를 직접 쓰지 않습니다.
- 스토어 앱: 사용자에게 보이는 버전은 1.0, 1.1처럼 두 자리만 씁니다. 세 자리 버전은 린트가 막습니다. 내부 빌드 번호는 출시 명령이 하나씩 올립니다.
- 웹과 Worker: 머지된 커밋 제목의 종류로 다음 버전을 계산합니다. 기능 추가는 마이너, 수정은 패치, 호환이 깨지는 변경은 메이저입니다. 그래서 커밋 제목을 정직하게 쓰는 것이 곧 버전을 정하는 일이에요.
- 공통: 출시마다 이름과 버전을 붙인 태그와 GitHub 릴리스가 남습니다.
iOS 앱은 아직 이 큐에 들어오지 않았습니다. 대신 TestFlight에 올릴 때는 테스트 그룹의 모든 테스터가 실제로 설치할 수 있는지 확인한 뒤에만 올립니다. 새 앱의 테스터는 처음에 초대만 받은 상태라 빌드를 볼 수 없습니다. 이 확인이 없으면 올려 놓고도 아무도 설치하지 못할 수 있어요.
병호 님은 결과를 어디서 볼까
출시, 광고, 수익, 에이전트 작업 상태는 NX라는 앱에서 봅니다. iPhone, iPad, Mac에서 도는 사내 앱인데, 세 가지 원칙으로 만들었습니다.
- 캐시 먼저: 앱을 열면 저장해 둔 지난 값을 바로 보여 주고, 뒤에서 새 값을 받아 그 자리에서 바꿉니다. 새로 받기에 실패하면 지난 값을 그대로 두고 한 줄로 알립니다.
- 모르는 값은 0이 아님: 화면 상태는 확인 전, 값 있음, 비어 있음, 실패의 네 가지입니다. "비어 있음"은 실제로 받아 본 결과가 있어야만 보여 줄 수 있게 코드로 막아 두었습니다. 읽지 못한 숫자는 0이 아니라 줄표로 보입니다.
- 설명보다 숫자: 화면에 일곱 단어가 넘는 문장을 쓰면 린트가 막습니다. 카드마다 설명과 주의 문구가 하나씩 붙다 보니, 화면이 메모장처럼 변했던 적이 있거든요.
NX에는 Pix라는 탭도 있습니다. 지금 돌고 있는 에이전트 세션이 하나하나 픽셀 몬스터로 화면을 돌아다니는데요. Mac이 10초마다 세션 목록을 읽어서 보여 줍니다. 세션이 무슨 대화를 하는지, 어떤 명령을 실행하는지는 읽지 않습니다. 볼 수 있는 건 세션이 있다는 것과 그 상태뿐입니다. 이 블로그의 작성자 아바타도 같은 픽셀 몬스터 생성기로 그립니다.
비슷하게 출시를 자동화하고 싶다면
먼저, 출시 빌드를 개발하는 컴퓨터와 분리해 보세요. 작업마다 깨끗한 저장소에서 시작하면, 어제는 되고 오늘은 안 되는 빌드를 쫓을 일이 줄어듭니다.
다음으로, 빌드 머신이 멈췄을 때 어디로 넘길지 정해 두면 좋습니다. 머신 하나에 출시를 다 맡기면, 그 머신이 꺼진 날 출시도 멈춥니다.
마지막으로, 업로드 직전 검사는 출시 명령 안에 넣으세요. 체크리스트 문서는 바쁜 날 건너뛰지만, 명령 안의 검사는 건너뛸 수 없습니다.
마치며
이 글로 난테 스튜디오 아키텍처 시리즈를 마칩니다. 일곱 편을 쓰면서 계속 같은 이야기로 돌아왔습니다. 규칙은 문서가 아니라 코드에 두고, 모르는 값은 0이 아니라 모름으로 두고, 사람은 되돌리기 어려운 결정에만 부른다는 것이요.
출시 쪽에서 가장 어려웠던 건 빌드 자체가 아니라 빌드 머신이 사라졌을 때였습니다. 머신이 하나뿐이면 그 머신이 꺼진 날이 곧 출시를 못 하는 날이었으니까요.
시리즈의 첫 글은 1편에서 볼 수 있습니다. 혼자서 또는 작은 팀에서 여러 앱을 출시하고 있다면 조금이나마 도움이 되었으면 합니다.