본문 바로가기
C.W.K.
Stream
Lesson 06 of 06 · published

배송 — 케이블은 빌드 점검이지 배송이 아니야

~12 min · testflight, delivery, gates, reporting

Level 0호기심
0 XP0/80 lessons0/18 achievements
0/100 XP to next level100 XP to go0% complete

건너뛰게 되는 사실

이 집의 다른 클라이언트는 전부 파일을 복사해서 나가. 웹 UI 는 엔진이 서빙하는 빌드 디렉터리고, 맥 앱들은 서명된 번들을 자리에 복사하는 거고. iOS 는 마지막 단계가 내 것이 아닌 유일한 플랫폼이야. 빌드랑 기기 사이에 애플이 앉아 있고, 그게 "끝났다" 의 뜻을 바꿔.

가족 규칙은 한 줄이야. TestFlight 가 배송이고, 케이블 설치는 빌드 점검이야. 케이블 빌드는 일주일이면 만료되고, 케이블이랑 잠금 풀린 기기가 있어야 하고, 폰 딱 한 대에 닿아. 그건 이게 돌아가는지 알아보는 방법이지 누가 받는 방법이 아니야.

이게 적혀 있는 건 비싸게 배웠기 때문이야. 형제 앱에서, 집안에 이미 돌아가는 업로드 파이프라인이 생긴 지 열이틀 뒤에. 어떤 세션이 작업을 끝내고 아빠의 잠긴 폰에 옆으로 설치해놓고, 진짜 배송 경로는 나중에 할 일로 적어놨어. 아빠가 직접 짚어줘야 했고.

Principle: 출시의 마지막 단계가 남의 것일 때, 내 마지막 단계를 끝으로 치는 습관은 거의 못 참을 만큼 강해. 교정은 더 조심하는 게 아니라 단계들에 따로 이름을 붙여서 보고가 그걸 뭉갤 수 없게 만드는 거야.

사실이 넷, 배송은 마지막 하나뿐

계약서가 넷에 이름을 붙여놔서 상태 보고가 하나로 뭉칠 수 없게 돼 있어.

archive 를 내보내서 업로드했다 — 내 스크립트가 그렇게 말해. 애플이 처리를 끝냈다 — 스토어 콘솔이 그렇게 말하고, 한참 걸릴 수도 있어. 내부 그룹이 그 빌드를 가졌다 — 별개의 배정이고 별개의 화면이야. 기기에 설치됐다 — 기기가 그렇게 말하거나 테스터 행이 그렇게 말해.

서로 다른 참이 넷이야. 첫 번째만 참인데 "출시했다" 고 쓰는 보고는 일부러 거짓말하는 게 아니야. 네 단계짜리 과정을 한 단계짜리 압축하듯이 압축한 거지. 그래서 규칙은 넷 중 어느 게 참인지를 말하는 거야.

나중에 오는 메일 대신, 거부하는 게이트

업로드 스크립트는 대부분 거부야. 그리고 모든 거부에 같은 기원 설화가 있어. 안 그러면 애플이 업로드를 받아준 다음 몇 시간 뒤에 메일을 보내.

순서가 곧 설계야. 싼 거부는 비싼 일이 돌기 전에 전부 끝나고, 그 전부가 빌드 번호가 움직이기 전에 끝나. 맨 먼저 App Store Connect 키. 키가 없으면 화면이 잠겨 있을 때 업로드를 거부해. 잠긴 화면은 archive 에 필요한 keychain 세션을 죽이거든. 그다음 전용 시뮬레이터. 테스트가 남들 쓰는 시뮬레이터에 떨어지면 안 되니까. 그다음 앱의 입력이 커밋돼 있는지. 그래야 빌드 번호가 실제로 빌드되는 걸 가리켜. 공용 kit 소스가 깨끗한지도 봐. archive 가 그것도 같이 컴파일하니까. 포장된 renderer 가 있는지, 아이콘이 크기 맞고 불투명한지까지 보고 나서야 스위트가 돌고, 스위트가 통과해야 빌드 번호가 움직여.

archive 가 나오면 HEAD 를 다시 확인해 — 빌드하는 동안 형제 세션이 커밋했을 수 있으니까. 그다음 archive 자체를 들여다봐. 앱 아이콘 이름이 선언됐는지, 내장된 워치 앱 것도 그런지, 워치의 컴파일된 에셋 카탈로그가 있는지, complication 확장이 진짜로 거기 있는지.

마지막 묶음이 재밌는 쪽이야. 입력이 아니라 출력 에 대한 단언이거든 — 빌드는 성공했는데 산출물이 틀린 상황. 컴파일이 초록이라는 건 번들 내용물에 대한 증거가 아니야.

사실 1의 증거에 게이트가 없었어: export 단계 첫 버전은 빌드 도구를 필터에 파이프로 물리고 에러를 삼키는 절로 끝냈어. 셸 파이프라인은 마지막 명령의 상태를 보고하니까 strict 모드가 걸 데가 없었고 — 스크립트는 실제로 뭐가 올라갔든 말든 upload OK 줄을 찍었어. 그 줄이 바로 계약서가 네 사실 중 첫 번째의 증거로 지목한 거야. 그날 바로 고쳤어. 도구 자기 상태를 직접 읽고, 로그에서 실패 배너도 따로 찾아 — 논리적으로 실패해도 멀쩡히 종료하는 도구가 있으니까. 믿는 검사는 아는 검사여야 해.

프로젝트 파일은 생성물, 그리고 트리는 깨끗해야 해

보이는 것보다 중요한 작은 선택 둘.

Xcode 프로젝트는 평범한 텍스트 소스에서 생성해서 커밋해. IDE 에서 프로젝트를 손으로 고치는 건 팀 식별자나 서명 설정이 리뷰에서 아무도 안 읽는 파일에 들어앉는 길이고, 그러면 다음 기계는 미묘하게 다른 걸 빌드해. 텍스트 파일이 소스고, 프로젝트는 마침 추적되고 있을 뿐인 산출물이야.

그리고 깨끗한 트리 게이트는 위생 문제가 아니라 archive 가 실제로 뭘 컴파일하느냐의 문제야. 마지막 커밋이 아니라 작업 트리를 컴파일하거든. 더러운 파일 하나가 지금 출시하려는 빌드에 조용히 섞여 들어가. 공유 체크아웃에 형제 세션이 남기고 간 파일이어도 마찬가지고. 그러면 그 빌드는 거기 찍어둔 커밋으로 영영 재현이 안 돼.

이미 값을 치른 것들

앱마다 새로 만드는 건 하나도 없어. 개발자 팀 하나가 가족 전체를 지고, 그건 IDE 에서 클릭하는 게 아니라 각 프로젝트의 텍스트 소스에 이름으로 적혀. 새 앱한테 필요한 건 스토어 기록 하나, 그게 다야.

그리고 2026-09-14부터는 파이프라인 자체가 프로그램 하나야. 그날까지 가족은 손으로 키운 사본 여덟 개를 들고 있었고, 사본끼리 다른 줄이 제일 작은 사본의 줄 수보다 많았어. 그 차이는 설계 선택이 아니었어. 한 앱이 배운 가드를 다른 앱들이 아직 못 따라잡은 거였지. archive 둘은 빌드 도구의 상태를 필터 파이프 뒤에 삼켰고, 하나는 깨끗한 트리 검사도 HEAD 재확인도 없었고, 하나는 빌드 번호를 안 올렸고, 잠긴 화면을 거부하는 건 둘뿐이었어. 가드마다 한 번 배우고 덜 베껴진 거야. 이제 모든 가드가 모든 앱에서 한 순서로 돌아. 프로그램은 각 레포에 사본으로 들어가고 drift 테스트가 바이트 단위로 같음을 붙들어. 앱은 자기 사실만 옆에 둬 — 이름, 경로, 훅 몇 개. 그래서 출시가 빌드하는 기계에 형제 체크아웃이 있느냐 없느냐에 절대 기대지 않아.

vessels 트랙이 두뇌에 대해, frontend 트랙이 형제 앱에 대해 가르쳐온 그 본능을 빌드 파이프라인에 겨눈 거야. canonical 한 건 한 자리에 살고, 모든 소비자는 같기를 바라는 재구현이 아니라 같음이 증명된 사본을 들고 다녀.

Code

넷 중 어느 게 참인지 말해·text
1  archive 내보내서 업로드         <- 내 스크립트의 UPLOAD_OK 줄
2  애플이 처리 끝냄                <- 스토어 콘솔
3  내부 그룹이 빌드를 가짐         <- 별개의 배정 화면
4  기기에 설치됨                   <- 기기, 또는 테스터 행

배송은 4뿐이야.
1 끝내고 "출시했다" 는 네 단계짜리를
한 단계짜리처럼 보고하는 거야.
게이트, 도는 순서대로·text
비싼 일 전에 (그리고 빌드 번호가 움직이기 전에)
  auth        App Store Connect 키 — 없으면 잠긴 화면에서 업로드 거부
  simulator   전용 id, 남들 쓰는 것 절대 아님
  inputs      앱 입력이 커밋됨 — 빌드 번호가 실제 빌드를 가리킴
  kit         공용 kit 소스가 깨끗함 — archive 가 그것도 컴파일
  renderer    포장된 웹 셀이 있음
  icon        1024 px, 불투명

그다음
  suite       통과해야 함
  build no.   프로젝트 소스에서 올림
  archive     빌드 도구 자기 상태 + 남긴 로그 — 필터 파이프 절대 아님
  HEAD        빌드 도는 동안 안 움직였음
  contents    앱 + 워치 아이콘 이름, 워치 에셋 카탈로그, complication 확장
  export      도구 상태 그리고 실패 배너 — 서로 독립인 검사 둘

하나하나가 안 그랬으면 애플이 몇 시간 뒤 보냈을 메일이야.

Exercise

자기 출시 과정을 가져와서 마지막 단계를 그 안에 실제로 들어 있는 별개의 사실들로 쪼개봐. 그다음 가장 최근 출시를 어떻게 보고했는지 보고, 끝났다고 말한 그 순간에 그 사실들 중 어느 것에 대한 증거를 갖고 있었는지 물어봐.
Hint
산출물이 누군가에게 닿은 순간이 아니라 내 작업이 끝난 순간에 쓰인 보고가 신호야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.