이름을 확정하고 나서 검색해봤다
새 앱의 이름을 정했다. 좋은 이름이었다. 코드 네 군데의 표시명을 바꾸고, 법적 문서 세 종을 고치고, 이름이 어긋나면 실패하는 테스트까지 새로 심었다. PR 을 올리고 머지했다. 그리고 스토어에서 검색해봤다.
확정은 쉬웠다
운세 앱을 하나 만들고 있다. 새벽 두 시, 이름을 정했다. 앱의 성격을 잘 담고 발음도 편한 이름이었다.
확정한 다음에 한 일들이 정석 그 자체였다. 안드로이드 매니페스트의 표시명, iOS 번들 표시명, 앱 안의 제목, 알림 문구까지 네 군데를 전부 맞췄다. 이용약관·개인정보처리방침 같은 문서 세 종도 새 이름으로 갈았다. 그리고 이 네 군데가 서로 어긋나면 실패하는 테스트를 새로 만들어 넣었다.
테스트 149개가 전부 통과했다. PR 을 올리고, 머지했다.
그 다음에 스토어 검색을 돌렸다.
이미 있었다
구글 플레이에 같은 이름으로 시작하는 앱이 이미 있었다. 다른 개발자가 만든, 같은 분야의, 접두가 완전히 일치하는 앱.
애플 쪽은 깨끗했다. 여덟 개가 걸렸지만 전부 부분 일치였고 완전히 같은 이름은 없었다.
여기서 판단이 갈렸다. 한쪽에서는 “이건 실격이다, 이름을 못 쓴다”는 결론이 나왔다. 다른 쪽에서는 조사 결과를 다시 읽고 이렇게 판정했다 — 구글 플레이는 표시명의 유일성을 강제하지 않는다. 그러니 기술적으로 막히는 건 아니다. 진짜 피해는 검색 결과에서 그 앱이 먼저 뜬다는 것, 그리고 애플 심사에서 유사명으로 지적받을 여지가 있다는 것.
실격이라는 단정은 과했다. 하지만 그렇다고 그냥 쓸 이름도 아니었다.
되돌리는 데 든 비용
결국 이름을 원래대로 되돌렸다. 되돌리는 PR 을 올려 머지했다.
그 사이에 다른 기계가 같은 파일을 만지고 있었다. 되돌리기가 머지되면서 그쪽 작업 브랜치에 충돌이 두 군데 생겼다. 표시명이 있는 파일 두 개가 정확히 부딪혔다.
충돌을 풀고, 테스트를 다시 돌리고, 다시 올렸다. 그리고 다음 날 아침, 최종 결정이 내려왔다. 처음 이름으로 확정. 그러니까 되돌린 그 상태가 정답이었다.
계산해보면 이렇다. 이름을 확정하고 → 코드에 반영하고 → 머지하고 → 검색해서 문제를 발견하고 → 되돌리고 → 충돌을 풀고 → 다시 확정했다. 중간의 네 단계가 통째로 왕복이었다. 만약 확정 전에 검색을 먼저 했다면, 같은 결론에 검색 한 번으로 도착했을 것이다.
순서를 바꾸는 것만으로
이 사고에서 나온 처방은 코드가 아니라 순서였다.
가용성 확인이 확정보다 먼저다.
너무 당연해 보여서 오히려 규칙으로 안 적어 뒀던 것이다. 도메인을 살 때는 아무도 이 순서를 틀리지 않는다. 도메인은 확정한다고 내 것이 되지 않으니까. 그런데 앱 이름은 확정하면 내 것이 될 것 같은 착각을 준다. 코드에 적어 넣을 수 있으니까. 테스트로 고정할 수도 있으니까.
코드에 적힌 이름은 내 저장소 안에서만 확정이다. 바깥 세계에서는 아무 의미가 없다.
되돌릴 수 있어서 다행이었던 것
이 이야기에 결정적인 안전장치가 하나 있었다. 스토어에 앱 레코드를 아직 만들지 않았다는 것.
코드는 되돌릴 수 있다. PR 은 revert 할 수 있다. 하지만 스토어에 앱을 등록하는 건 대체로 되돌릴 수 없다. 이름이 전역으로 예약되고, 지우려면 훨씬 복잡한 절차를 밟아야 한다.
이름이 흔들리는 동안 앱 레코드 생성은 전면 정지로 묶어 뒀다. 그게 이 사고를 “하루치 코드 왕복”으로 끝나게 했다. 정지가 없었다면 되돌릴 수 없는 쪽이 먼저 확정됐을 것이다.
배운 것
바깥 세계가 소유권을 가진 것들 — 앱 이름, 도메인, 계정 아이디, 상표 — 은 확정보다 조회가 먼저다. 내 저장소에서 확정할 수 있다는 사실이 바깥에서 쓸 수 있다는 뜻은 아니다.
되돌릴 수 있는 것과 없는 것을 갈라서, 없는 쪽을 뒤로 미루는 습관이 여기서 값을 했다. 이름이 흔들리는 동안 코드는 마음껏 흔들려도 됐다. 흔들리면 안 되는 건 스토어 등록이었고, 그건 잠겨 있었다.
그리고 남의 판정을 그대로 받지 않고 근거를 다시 읽은 것도 값을 했다. “실격”이라는 단정이 그대로 통과했다면 쓸 수 있는 이름을 버렸을 것이다.
내 저장소에서의 확정은 확정이 아니다. 세상이 동의해야 확정이다.
— 강대종 / @ssamssae