개발 slecs

안드로이드 버전 코드 올리기 전 결제 회귀 테스트까지 챙기는 릴리즈 루틴

목차

build.gradle 한 줄 고치는 게 이렇게 무거울 수 있나 싶다. versionCode 7로 바꾸고 커밋 메시지 타이핑하면서 손이 잠깐 멈췄음. v1.0.4 릴리즈 준비인데, 코드 변경은 단 한 줄이지만 그 줄이 프로덕션으로 나가는 순간부터 스토어에서 이 숫자보다 낮은 빌드는 사실상 존재를 지우게 된다.

versionName vs versionCode — 여전히 헷갈리는 사람을 위해

팀 내에서 이 둘을 혼동하는 상황을 여러 번 봤다. 쓸 때마다 정리해두는 게 낫겠다 싶어 표로 박아둠.

항목 용도 예시
versionName 사용자에게 보여주는 문자열 "1.0.4"
versionCode 스토어/시스템이 비교하는 정수 7
defaultConfig {
    versionCode 7
    versionName "1.0.4"
}

versionName은 마케팅용 레이블이라 "1.0.4-hotfix"나 "1.0.4-rc1" 같이 써도 APK는 멀쩡히 동작한다. 근데 versionCode는 규칙이 하나뿐임. 무조건 단조 증가하는 정수. 한번 7이 나가면 다음엔 8 이상이어야 하고, 어떤 이유로든 7로 돌아가면 Google Play가 그 빌드를 거부한다.

이게 이론으로 알고 있어도 실수가 난다. 예전에 hotfix 급하게 치려고 옛날 release 브랜치 그대로 빌드 올리다가 versionCode 충돌 터진 사고를 옆에서 봤음. 담당자가 "이미 배포된 번호랑 같다"는 에러 메시지 앞에서 당황하던 게 기억난다. 그 뒤로 팀에서 versionCode를 Git 태그 기반 CI 변수로 자동 주입하는 방식으로 바꿨는데, 수동 관리할 때보다 충돌 가능성이 많이 줄긴 했다. 다만 자동화해도 태그를 잘못 붙이면 결국 같은 문제가 생겨서, 결국 릴리즈 당사자가 직접 확인하는 단계를 없애는 건 위험하다고 본다.

한 줄짜리 커밋을 굳이 분리하는 이유

릴리즈 직전에 기능 커밋이랑 버전 bump를 한 커밋에 묶던 시절이 있었다. 당시엔 "어차피 같이 나가는 거 뭘 나눠"였는데, 롤백할 때마다 후회했음.

버전 bump를 독립 커밋으로 분리하면 얻는 게 세 가지다.

  • git log --grep="versionCode" 하나로 릴리즈 히스토리가 타임라인으로 잡힌다. 언제 어떤 버전이 나갔는지 별도 문서 없이도 파악 가능.
  • 특정 기능 커밋에 문제가 생겨 revert할 때 versionCode가 같이 되돌아가지 않는다. 기능만 빼고 버전은 유지할 수 있어서 그다음 빌드 올릴 때 번호 꼬이는 걸 방지함.
  • 릴리즈 노트 자동화 스크립트가 versionCode 커밋을 anchor 삼아 범위를 잘라내기 편하다. "이 커밋부터 다음 버전 bump 전까지"가 자연스럽게 하나의 릴리즈 단위가 됨.

이번 1.0.3 → 1.0.4도 단독 커밋으로 분리했다. 6개월 뒤에 git log 열어볼 내가 고마워할 결정임.

빌드 올리기 전 체크리스트

매번 머릿속으로 도는 루프를 한번 외부로 꺼내 적어뒀음. 습관이 된 것들인데, 팀 신규 합류자한테 공유하기도 좋다.

  • versionCode가 직전 배포본보다 큰 정수인지 확인
  • versionName이 시맨틱 버저닝 규칙대로 올라갔는지 — 버그 픽스만이면 patch(1.0.x), 사용자가 체감할 기능 추가면 minor(1.x.0)
  • 이번 변경 내용이 versionName이 내세우는 수준에 맞는지 재검토 (patch라고 표기해놓고 결제 흐름 건드렸으면 그건 patch가 아님)
  • 릴리즈 노트 초안에 개발자 관점 아닌 사용자 관점 변경점이 담겼는지
  • 결제 플랫폼 연동 쪽 회귀 테스트 — 파트너 정산 흐름은 patch 릴리즈라도 무조건 한 번 더 돌린다

마지막 항목이 다른 것들보다 비중이 크다. patch 수준 변경이라 "설마 결제가 흔들리겠어"라는 생각이 드는 게 사실인데, 그 생각이 드는 순간이 가장 위험하다. 빌드가 사용자 단말에 깔리기 시작하면 롤백 수단이 사실상 새 버전 강제 업데이트뿐이고, 그 사이에 결제 실패가 쌓이면 복구 비용이 커진다. patch 라벨이 테스트 생략의 근거가 될 수는 없다.

결제 회귀 테스트를 어느 깊이까지 돌리느냐는 팀마다 다르겠지만, 최소한 정상 결제 완료 → 정산 기록 생성 → 환불 요청 응답까지의 핵심 플로우는 끊기지 않음을 직접 확인하는 게 원칙이다. 자동화 테스트가 있다면 그 결과를 보는 것에 그치지 않고, 마지막 배포 이후 건드린 코드 경로가 테스트 커버리지 안에 들어가 있는지도 같이 보는 편이다.

versionCode 한 칸 올리는 일이 줄 수로는 1줄이지만, 그 줄이 의미하는 건 "이 빌드는 이제 되돌리기 어렵다"는 선언에 가깝다. 특히 결제 흐름이 들어간 빌드는 versionCode를 올린 순간부터 사용자 단말에 배포될 수 있다는 걸 염두에 두고 손댄다. 한 줄이라고 가볍게 넘어가지 않는 것, 그게 지금까지 릴리즈 사고를 피해온 이유 중 하나라고 생각함.

댓글 0

첫 댓글 달아줘.