자동화 파이프라인8 분 읽기

제 수정이 다른 앱에 붙을 뻔했습니다. 번들 이름 하나가 겹쳐서

앱 여러 개에 같은 스토어 문구 수정을 자동으로 적용하는 파이프라인에서 한 앱이 세 번 연달아 실패했습니다. 원인은 수정 파일을 찾는 코드가 앱 이름을 부분 문자열로 검색하는 것이었고, 옛 이름이 남은 번들 식별자가 다른 앱과 겹쳤습니다.

#automation#gotchas#tooling#debugging
검색창에 B를 입력한 그림. 결과 목록에 앱 두 개가 있는데 첫째는 이름이 A이지만 번들 식별자에 B가 섞여 있어 빨간 밑줄이 그어져 있고, 둘째가 진짜 대상인 B. 화살표가 잘못된 쪽으로 먼저 향하고 X 표시.
매니페스트 키, 번들 ID, 화면에 보이는 이름, 파일 이름은 넷 다 다를 수 있습니다.

당신의 자동화는 대상을 무엇으로 식별합니까? 화면에 보이는 이름입니까, 아니면 진짜 키입니까?

저는 편의를 위해 부분 문자열 검색을 넣었습니다. 그래서 한 앱에 붙어야 할 수정이 다른 앱에 통째로 적용됐습니다.

상황

앱 여러 개에 같은 종류의 스토어 문구 수정을 자동으로 적용하는 파이프라인을 돌렸습니다. 앱 이름을 인자로 주면 그 이름으로 수정 파일을 찾아서 붙이는 구조였습니다.

한 앱에서 제출이 세 번 연달아 실패했습니다.

수정 파일을 찾는 코드가 부분 문자열로 검색하고 있었습니다

이게 왜 문제가 됐는지에 우연이 하나 끼어 있습니다.

두 앱 중 하나는 예전에 다른 이름으로 시작했던 흔적이 번들 식별자에 남아 있었습니다. 실제 이름은 A 인데 번들에는 옛 이름 B 가 들어 있었던 겁니다. 그리고 다른 앱의 진짜 이름이 정확히 B 였습니다.

B 를 대상으로 검색하면, 코드는 "이름에 B 가 들어가는 앱"을 찾습니다. 그런데 앱 A 의 번들에도 B 가 들어 있으니 A 가 먼저 걸렸습니다.

로케일이 두 개뿐인 작은 앱에, 서른일곱 개 로케일짜리 수정이 통째로 적용됐습니다.

왜 라이브에 안 나갔나

다행히 그 자리에서 죽었습니다. 다음 단계가 "이 버전에 없는 로케일이 있으면 멈춘다" 는 검사였는데, 서른다섯 개 로케일이 그 버전에 없어서 걸린 겁니다.

여기가 이 글의 핵심입니다. 로케일 수가 우연히 맞았다면, 조용히 남의 앱 문구가 라이브에 나갔을 겁니다.

멈춘 건 대상 식별 검사가 아니라 전혀 다른 목적의 검사였습니다. 안전 장치가 제 역할을 한 게 아니라, 옆에 있던 검사가 우연히 걸린 겁니다.

같은 배치의 다른 실패

같은 배치에서 다른 앱은 반대 이유로 죽었습니다. 제출 스크립트가 아예 없었습니다.

자동화 목록에 있는 이름과 실제 스크립트 파일 이름의 철자가 한 글자 달랐습니다. 이쪽은 조용히 잘못되지 않고 그냥 없어서 죽었으니 오히려 나은 실패입니다.

고친 형태

# 틀림 — 부분 문자열은 우연한 겹침을 놓치지 않는다
if 검색어 in 번들이름 or 검색어 in 표시이름:
    return 이_앱
 
# 맞음 — 번들 ID 정확 일치, 중복은 추측하지 말고 거부
후보 = [앱 forin 전체 if 앱.번들 == 정확한_번들]
if len(후보) != 1:
    raise Error(f"여러 앱에 걸린다: {[a.이름 for a in 후보]}")

중복일 때 첫 번째를 고르지 않고 죽는 것이 핵심입니다. 부분 검색의 진짜 문제는 겹침이 아니라, 겹쳤을 때 말없이 하나를 골랐다는 것입니다.

같은 배치에서 배포 스크립트가 리포 값으로 라이브를 덮으려 한 일도 나왔는데, 뿌리가 같습니다. 표시용 값으로 대상을 특정하면, 그 값이 바뀌거나 겹치는 날 조용히 틀립니다.

배치 전에 훑는 검사

그리고 배치를 돌리기 전에, 전체 대상에 대해 세 가지를 미리 훑는 검사를 넣었습니다.

  1. 수정 파일을 찾을 수 있는가
  2. 제출 스크립트가 있는가
  3. 앱 ID를 얻을 수 있는가

이번엔 이걸로 사고 전에 11건의 배선 결함을 먼저 뽑았습니다. 46개 대상 중 11건이면 4분의 1 가까이입니다. 그걸 실행 중에 하나씩 만났으면 배치가 중간에 계속 멈췄을 겁니다.

핵심 교훈

매니페스트의 키, 번들 ID, 화면에 보이는 이름, 파일 이름은 넷 다 다를 수 있습니다.

하나로 다른 하나를 추론하면 이런 일이 생깁니다. 그리고 앱이 많아질수록 겹칠 확률이 올라갑니다 — 46개면 이미 겹칩니다.

자가진단 3줄

  1. 당신의 자동화가 대상을 부분 문자열로 찾습니까? in 하나가 전부입니다. grep 해 보세요.
  2. 후보가 둘 이상일 때 무엇을 합니까? 첫 번째를 고르면 그 자동화는 언젠가 조용히 틀립니다. 죽는 게 맞습니다.
  3. 배치 실행 전에 대상 전수를 훑는 검사가 있습니까? 실행 중에 만나는 결함은 이미 절반이 적용된 상태입니다.

솔직한 부분

이 결함을 제가 만든 자동화가 만들었습니다. 편의를 위해 부분 검색을 넣었는데, 넓은 이름 목록에서 겹침을 예상하지 못했습니다. 남의 코드가 아니라 제 코드입니다.

이번엔 우연히 안전했습니다. 로케일 수가 안 맞아서 멈췄을 뿐, 검사 순서가 달랐다면 못 잡았습니다. "운이 좋아서 안전했다"는 "설계가 안전하다"와 다릅니다. 이 글의 결론이 "가드를 하나 더 넣었다"인 이유가 그것입니다.

그리고 전체 46개 대상 중 이 조합을 어떻게 미리 찾았느냐면, 사고가 난 뒤에 전수 검사를 돌려서입니다. 사고 전에 미리 걸러내는 검사는 이번에 처음 넣었습니다. 즉 이 검사는 사고의 산물이지 설계의 산물이 아닙니다.

여러 대상에 같은 수정을 뿌리는 자동화가 있으시면, 대상 식별 코드에서 in 을 한 번 grep 해 보세요. 거기 있으면 겹치는 날이 옵니다.

관련 글