Android App architecture: About app architecture

안드로이드 App architecture: About app architecture를 알아보겠습니다.



앱 개발에 있어서 좋은 구조는 어떤 것인지 알아봅시다.


출처:
https://developer.android.com/topic/architecture


◎ Common architectural principles; 일반적인 아키텍처의 원칙들



• Separation of concerns; 목적에 따라 분리하기: 

UI와 관련된 클래스들은 UI와 인터페이스만 다루게 해야 합니다.



• Drive UI from data models; Data 모델이 UI를 조절하기:

Data 모델은 앱의 데이터를 나타냅니다. 데이터는 UI와 다른 요소들과 분리되어 있습니다.

영구 보관 모델이 이상적인 이유 두 가지입니다.

  - Android OS가 앱을 종료하더라도 data를 잃지 않는다.

  - Network가 불안정하거나 끊기더라도 앱을 계속 사용할 수 있다.



• Single source of truth; 하나의 진실한 소스:

새로운 data type을 앱에 정의할 때, Single Source of Truth(SSOT)를 적용해야 합니다. SSOT는 data의 소유자이며 SSOT만이 data를 변경할 수 있습니다.

이 패턴이 가져다주는 이득은 여러 가지입니다.

  - 특정 한 type의 data 변경을 한 장소에서 관리한다.

  - data를 보호하여 다른 type들이 조작할 수 없게 한다.

  - data를 추적하기 쉽게 해주어, 버그를 찾기 용이해진다.

오프라인 모드가 우선인 앱의 경우 SSOT는 보통 database가 됩니다. 다른 경우에는 ViewModel 또는 UI가 될 수 있습니다.



• Unidirectional Data Flow; 단방향 data 흐름:

Single Source Of Truth 원칙은 Unidirectional Data Flow(UDF) 패턴과 함께 사용됩니다. State는 오직 한 방향으로만 흐릅니다. 반대 방향으로는 data를 변경하는 Event가 흐릅니다.

안드로이드에서는 state 또는 data가 계층의 higher-scoped type에서 lower-scoped로 흐릅니다. Events는 보통 lower-scoped types에서 발생합니다. 예를 들어, data는 data source에서 UI로 흐릅니다. 버튼 클릭 같은 사용자 event는 UI에서 SSOT로 흐릅니다.

이러한 패턴은 data의 일관성을 지키고, 오류를 줄여주며, 디버그 하기 쉽고 SSOT 패턴의 모든 장점을 활용할 수 있게 해줍니다.



◎ Recommended app architecture; 추천하는 앱 구조:

여기서 추천하는 구조는 확장 가능하고, 품질이 좋고, 활동적이며, 테스트하기 쉽게 해줍니다. 그러나, 이것은 Guidline(지침)일 뿐입니다. 상황에 맞게 수용해야 합니다.





위에서 설명한 일반적인 architectural의 원칙들을 고려해 볼 때, 앱은 적어도 두 개의 layer를 가지고 있어야 합니다.

  - UI layer 화면에 data를 그려주는 layer(레이어).

  - data layer 비즈니스 로직과 앱의 data를 전달하는 layer.

domain layer를 선택적으로 넣을 수 있습니다. UI와 data layer 사이에 자주 사용되는 것을 모아놓은 layer.






화살표는 의존성을 나타내며 각 layer가 바라보는 방향입니다. Domain layer는 data layer를 볼 수 있습니다.




• Modern App Architecture; 현대의 앱 구조:

Modern App Architecture는 아래의 기술을 사용하길 장려합니다.

  - 반응하고 계층이 분리된 구조.

  - Unidirectional Data Flow(UDF)를 모든 layer에 사용.

  - UI layer에 state holder를 사용하여 복잡한 UI 관리.

  - Coroutine과 flow 사용.

  - Dependency injection(의존성 주입) 사용.



• UI layer:

UI layer의 역할은 data를 화면에 보여주는 것입니다. data가 변하거나 사용자의 입력, 네트워크 연결 등의 변화가 있으면 UI를 최신화합니다.

UI layer는 두 가지로 구성되어 있습니다.

  - Views 또는 Compose를 사용하여 data를 UI로 그리는 것.

  - ViewModel 같은 State holders가 보유한 data를 UI에 보여주고 로직 처리하는 것.





• Data layer:

Data layer는 business 로직을 포함합니다. business logic 이란 당신의 앱에 가치를 주는 것을 말합니다. 데이터를 만들고 저장하고 변경하고 이러한 작업들을 말합니다.

Data layer는 repositories를 가지고 있으며, repositories에는 0에서 여러 개의 data Sources를 가질 수 있습니다. repository는 다루는 data에 맞춰서 만들어야 합니다. MoviesRepository는 movies data만 다루고, PaymentsRepository는 payments와 관련된 data만 다룹니다.








Repository가 하는 일은 다음과 같습니다.

  - data를 앱의 여러 부분에 전달한다.

  - data의 변화를 관리한다.

  - 여러 data sources의 충돌을 관리한다.

  - Data와 관련된 sources를 추상화한다.

  - business logic을 포함한다.

Data source는 한 가지 source of data에 관해서만 작동합니다. 예로는 file, network, local database가 될 수 있습니다. Data source는 앱과 data를 불러오는 기능을 연결합니다.



• Domain layer

Domain layer는 선택사항이며, UI와 data layer 사이에 있습니다.

복잡한 business logic을 캡슐화하고, 간단한 로직의 경우 여러 ViewModel에서 재사용할 수 있게 만들어줍니다. 이 domain layer가 선택사항인 이유는 모든 앱에 필요하지 않기 때문입니다. 복잡한 로직을 다루거나 재사용성을 높이고 싶을 때만 사용합니다.








Domain layer에 사용되는 class의 이름은 보통 use case 또는 interactors라고 불립니다. 각 각의 use case는 하나의 기능에만 사용합니다. 예를 들어, GetTimeZoneUseCase의 경우 time zone을 UI에 보여줄 message로 변경하는 하나의 기능만 수행합니다.



◎ Manage dependencies between components; 요소 간 의존성 관리:

class 간의 의존성을 관리하는 방법은 두 가지가 있습니다.

  - Dependency injection(DI): 내부에서 호출하는 것이 아닌 외부에서 받습니다.

  - Service locator: 내부에서 호출하는 것이 아닌 레지스트리를 제공합니다.

둘 다 확장성이 좋고 중복과 복잡성 없이 의존성이 관리하기 좋습니다. 그리고 test와 실제 제품의 차이를 줄 수 있습니다.



구글에서는 Dependency injection을 사용하길 추천하고, 라이브러리는 Hilt library를 추천합니다.





• General best practices; 일반적인 사항들

프로그래밍은 창조적인 영역이고, Android 앱 개발 역시 마찬가지입니다.

아래의 추천은 강제가 아닙니만, 추천을 따르면 좀 더 유연하고 활동적이고 테스트가 쉽고, 유지 보수가 쉬워집니다.

  - Don't store data in app components; data를 앱 요소에 저장하지 마세요:

activity, service, broadcast receiver 등은 data의 source로 사용하기에 생명 주기가 짧습니다. 

  - Reduce dependencies on Android classes; 안드로이드 class의 의존성을 낮추세요:

앱 요소에만 Context, Toast 등의 Android framework SDK APIs를 사용하세요. 다른 class에서는 Android framework SDK APIs 사용을 피해 테스트를 쉽게 만들고 연결을 줄이세요.

  - Create well-defined boundaries of responsibility between various modules in your app; 여러 모듈이 영역을 잘 지정하세요:

예를 들어, 네트워크에서 데이터를 가져오는 코드를 여러 class와 package에 걸쳐서 만들지 말라는 뜻입니다. 비슷하게 여러 관련 없는 data caching과 data binding 같은 행위들을 같은 class에 넣지 마세요.

  - Expose as little as possible from each module; 각 모듈 간 최소한의 영역만 공유하세요:

예를 들어, 모듈 간 직접적으로 내부를 연결하지 마세요. 간단하게 연결할 수 있겠지만, 나중에 코드가 변경되거나 추가될 때 많은 시간이 필요하게 됩니다.

  - Focus on the unique core of your app so it stands out from other apps; 당신만의 앱 기능에 집중하세요. 그래야 다른 앱들보다 우위에 있을 수 있습니다:

동일한 작업을 하는데 시간을 낭비하지 마세요. 여러 라이브러리를 사용하고 당신만의 앱을 위한 기능에 집중하세요.

  - Consider how to make each part of your app tesetable in isolation; 독립되고 테스트가 쉬운 앱 부분들을 어떻게 만들지 고민하세요:

예를 들어, 네트워크 데이터를 가져와 최신화를 하는 잘 정의된 API는 내부 저장소에 있는 data를 테스트하기 쉽습니다. 만약 두 module에 있는 여러 로직을 한 장소에 섞거나 전체 코드 속에 나눠 넣는다면 점점 어려워지고 테스트가 불가능할지도 모릅니다.

  - Types are responsible for their concurrency policy; 동시성 원칙에 따라 알맞게 Type을 정하세요:

만약 오랜 시간 작업이 필요한 type이라면 알맞은 thread로 옮겨야 합니다. Type은 main-safe 해야 하고 이 뜻은 main thread를 멈추지 않고 실행할 수 있어야 합니다.

  - Persist as much relevant and fresh data as possible; 가능한 연관되고 최신화된 data를 유지하세요:

그래야만 사용자가 당신의 앱을 즐겁게 사용할 수 있습니다. 비록 오프라인 모드일지라도요. 모든 유저가 빠른 네트워크를 사용하지는 않습니다. 또한, 공공장소에서는 느린 환경일 수도 있습니다.





◎ Benefits of Architecture; 구조의 장점

좋은 구조는 개발팀과 프로젝트에 많은 이점을 줍니다.

• 유지 보수가 쉽고, 좋은 품질, 좋은 앱의 활동성

• 확장 가능성, 많은 사람들이 적은 코드 충돌로 협업이 가능합니다.

• 설명하기 쉬워 새로운 사람이 들어와도 빠르게 이해하고 참여할 수 있습니다.

• 테스트하기 쉬움.

• 버그를 찾기 쉽다.

구조는 또한 여러분의 사용자에게도 영향을 줍니다. 구조는 안정적인 앱, 좋은 생산성으로 기능들을 많이 만들 수 있습니다. 그러나 구조는 또한 준비 시간이 필요합니다. 그래서 당신의 회사 사람들에게 설득할 때, 성공적인 앱들의 예시를 활용해 보세요.





끝.


카테고리: Android

댓글

이 블로그의 인기 게시물

Python urllib.parse.quote()

Python bytes.fromhex()

Python OpenCV 빈 화면 만들기

Android Notification with Full Screen

Android Minimum touch target size

Android Compose Instrumentation test to unit test

KiCad 시작하기 7 (FreeRoute 사용하기 2)

tensorflow tf.expand_dims()

딩기 요트 명칭

Android AVD Ram size change