안드로이드 여러 앱 버전 관리, 결국 통일한 세 가지 규칙

도입
안드로이드 여러 앱 버전 관리는 앱을 한 개만 운영할 때는 잘 드러나지 않다가, 두 번째, 세 번째 앱을 만들면서부터 갑자기 골치 아파지는 문제입니다. 저는 개인 앱을 여러 개 동시에 운영하면서 앱마다 제각각이던 버전 번호 규칙과 배포 절차를 시맨틱 버저닝, 통일된 브랜치 전략, 배포 전 체크리스트로 정리했고, 그 이후로 스토어에 잘못된 버전을 올리는 실수가 눈에 띄게 줄었습니다. 이 글에서는 그 과정에서 실제로 부딪힌 문제와 지금까지 지키고 있는 기준을 정리합니다.
앱이 하나에서 여러 개로 늘어나며 생긴 문제
앱을 하나만 관리할 때는 버전 번호를 어떻게 매기든 크게 문제가 되지 않았습니다. 릴리즈 주기도 제 머릿속에만 있으면 됐고, 브랜치 이름도 그때그때 편한 대로 지어도 헷갈릴 일이 없었습니다.
문제는 여러 앱을 동시에 운영하게 되면서 시작됐습니다. 앱 A는 1.2.0 다음이 마이너 업데이트인지 패치인지 감으로 정하고 있었고, 앱마다 브랜치 운용 방식도 조금씩 달랐습니다. 다만 브랜치 이름 자체(release vs releases 같은 표기 차이)로 헷갈린 적은 없었는데, 애초에 모든 레포에 gitflow 정책을 적용해두고 있었기 때문입니다. 진짜 문제는 버전 번호 쪽이었습니다.
앱마다 시맨틱 버저닝 규칙을 통일한 방법
가장 먼저 정리한 건 버전 번호였습니다. 모든 앱에 MAJOR.MINOR.PATCH 규칙을 동일하게 적용하되, 기준을 이렇게 나눴습니다.
- MAJOR: 화면 구조나 핵심 플로우가 바뀌어 기존 사용자가 다시 적응해야 하는 변경
- MINOR: 기능 추가지만 기존 사용 흐름은 그대로 유지되는 변경
- PATCH: 버그 수정, UI 미세 조정처럼 사용자가 거의 인지하지 못하는 변경

기준을 세우기 전에는 MAJOR를 올리는 기준이 명확하지 않다 보니, 사용자 문의가 들어온 적은 없었지만 어느 순간 돌아보면 MAJOR 숫자가 3까지 올라가 있는 경우가 있었습니다. 뒤늦게 히스토리를 되짚어보면 그 정도로 큰 변경이 실제로 세 번 있었는지 스스로도 확신이 서지 않는 경우였고, 그게 기준을 명문화해야겠다고 마음먹은 계기가 됐습니다.
versionCode는 versionName과 별개로 앱마다 계속 증가하는 정수 하나로만 관리합니다. Google Play는 새 버전인지 판단할 때 versionCode만 보고, 업데이트할 때는 이전 값보다 커야 하며 최댓값(2100000000)을 넘으면 그 이상 빌드를 올릴 수 없다는 제한도 있어서 처음부터 여유 있게 관리하는 편이 낫습니다.[1] 게시 형식도 APK가 아니라 Android App Bundle(AAB)이 표준이라, 여러 앱 모두 AAB 업로드를 기본값으로 맞췄습니다.[1]
브랜치 전략: Gitflow를 기본값으로 통일한 이유
브랜치는 처음부터 gitflow 정책을 기준으로 통일했습니다. main(배포된 상태) / develop(다음 배포 준비) / release/*(배포 준비 중인 브랜치) / hotfix/*(긴급 수정) 구조를 모든 레포에 동일하게 적용했습니다.
- main: 스토어에 실제로 올라간 상태와 항상 동일한 브랜치
- develop: 다음 배포를 준비하는 개발 브랜치
- release/*: 배포를 준비하며 마무리 작업만 반영하는 브랜치
- hotfix/*: main에서 분기해 급한 수정만 반영하고, 수정 후 main과 develop 양쪽에 다시 합치는 브랜치
gitflow라는 정해진 규약을 그대로 따르다 보니 브랜치 이름 표기 차이로 레포를 오가며 헷갈리는 일은 애초에 없었습니다. 이 원칙은 [
혼자 개발한 AI 챗봇에서 마주친 기술부채들]에서 다룬 기술부채 관리와도 맞닿아 있습니다.
혼자 개발한 AI 챗봇에서 마주친 기술부채들
도입사이드 프로젝트를 혼자 진행하다 보면 기능을 붙이는 데 집중하느라 구조를 되돌아볼 시간을 따로 내기 어렵습니다. 이번에 AlterAI 소개 글을 준비하면서 코드베이스를 다시 훑어봤는데,
blog.jdevy.com

배포 전 체크리스트로 실수를 줄이다
버전 규칙과 브랜치를 정리한 뒤에도, 배포 직전에 확인하지 않으면 놓치는 항목들이 있어서 앱 종류와 무관하게 공통으로 쓰는 체크리스트를 만들었습니다.
- versionCode가 스토어에 올라간 마지막 값보다 큰지 확인
- 서명 키가 이전 릴리즈와 동일한 키인지 확인 (키가 다르면 업데이트 자체가 거부됨)
- 릴리즈 노트를 국문/영문 모두 작성했는지 확인
- main 브랜치와 실제로 빌드한 소스가 일치하는지 확인 (로컬에만 반영하고 푸시를 잊는 경우 방지)
- 타겟 API 레벨이 스토어 정책 기준을 충족하는지 확인
이 중 서명 키 항목은 업데이트가 거부되는 가장 흔한 원인 중 하나라 예방 차원에서 목록에 넣었습니다. [
출석체크, 이벤트 참여... 앱마다 흩어진 할 일을 한곳에]처럼 여러 앱을 관리하는 과정에서 하나씩 늘려온 항목들입니다.
출석체크, 이벤트 참여... 앱마다 흩어진 할 일을 한곳에
도입매일 쓰는 앱 중에는 "출석체크만 하면 포인트를 주는" 앱, "매일 퀴즈를 풀면 혜택을 주는" 앱처럼 반복되는 자잘한 할 일이 딸려있는 경우가 많습니다. 문제는 이런 할 일이 앱마다 따로 흩
blog.jdevy.com
정리: 결국 지키는 원칙 몇 가지
완벽한 정답이 있는 문제는 아니라고 생각합니다. 다만 앱 개수가 늘어날수록 "이번엔 예외로 하자"는 판단을 줄이는 쪽이 결국 실수를 줄인다는 걸 체감했습니다. 지금은 새 앱을 만들 때도 버전 규칙, 브랜치 이름, 체크리스트를 그대로 가져와 시작하고, 예외가 필요하면 그 이유를 코드가 아니라 문서로 남겨두는 정도로 정리하고 있습니다.
자주 묻는 질문
앱이 두 개뿐이어도 이렇게까지 정리할 필요가 있나요?
앱이 두 개면 아직은 감으로 버틸 수 있는 시점일 수 있습니다. 다만 세 번째 앱을 만들 계획이 있다면, 그 전에 규칙을 미리 통일해두는 편이 나중에 전체 레포를 갈아엎는 것보다 수고가 훨씬 적었습니다.
시맨틱 버저닝 대신 날짜 기반 버전을 쓰면 안 되나요?
팀·서비스 성격에 따라 날짜 기반 버전이 더 맞는 경우도 있습니다. 다만 여러 앱을 동시에 운영할 때는 "이 버전이 이전 버전보다 얼마나 큰 변경인지"를 버전 번호만으로 짐작할 수 있다는 점에서, 개인적으로는 시맨틱 버저닝 쪽이 더 유용했습니다.
[핵심요약]
여러 앱 운영 시 버전·브랜치(gitflow)·체크리스트 통일 경험