Grab은 동남아시아의 선도적인 슈퍼 앱으로, 단일 앱을 통해 8개국 수백만 명의 사용자에게 배송, 모빌리티, 금융 서비스를 제공합니다. 10년 된 코드베이스에 1, 000만 줄이 넘는 코드와 수백 개의 서드 파티 라이브러리가 포함되어 있고 Bazel과 Gradle을 혼합하여 빌드된 Grab팀은 세 가지 과제에 직면했습니다. 높은 애플리케이션 응답 없음 (ANR) 비율, 슈퍼 앱에 새로운 서비스가 추가됨에 따라 계속 증가하는 앱 크기, 매년 서서히 증가하는 시작 시간이었습니다.Grab은 R8 최적화를 사용 설정하고, 유지 규칙을 미세 조정하고, 기준 프로필과 시작 프로필을 구현하여 사용자가 인식하는 ANR 발생률을 32% 줄이고, 앱 다운로드 크기를 약 30% 줄이고, 시작 시간을 35% 개선했습니다.
출시 후 ANR 급증을 제거하여 더 원활한 사용자 환경 제공
빌드 프로세스를 최적화하기 전 Grab은 새로운 업데이트 직후 콜드 스타트 지연과 애플리케이션 응답 없음 (ANR) 급증을 경험했습니다. 이는 주로 앱 초기화 중에 많은 DEX 파일을 읽는 오버헤드로 인해 발생했습니다.
Google Play의 Cloud Profiles는 전체 사용자층에 걸쳐 표준 흐름에 대한 최적화를 제공하지만, 앱 실행 중 Dagger 종속 항목 그래프 초기화와 같은 Grab의 중요한 사용자 여정에 필요한 모든 초기화 경로를 최적화하지는 않습니다. 초기 배포에 포함되지 않은 코드 경로의 경우 기기는 JIT 컴파일과 이후 며칠 동안의 로컬 백그라운드 최적화에 의존했습니다. 맞춤 기준 프로필을 구현하여 이러한 중요한 사용자 여정을 Google Play의 클라우드 프로필에 직접 제공하고 최적화 범위를 확장하여 설치 시 이러한 주요 경로가 즉시 기계어 코드로 컴파일되도록 함으로써 이 문제를 해결했습니다.
Grab의 승객 앱 핵심팀 수석 소프트웨어 엔지니어인 응우옌 반 민은 "매주 앱을 출시할 때마다 ANR 발생률이 급증하는 현상이 지속적으로 발생했습니다."라고 설명합니다.
Grab은 ANR을 제거하고 시작 시간을 개선하기 위해 R8 최적화, 기준 프로필, 시작 프로필을 구현했습니다. R8 옵티마이저와 함께 프로필 기반 최적화를 적용한 결과, R8에서 12%, 기준 프로필에서 추가로 15% 의 콜드 스타트 개선 효과를 즉시 얻었습니다. 이를 통해 시작 시간이 27% 빨라졌고 출시 후 ANR 급증 문제가 효과적으로 해결되었습니다.
Grab은 호환 모드에서 R8 최적화 사용 설정, R8 전체 모드로 전환, 구성 분석 도구를 사용한 유지 규칙 미세 조정 및 CI/CD 거버넌스 추가라는 세 가지 전략적 단계를 통해 이 앱 최적화를 실행했습니다.
1단계: R8 최적화 사용 설정 (2025년 출시)
첫 번째 단계에서 Grab은 기존의 기본 Proguard 파일에서 벗어나 R8 최적화를 지원하는 proguard-android-optimize.txt를 채택했습니다. 코드베이스가 10년 이상 되었고 1, 000만 줄이 넘는 코드가 포함되어 있었기 때문에 최적화 도구를 사용 설정하려면 레거시 구성과 리플렉션 사용을 해결해야 했습니다.
이 단계의 효과를 극대화하기 위해 Grab은 기준 프로필과 시작 프로필을 사용하여 R8 호환 모드가 사용 설정된 앱 업데이트를 출시했습니다. 이러한 노력의 결과로 사용자 인식 ANR 발생률이 즉시 25% 감소하고 앱 다운로드 크기가 16% 감소했으며 전반적인 콜드 시작 시간이 27% 개선되었습니다.
2단계: R8 전체 모드 및 이전 (2026년 출시)
첫 출시 후 9개월 만에 시작된 이 단계에서는 앱을 R8 전체 모드로 전환하여 추가 최적화를 지원했습니다. Retrofit, Firebase, Jetpack Compose와 같은 표준 라이브러리는 기본 제공 규칙을 사용하여 R8과 원활하게 작동했지만, 나머지 대규모 코드베이스를 이전하는 작업은 리플렉션이 많이 사용되는 특정 코드 경로를 해결함으로써 이루어졌습니다.
R8 전체 모드로 이전하기 위해 팀은 최신 Gson 출시의 소비자 유지 규칙을 채택하여 원활한 JSON 파싱을 보장했습니다. 또한 런타임에 리플렉션을 사용하여 인터페이스 구현을 생성하는 Java 동적 프록시의 최적화 문제도 해결했습니다. R8은 컴파일 중에 이 런타임 사용을 감지할 수 없으므로 필요한 클래스를 제거하거나 이름을 변경하여 애플리케이션이 비정상 종료됩니다. 앱 크기를 늘리는 광범위한 예외를 적용하는 대신, 리플렉션에 의존하는 특정 클래스를 분리하고 고도로 타겟팅된 유지 규칙을 구현하여 앱 안정성과 최적화 효율성을 모두 유지했습니다.
결과적으로 R8 전체 모드는 앱 다운로드 크기를 14% 추가로 줄이고, 시작 시간을 10% 추가로 개선하고, 사용자 인식 ANR을 10% 추가로 줄이는 등 엄청난 복합적 개선 효과를 가져왔습니다. R8 전체 모드로 이전한 후 Grab의 코드베이스는 다음과 같은 R8 최적화 점수를 달성했습니다.
- 최적화 점수: 72%
- 축소 점수: 73%
- 난독화 점수: 79.6%
이 점수는 R8 구성에 관한 의견과 R8 최적화를 극대화하기 위해 유지 규칙을 미세 조정해야 할 필요성을 제공했습니다.
3단계: 유지 규칙 미세 조정
최적화 여정의 마지막 단계에서 Grab은 장기적인 코드베이스 상태, 지속적인 성능 모니터링, 엄격한 컴파일 거버넌스를 확립하는 데 집중하고 있습니다. 규칙 위생을 체계적으로 측정하고 진행 중인 출시 주기 전반에서 구성 회귀를 방지하기 위해 팀은 R8 구성 분석기를 평가 워크플로에 통합하고 있습니다. 이 도구는 Grab의 유지 규칙이 R8에서 애플리케이션을 최적화, 축소, 난독화하는 데 얼마나 효과적인지 심층적으로 파악할 수 있게 해줍니다.
Grab은 R8 전체 모드를 기반으로 레거시 유지 규칙을 체계적으로 정리하여 분석기에서 평가하는 세 가지 핵심 측정기준 모두에서 상당한 개선을 이루고 있습니다.
- 최적화 점수: 72% 에서 78.2%로 증가
- 축소 점수: 73% 에서 79.1%로 증가
- 난독화 점수: 79.6% 에서 81.7%로 증가
이러한 진단 점수를 높이는 것 외에도, 이 전용 유지 규칙 미세 조정 단계를 통해 앱 다운로드 크기가 약 3.6% 추가로 감소했습니다. 더 중요한 것은 이러한 측정항목을 추적함으로써 엔지니어링팀이 자동화된 병합 전 CI 가드레일을 구현하는 데 필요한 객관적인 데이터를 확보할 수 있다는 점입니다. 이를 통해 새로 도입된 코드가 엄격한 유지 규칙 표준을 준수하고, 어렵게 얻은 성능 향상이 시간이 지나도 유지되도록 할 수 있습니다.
결과
R8 최적화 도구 출시 후 주요 성능 개선사항은 다음과 같습니다.
| 최적화 단계 | ANR | 크기 | 콜드 스타트 |
|---|---|---|---|
| 1단계: R8 최적화 도구 (2025년 출시) | ~25% 감소 | 16% 감소 | 약 27% 개선 |
| 2단계: R8 전체 모드 (2026년 출시) | 10% 감소 | 14% 감소 | 10% 개선 |
| Keep 규칙 최적화 | - | 3.6% 감소 | - |
| 전체 (누적) | 약 32.5% 감소 | 약 30.4% 감소 | 약 35% 개선 |
기술적 문제
10년 된 Grab의 코드베이스 전반에 R8 최적화 도구를 사용 설정하자 대규모의 주요 기술적 장애물이 발생했습니다.
- 테스트: 10년 동안 축적된 반사로 인해 완전 최적화 상태에서 에지 케이스가 발생했습니다. 수백만 줄의 코드에 대한 전수 테스트는 불가능했기 때문에 팀은 점진적이고 우선순위가 높은 접근 방식을 취했습니다. 특히 축소되는 유지 규칙이 적용되는 코드에 테스트를 집중하고, 리플렉션에 필요한 특정 클래스, 메서드 또는 필드만 타겟팅하도록 해당 규칙을 반복적으로 미세 조정하여 R8 최적화를 극대화했습니다.
- 빌드 지연 시간 및 하이브리드 아키텍처: Grab의 하이브리드 빌드 시스템 (디버그용 Bazel, R8 출시 빌드용 Gradle)은 실험용 R8 변경사항을 원격 CI에서 최대 2시간 동안 적용해야 했습니다. 피드백 격차를 해소하기 위해 Grab은 일일 QA 빌드를 프로덕션 R8 동작과 일치시키고 mapping.txt, configuration.txt와 같은 주요 CI 빌드 아티팩트의 수집을 자동화하여 조사를 간소화했습니다.
- 느린 디버깅 주기: 최적화된 수백 개의 클래스에서 근본 원인을 추적하는 작업은 소규모 팀에 큰 부담이 되었습니다. Grab은 Gradle을 통해 Firebase Crashlytics에 매핑 파일 업로드를 자동화하고 Play Console의 가독화 매핑을 번들로 묶어 런타임 문제에 대한 즉각적이고 정확한 기호 확인을 지원함으로써 이 문제를 해결했습니다.
R8을 사용한 장기적인 코드 영향
R8 최적화 도구를 사용 설정한 결과, 즉각적인 성능 향상 외에도 Grab의 대규모 코드베이스에 영구적인 구조적 이점이 생겼습니다. Grab팀은 오픈소스 도구인 app-sizer를 사용하여 R8의 영향을 측정했고, R8이 앱의 모든 코드 줄이 다운로드 크기에 미치는 영향을 영구적으로 줄인다는 것을 확인했습니다.
코드 양이 빠르게 증가하는 AI 지원 개발 시대에는 이러한 최적화가 더욱 중요합니다. R8이 없으면 코드 확장에 따라 다운로드 크기가 비례하여 증가합니다. R8은 동일한 코드 확장 비율로 메모리 사용량을 대폭 줄입니다.
참고: 방법론: 앱 다운로드 크기 (대표 기기)에 대한 app-sizer의 Kotlin/Java 기여도를 프로덕션 Kotlin LOC (cloc, 기본 소스 세트만, 테스트, 모의, 샘플 모듈 제외)로 나눕니다.
Keep 규칙 관리 및 가드레일
Grab은 규칙 저하를 방지하고 시간이 지나도 R8 최적화를 유지하기 위해 자동화된 병합 전 가드레일을 CI 파이프라인에 직접 통합할 계획입니다. 이 정책에 따라 새로운 보관 규칙은 엄격하게 제한되며, 추가 규칙에는 명시적인 근거와 검토가 필요합니다. Grab팀은 CI에서 R8 최적화 점수를 추적합니다. 이를 바탕으로 팀은 이러한 측정항목을 지속적인 피드백 루프로 사용하여 병합 전에 회귀를 포착하고 모든 출시 주기에서 최적화 이점을 유지할 계획입니다.
그림 1: Grab 빌드에서 시간 경과에 따른 R8 축소, 최적화, 난독화 점수를 추적하여 출시 전반에서 회귀를 사전에 발견하고 방지하는 CI 대시보드
결론
Grab의 Pax App Core팀은 성숙한 대규모 코드베이스의 문제에 직면하여 기준 프로필을 구현하고 R8 구성을 지속적으로 개선함으로써 증가하는 시작 시간과 출시 후 성능 급증 문제를 선제적으로 해결했습니다. 이 팀은 사용자 인식 ANR을 약 32.5% 줄이고, 앱 다운로드 크기를 약 30.3% 줄이고, 콜드 시작 시간을 약 35% 개선하는 동시에 코드베이스 확장 효율성을 근본적으로 개선했습니다.
이러한 최적화를 통해 동남아시아 전역의 수백만 명의 사용자에게 더 빠르고 안정적인 슈퍼 앱 환경을 제공하는 동시에 Grab 엔지니어는 다운로드 크기가 급격히 증가하지 않으면서도 기능을 더 빠르게 빌드할 수 있는 도구를 확보할 수 있었습니다.
R8을 시작하고 자세히 알아보려면 - d.android.com/r8을 방문하세요.
-
우수사례Tinder는 새로운 세대의 싱글들이 쉽고 재미있게 만나고 진정한 관계를 맺을 수 있도록 지원하고 영감을 주는 것을 목표로 합니다.
Ajesh Pai, Ulises Uriel Verduzco Díaz , Tracy Agyemang • 읽는 데 4분 소요 -
우수사례WhatsApp은 전 세계 수십억 명의 사용자에게 서비스를 제공하는 세계 최대 규모의 메시지 플랫폼입니다. WhatsApp은 다양한 지역의 사용자가 비공개적이고 안정적이며 안전한 메시지를 통해 소통할 수 있는 기본 커뮤니케이션 도구입니다.
Niharika Arora, Tracy Agyemang, Mayank Jain • 읽는 데 8분 소요 -
우수사례당근은 세부 지역의 커뮤니티 중심 P2P 마켓플레이스 앱으로, 사용자가 인증된 다른 사용자와 물품을 사고팔고 거래할 수 있습니다. 2015년 대한민국에서 출시된 이 플랫폼은 글로벌 시장으로 확장하여 4,300만 명 이상의 등록 사용자를 확보했습니다.
Thomas Ezan, Tracy Agyemang • 읽는 데 2분 소요
Android 개발 관련 최신 정보를 이메일로 받아 보세요.