1. 의존성(Dependency)이란 대체 뭔가 - 레고 블록의 악몽

의존성을 가장 쉽게 설명하자면 "내 앱이 작동하기 위해 필요한 다른 사람이 만든 코드 조각들"입니다. 마치 레고 블록처럼 여러 조각을 조립해서 앱을 만드는데, 문제는 이 블록들이 서로 맞지 않는 경우가 너무 많다는 것이죠.

예를 들어, 카메라 기능을 구현하려면:

이렇게 꼬리에 꼬리를 무는 것이 의존성입니다.

  1. 직접 의존성 vs 간접 의존성 내가 직접 추가한 라이브러리는 '직접 의존성'입니다. 하지만 그 라이브러리가 또 다른 라이브러리를 필요로 하는 '간접 의존성'이 진짜 문제입니다.
  2. 의존성 충돌의 시작 A 라이브러리는 C 라이브러리 버전 1.0을 요구하고, B 라이브러리는 C 라이브러리 버전 2.0을 요구한다면? 빌드는 실패하고 여러분은 머리를 쥐어뜯게 됩니다.
  3. 왜 이런 시스템을 만들었나 아이러니하게도 의존성 시스템은 개발을 '쉽게' 하려고 만들어졌습니다. 모든 코드를 처음부터 짜는 대신, 남이 만든 검증된 코드를 가져다 쓰자는 좋은 의도였죠. 하지만 현실은...

2. 안드로이드 버전 파편화 - 지옥의 시작

안드로이드의 가장 큰 저주는 '파편화(Fragmentation)'입니다. iOS와 달리 안드로이드는 수천 개의 제조사, 수만 개의 기기 모델, 그리고 Android 4.4부터 14까지 모든 버전이 여전히 사용되고 있습니다.

  1. API 레벨의 악몽 Android 5.0(API 21)에서 추가된 기능을 쓰고 싶은데, 아직도 4.4를 쓰는 사용자가 있다면? 조건문으로 버전을 체크하고 다른 코드를 작성해야 합니다.
  2. 제조사별 커스터마이징 삼성, LG, 샤오미... 각 제조사가 안드로이드를 마음대로 수정합니다. 같은 Android 12라도 제조사마다 동작이 다를 수 있습니다.
  3. 하위 호환성의 딜레마 구글은 하위 호환성을 포기할 수 없습니다. 10년 전 기기도 지원해야 하니, 새로운 기능을 추가할 때마다 복잡도가 기하급수적으로 증가합니다.

3. Gradle과 빌드 시스템 - 필요악의 대명사

Gradle은 안드로이드의 빌드 시스템입니다. 의존성을 관리하고, 코드를 컴파일하고, APK를 만드는 모든 과정을 담당하죠. 하지만 이게 또 골칫거리입니다.

Gradle이 하는 일들:

  1. Gradle 버전 자체의 문제 Gradle도 버전이 있고, Android Gradle Plugin도 버전이 있습니다. 이 둘의 호환성도 맞춰야 합니다. Gradle 7.0은 AGP 7.0과 맞지만, Gradle 6.0과는 안 맞습니다.
  2. 빌드 캐시의 저주 "Clean Project 하고 다시 빌드하세요"라는 조언을 들어보셨나요? Gradle 캐시가 꼬이면 이상한 오류가 발생합니다. 캐시를 지우면 해결되지만, 다시 빌드하는데 30분...
  3. 의존성 해결 알고리즘 Gradle은 복잡한 알고리즘으로 버전 충돌을 해결하려 합니다. 하지만 때로는 잘못된 선택을 하고, 런타임에 크래시가 발생합니다.

4. 실제 발생하는 버전 충돌 사례들 - 현실의 고통

실제로 안드로이드 개발하면서 마주치는 대표적인 버전 충돌 사례들을 살펴봅시다.

사례 1: AndroidX 마이그레이션 지옥

Error: Manifest merger failed : Attribute application@appComponentFactory value=(android.support.v4.app.CoreComponentFactory)

구버전 Support Library와 새로운 AndroidX가 충돌하는 전형적인 예입니다.

사례 2: Kotlin 버전 충돌

Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.8.0, expected version is 1.6.0

라이브러리가 더 높은 Kotlin 버전으로 컴파일되어 있을 때 발생합니다.

사례 3: Firebase의 악몽

Please fix the version conflict either by updating the version of the google-services plugin or updating the version of com.google.android.gms

Firebase와 Google Play Services 버전이 맞지 않을 때의 고통입니다.

  1. Jetpack Compose 도입의 함정 Compose를 쓰려면 Kotlin 버전, Gradle 버전, 심지어 Android Studio 버전까지 모두 맞춰야 합니다. 하나라도 틀리면 빌드 실패.
  2. 네이티브 라이브러리 충돌.so 파일이 중복되거나 아키텍처가 맞지 않으면 런타임 크래시. 디버깅도 어렵습니다.
  3. ProGuard/R8 규칙 충돌 각 라이브러리마다 난독화 규칙이 있는데, 이게 충돌하면 릴리즈 빌드만 크래시가 발생합니다.

5. 왜 이런 시스템이 생겼나 - 역사적 배경

이 모든 고통의 역사적 배경을 이해하면 조금은 납득이 될 수도 있습니다(화는 여전히 나지만).

  1. 오픈소스 생태계의 성장 안드로이드는 오픈소스를 기반으로 빠르게 성장했습니다. 누구나 라이브러리를 만들고 공유할 수 있었죠. 하지만 통제되지 않은 성장은 혼돈을 가져왔습니다.
  2. 구글의 전략 변경 Support Library → AndroidX로의 전환, Eclipse → Android Studio로의 이동 등 구글의 큰 방향 전환마다 개발자들은 고통받았습니다.
  3. 자바에서 코틀린으로 코틀린 도입은 좋았지만, 또 다른 버전 관리 지옥을 만들었습니다. Java 8, 11, 17... Kotlin 1.4, 1.5, 1.6, 1.7, 1.8, 1.9...

6. 버전 맞추기 실전 가이드 - 생존 전략

이제 실제로 버전 충돌을 해결하는 방법을 알아봅시다. 이건 정말 경험에서 나온 피눈물의 노하우입니다.

  1. 버전 카탈로그 사용하기
  2. 의존성 트리 분석
  3. 강제 버전 지정
  4. exclude 전략

충돌하는 의존성을 제외시킬 수 있습니다.

7. 개발 환경 세팅의 베스트 프랙티스

버전 지옥을 최소화하는 개발 환경 세팅 방법입니다.

  1. 버전 고정 원칙
  2. 정기적인 업데이트 전략
  3. 로컬 환경 격리
  4. CI/CD 활용 GitHub Actions나 Jenkins에서 클린 환경 빌드를 돌려보세요. 로컬에서만 되는 빌드를 방지할 수 있습니다.

8. 미래는 나아질까? - 희망과 절망

구글도 이 문제를 인지하고 개선하려 노력하고 있습니다.

  1. Version Catalog의 도입 Gradle 7.0부터 도입된 버전 카탈로그는 의존성 관리를 훨씬 쉽게 만들었습니다.
  2. Gradle의 개선 빌드 속도 향상, 더 나은 캐싱, 명확한 에러 메시지 등 계속 개선되고 있습니다.
  3. BOM(Bill of Materials) 도입

BOM을 사용하면 호환되는 버전을 자동으로 선택합니다.

하지만 여전히 갈 길은 멉니다. 안드로이드의 파편화는 계속될 것이고, 새로운 기술(Compose Multiplatform 등)은 또 다른 복잡성을 추가할 것입니다.