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

한도를 바이트로 쟀더니, 검색 노출 면적의 3분의 1만 쓰고 있었습니다

앱 46개의 스토어 키워드 필드를 전수 감사했습니다. 비라틴 로케일이 유독 짧길래 번역가가 짧게 쓴 줄 알았는데, 제 검증기가 100자 한도를 100바이트로 재고 있었습니다. 라이브 678슬롯 중 100바이트를 넘는 건 216건, 100자를 넘는 건 0건이었습니다.

#aso#i18n#gotchas#automation#metrics
같은 100 눈금에 놓인 가로 막대 두 개. 위 막대는 라틴 문자열이 눈금 끝까지 가득 차 96자. 아래 막대는 비라틴 문자열인데 3분의 1 지점에서 잘려 33자, 잘린 자리에 '100바이트에서 잘림' 라벨이 붙고 그 뒤는 회색 빈 칸.
한도의 단위를 확인하지 않으면, 검증기가 제품의 상한이 됩니다.

당신의 검증기는 한도를 넘는 것만 막습니까, 아니면 한도에 얼마나 못 미치는지도 셉니까?

저는 앞의 것만 하고 있었습니다. 몇 달 동안 초록불이었고, 그 초록불이 제 앱 46개의 검색 노출 면적을 3분의 1로 묶어 두고 있었습니다.

하려던 일

스토어에는 검색어를 직접 넣는 필드가 하나 있습니다. 한도는 100입니다. 앱 46개의 검색 노출을 늘려 보려고, 우선 그 필드를 얼마나 채우고 있는지부터 세기로 했습니다.

로케일 슬롯 678개를 세니 평균 채움이 72였습니다. 그런데 분포가 이상했습니다.

en-*    96
ko      53
ja      52
zh-Hans 44

영어권만 한도에 붙어 있고 나머지는 절반쯤에서 멈춰 있었습니다. 처음엔 자연스럽게 읽었습니다 — 번역가가 짧게 쓴 거겠지, 그 언어는 낱말이 짧으니까.

당신이라면 이 분포를 어떻게 읽으시겠습니까

여기서 갈림길이 있습니다. "번역가가 짧게 썼다"로 읽으면 다음 작업은 낱말을 더 채워 넣는 일입니다. 46개 앱 × 여러 로케일에 손번역을 더 붓는 일이 됩니다.

저는 다른 걸 먼저 물었습니다. 왜 하필 비라틴만 짧은가. 언어가 짧은 거라면 한국어와 일본어와 중국어가 비슷하게 짧은 건 설명이 되는데, 그 셋이 거의 정확히 3분의 1 근처에 몰려 있는 건 언어로 설명이 안 됩니다.

진짜 원인

한도는 100자인데, 제 검증기가 100바이트로 재고 있었습니다.

라틴 문자는 UTF-8에서 한 글자가 1바이트입니다. 그래서 영어권은 아무 문제가 없었습니다. 한글·일본어·중국어는 한 글자가 3바이트입니다. 검증기가 "100바이트 초과"에서 자르면 비라틴 로케일은 실한도의 3분의 1 지점에서 잘립니다. 33자쯤에서 더 못 넣게 되니, 사람이 그 앞에서 멈춘 것처럼 보였던 겁니다.

증거는 깔끔했습니다.

  • 라이브 678슬롯 중 100바이트를 넘는 것: 216건
  • 100를 넘는 것: 0건

아무도 진짜 한도를 넘긴 적이 없습니다. 216개 슬롯은 존재하지 않는 한도에 막혀 있었습니다.

비어 있던 총량은 23,089자였습니다. 이건 번역 비용이 드는 면적이 아닙니다. 이미 그 언어로 서비스하는 앱들이고, 그 시장에서 검색될 낱말을 넣을 자리가 비어 있었을 뿐입니다.

고친 형태

# 틀림 — 한도의 단위를 바꿔 버린다
if len(keywords.encode("utf-8")) > 100:
    keywords = truncate(keywords)
 
# 맞음
if len(keywords) > 100:
    raise ValueError("키워드 한도 초과")

그리고 한 줄을 더 넣었습니다. 이게 실제 교훈입니다.

남은_면적 = max(0, 100 - len(keywords))

넘치는 것만 막는 검사기는 비어 있는 것을 영원히 못 봅니다. 통과 신호는 "한도를 지켰다"만 말해 주고, "한도의 3분의 1에서 멈췄다"는 절대 말해 주지 않습니다.

감사 결과

항목
로케일 슬롯 678
평균 채움(전) 72자
평균 채움(후) 90자
100바이트 초과 216건
100자 초과 0건
비어 있던 총량 23,089자

같은 감사에서 결함 넷을 더 잡았습니다. 전각 쉼표로 낱말을 구분해 문자열 전체가 한 단어로 색인되던 슬롯, 제3자 상표가 들어간 슬롯(정책 위반), 포지셔닝이 바뀌었는데 옛 낱말이 남아 새 낱말을 밀어내던 슬롯, 그리고 남의 앱 키워드가 들어간 슬롯.

이 감사는 세 층으로 이어졌습니다. 키워드 다음은 본문이었고(스토어 설명에서 아포스트로피까지 빠져 있었습니다), 그다음은 부제였습니다(부제 36칸이 영어 원문 그대로였습니다). 세 필드 다 같은 종류의 구멍이 있었습니다.

자가진단 3줄

  1. 당신의 길이 검사는 무슨 단위로 셉니까? len(s)인지 len(s.encode())인지 지금 열어서 보세요. 다국어를 다루는데 후자면 비라틴 사용자만 조용히 손해를 보고 있습니다.
  2. 검사기가 "미달"을 셉니까? 상한만 보는 검사기는 하한이 0인 것과 같습니다. 채움률을 한 줄 찍는 것만으로 이런 게 드러납니다.
  3. "통과했다"를 몇 달째 안 의심하고 있습니까? 통과하는 검사기는 질문을 멈추게 합니다. 그게 이 버그가 오래 산 진짜 이유입니다.

솔직한 부분

채움을 늘린 것이 실제로 노출을 늘렸는지는 아직 모릅니다. 스토어 검색 순위는 즉시 반영되지 않고, 이 배치가 심사를 통과한 뒤 최소 2주는 지나야 비교할 수 있습니다. 지금 말할 수 있는 건 면적이 늘었다는 것뿐입니다.

채운 낱말이 좋은 낱말인지도 별개 문제입니다. 자리를 채우는 것과 맞는 검색어를 고르는 것은 다른 일이고, 이 글은 앞의 것만 다룹니다. 그리고 총량 숫자에 속기 쉽다는 것도 같은 주에 배웠습니다 — 51만 자가 비어 있다고 적어 두고 기준을 바꾸니 1만 9천 자였던 일이 바로 다음에 나왔습니다.

지금 다국어 필드를 다루는 코드가 있으시다면, encode 를 한 번만 grep 해 보세요. 거기 걸리는 게 있으면 그건 검증기가 아니라 상한입니다.

관련 글