일반적인 Android 앱에는 액티비티, 프래그먼트, 서비스, 콘텐트 프로바이더, 브로드캐스트 리시버를 비롯해 여러 앱 컴포넌트를 포함할 수 있고, 짧은 시간 내에 여러 앱과 상호작용할 때도 많다는 점을 고려하면, 앱은 사용자 중심의 다양한 워크플로에 맞게 조정될 수 있어야 합니다.
또한, 기기의 리소스는 제한적이므로 운영체제에서 새로운 앱을 위한 공간을 확보하기 위해 언제든 일부 앱 프로세스를 종료해야할 수 있습니다.
앱 컴포넌트는 개별적이고 비순차적으로 실행될 수 있으며, 운영체제나 사용자가 언제든지 앱 컴포넌트를 제거할 수 있습니다. 이런 이벤트는 직접 제어할 수 없기 때문에 앱 컴포넌트에 애플리케이션 데이터나 상태를 저장해서는 안되며 앱 컴포넌트가 서로 종속되면 안됩니다.
Android 앱은 크기가 커지기 때문에 앱을 확장하고 견고성을 높이며 더 쉽게 테스트할 수 있도록 아키텍처를 정의하는 것이 중요합니다. 이를 위해 아래 원칙을 준수하도록 앱 아키텍처를 설계해야 합니다.
1. 관심사 분리
따라야 할 가장 중요한 원칙입니다. 액티비티 또는 프래그먼트에 모든 코드를 작성하는 실수는 흔히 일어납니다. 이러한 UI 기반의 클래스를 최대한 가볍게 유지하여 컴포넌트의 라이프사이클과 관련된 많은 문제를 피하고, 테스트 가능성을 개선할 수 있습니다.
또한, OS는 사용자 상호작용을 기반으로 또는 메모리 부족과 같은 시스템 조건으로 인해 언제든지 클래스를 제거할 수 있습니다. 만족스러운 사용자 환경과 수월한 앱 관리 환경을 제공하려면 이러한 클래스에 대한 의존성을 최소화하는 것이 좋습니다.
2. 데이터 모델에서 UI 도출하기
또 하나의 중요한 원칙은 데이터 모델에서 UI를 도출해야 한다는 것 입니다. 가급적 persistent models(ex Room, DataStore)를 사용하기를 권장합니다. 데이터 모델은 앱의 데이터를 나타냅니다. 데이터 모델은 앱의 UI 요소 및 기타 컴포넌트와 독립되어 있어 UI 및 앱 컴포넌트의 라이프 사이클과는 관련이 없습니다.
persistent models 사용이 이상적인 이유?
- Android OS에서 리소스를 확보하기 위해 앱을 제거해도 사용자 데이터가 삭제되지 않습니다.
- 네트워크 연결이 취약하거나 연결되어 있지 않아도 앱이 계속 작동합니다.
위에 언급한 일반적인 아키텍처 원칙을 고려하면 각 앱에서는 레이어가 두 개 이상 있어야 합니다.
1. 화면에 애플리케이션 데이터를 표시하는 UI 레이어
2. 앱의 비즈니스 로직을 포함하고 애플리케이션 데이터를 노출하는 데이터 레이어
UI와 데이터 레이어 간의 상호작용을 간소화하고 재사용하기 위한 도메인 레이어를 추가할 수 있습니다.
다이어그램의 화살표는 클래스 간의 종속 항목을 나타냅니다. 예를 들어 도메인 레이어는 데이터 레이어 클래스에 의존합니다.
UI 레이어(또는 프레젠테이션 레이어)의 역할은 화면에 애플리케이션 데이터를 표시하는 것입니다. 사용자 상호작용(ex 버튼 누르기) 또는 외부 입력(ex 네트워크 응답)으로 인해 데이터가 변할 때마다 변경사항을 반영하도록 UI가 업데이트되어야 합니다.
UI 레이어는 다음 두 가지로 구성됩니다.
앱의 데이터 레이어에는 비즈니스 로직이 포함되어 있습니다. 비즈니스 로직은 앱에 가치를 부여하는 요소로, 앱의 데이터 생성, 저장, 변경 방식을 결정하는 규칙으로 구성됩니다.
데이터 레이어는 0개부터 여러 개의 데이터 소스들을 저장할 수 있는 각각의 리포지토리로 구성됩니다. 앱에서 처리하는 다양한 유형의 데이터마다 리포지토리 클래스를 만들어야 합니다. 예를 들어 영화 관련 데이터에는 MoviesRepository
클래스, 결제 관련 데이터에는 PaymentsRepository
클래스를 만들 수 있습니다.
리포지토리 클래스에서 담당하는 작업은 다음과 같습니다.
각각의 데이터 소스 클래스는 파일, 네트워크 소스, 로컬 데이터베이스 같은 하나의 데이터 소스만 사용해야 합니다.
도메인 레이어는 UI 레이어와 데이터 레이어 사이에 있는 선택적 레이어입니다.
도메인 레이어는 복잡한 비즈니스 로직, 또는 여러 viewModel에서 재사용되는 간단한 비즈니스 로직의 캡슐화를 담당합니다.
예를 들어 여러 ViewModel에서 시간대를 사용하여 화면에 적절한 메시지를 표시하는 경우 앱에는 GetTimeZoneUseCase
클래스가 있을 수 있습니다.
앱의 클래스는 올바른 작동을 위해 다른 클래스에 종속될 수 있습니다. 특정 클래스의 종속 항목을 수집하는 데 다음 디자인 패턴 중 하나를 사용할 수 있습니다.
아래의 권장 사항은 필수는 아니지만, 장기적으로 더 강력하고, 테스트 및 유지관리가 쉬운 코드를 작성할 수 있습니다.
Context
또는 Toast
같은 Android 프레임워크 SDK API를 사용하는 유일한 클래스여야 합니다. Android 클래스로부터 앱의 다른 클래스를 추상화하면 테스트 가능성은 높이고 앱 내의 커플링은 줄일 수 있습니다.