Slide 1

Slide 1 text

구글의 최신 기술을 적용한 Now in Android 살펴보기 레몬트리 : taehwan

Slide 2

Slide 2 text

오늘 알아볼 내용 ● Now in Android 알아보기 ● 모듈이 많아진다면? ● buildSrc? build-logic?

Slide 3

Slide 3 text

Now in Android https://github.com/android/nowinandroid

Slide 4

Slide 4 text

Now in Android에서 알 수 있는 것 ● Kotlin 기반 ● Coroutines/Flow 활용 ● Architecture - Google official architecture guidance 적용 ○ 모듈 기반 개발 ● Jetpack Compose 적용 ○ Material 3 guidelines 적용 ○ Android 32(12-L) 대응으로 다양한 해상도 지원 ■ Jetpack Compose 1.2.0 적용 시 target 32 환경 필요 ● DI - Hilt 활용 ● UI/Unit 테스트를 포함 ● Dependency의 gradle version.controller을 활용 ● buildSrc 대신 build-logic 적용

Slide 5

Slide 5 text

Now in Android에서 알 수 있는 것 ● Kotlin 기반 ● Architecture - Google official architecture guidance 적용 ● 모듈 형태의 개발 환경 ● Jetpack Compose 적용 ○ Material 3 guidelines 적용 ○ Android 32(12-L) 대응으로 다양한 해상도 지원 ■ Jetpack Compose 1.2.0 부터는 target이 32여야 적용 가능 ● UI/Unit 테스트를 포함 ● Dependency의 gradle version.controller을 활용 ● buildSrc 대신 build-logic 적용 새로운 안드로이드 개발 환경과 Compose 가이드를 위함 > 이해한 부분 및 가능성 고려 필요 <

Slide 6

Slide 6 text

아키텍처는?

Slide 7

Slide 7 text

구글 가이드 아키텍처? Now in android는 구글이 가이드 중인 아키텍처 기반으로 작성되었다. 크게 UI 레이어와 도메인, 데이터 레이어로 구분 되어있는데, now in android에서는 ui/data layer를 포함하고 있다. 오랜 기간 개발했지만 도메인 영역까지 필요한 경우가 많지는 않았다.

Slide 8

Slide 8 text

구글 가이드 아키텍처? UI는 일반적인 View와 ViewModel로 이루어져 있고, Data Layer는 Repository를 활용하고 있다. 여기에 Retrofit을 활용한 RemoteDataSource, Room과 DataStore(Protobuf)를 활용한 LocalDataSource로 분리되어 있다.

Slide 9

Slide 9 text

Now in android 아키텍처는? Now in android의 전체적인 아키텍처이다. 큰 차이는 없다.

Slide 10

Slide 10 text

Module은 왜 나눌까?

Slide 11

Slide 11 text

Module은 왜 나눌까? ● 기존 Package 단위의 개발에서 모듈 단위의 개발로 진화 ● 모듈을 통한 개발 시 수정하지 않은 모듈은 리빌드 필요치 않음 ● 코드 분할의 목적 ● 모듈 단독으로 다른 프로그램 개발에서 활용 가능 Module은 왜 분리하는 것일까? 개발 성능 향상을 위함과 코드 분할의 목적이 가장 크다. package로도 코드는 분리할 수 있지만, 필요치 않는 디펜던시와 빌드 속도도 개선할 수 있다.

Slide 12

Slide 12 text

Now in android Module은 어떻게 나눴을까?

Slide 13

Slide 13 text

Module은 어떻게 나눴을까? - App ● app a. Main app ● app-nia-catalog a. UI 확인용 앱 Now in android는 크게 2개의 앱으로 분리되어 있는데, Main 앱과 UI 확인용 앱으로 모듈을 분리하였다. 각각 필요한 모든 모듈을 불러와 조합하는 형태로 구성되어 있다.

Slide 14

Slide 14 text

Module은 어떻게 나눴을까? - Core ● core - 베이스 코드를 담고 있다 a. common b. network/model 관련 c. UI 관련 Now in android의 core는 common, network/model과 UI 관련을 코어로 두고 있다. core-model은 전체에서 사용되고 있다.

Slide 15

Slide 15 text

Module은 어떻게 나눴을까? - Feature ● feature a. UI에 관한 feature b. 여기서는 Compose navigation 활용하여 구현 Now in android의 Feature는 compose navigation 활용하고 있으며, 이를 위해 core-navigation에 interface도 함께 활용하고 있다. 여기서는 모든 화면을 feature 모듈로 분리하여 사용하고 있다.

Slide 16

Slide 16 text

Module은 어떻게 나눴을까? - ETC ● ETC a. Lint - DesignSystem에 대한 lint 룰 체크 b. Sync - CoroutineWorker 활용 데이터 동기화 활용 c. build-logic - kotlin 문법을 활용한 plugin 구현 가능(buildSrc와 동일) i. id(“nowinandroid.android.library”) ii. id(“nowinandroid.android.library.jacoco”) 그 외 부분으로 lint, sync, build-logic 등이 있다. build-logic는 buildSrc와 동일한데 코틀린 기반의 plugin 코드 작성을 하기 위함이다.

Slide 17

Slide 17 text

모듈별로 담고 있는 내용 확인

Slide 18

Slide 18 text

Core - common ● Dispatcher 매핑 ● API Result에 대한 ○ sealed interface ○ Flow 확장 함수

Slide 19

Slide 19 text

의존성 관계 Core 모듈 간의 의존성을 먼저 살펴보면 다음과 같다. 결국 모든 모듈은 core-data에서 활용됨을 알 수 있다.

Slide 20

Slide 20 text

Core - network ● 네트워크 관련 ○ Retrofit ○ Api 정의 ● Response data 관련 클래스 모음 Network 모듈인데 여기서는 네트워크의 베이스뿐 아니라 Remote data struct까지도 포함하는 형태로 개발되어 있다. 네트워크 모듈은 네트워크 통신에 관한 부분을 제외한다고 한다면 remote data struct가 여기에 위치하지는 않을 것 같다.

Slide 21

Slide 21 text

Core - model ● 이 앱에서 사용할 모델을 정의하고 있음 여기서는 모든 앱에서 사용할 모든 모델을 모아두었다. UI와 core 등 모든 곳에서 활용된다. 단순히 View와 ViewModel 사이의 데이터 역시 여기에 위치하고 있는데, 여기에 정말 필요할지 적용 시 고민이 필요하다.

Slide 22

Slide 22 text

Core - database ● Room 활용 ● 여기서의 entity는 Room의 entity Database인 Room을 활용하고 있다. 여기서의 entity는 room 한정이며, 이를 외부로 돌려줄 때는 core-model의 데이터를 참고한다.(이 부분은 core-data에서 entity 복사를 진행한다.)

Slide 23

Slide 23 text

Core - datastore ● Datastore-protobuf 활용 ○ protobuf는 리빌드 필요하다는 단점 ○ Protobuf 정의 시 Protobuf 사용에 대한 이해 필요 ● DatastoreProtobuf 대신 DataStorePreference 활용 가능 ● Coroutine -Flow에 대한 이해도가 필요 ○ Flow 끝에 first()를 붙임으로써 suspend 하도록 변경 가능 DataStore로 protobuf를 활용하고 있다. Protobuf가 익숙하다면 매우 쉽게 활용이 가능하다.

Slide 24

Slide 24 text

Core - data ● Response Model to entity() ● Repository 정의 Data에서는 Repository에서 remote(network 모듈), local(database, datastore 모듈)을 참고하고 있다. 그리고 데이터는 model의 정의한 값을 참고하여 다시 리턴 시킨다.

Slide 25

Slide 25 text

의존성 관계 이번엔 ui와 관련한 디펜던시이다. 여기서도 core-model을 활용하고 있음을 알 수 있다. 크게 디자인 시스템은 정말 코어 한 UI이고, ui는 LazyColumn 등에서 활용할 공통 UI를 정의하고 있다.

Slide 26

Slide 26 text

Core - designsystem ● Now in android에서 활용할 compose 기반 디자인 시스템 ● 애니메이션을 포함하거나, 내부 UI 활용 위한 매핑 ● 이 경우 Font 적용 내부 theme 적용 등을 할 수 있다. ● 컴포즈 활용 시에는 이런 매핑 함수를 미리 만들어 활용하는 게 좋다. ○ Android Compose Component - mapping. - Speaker Deck 디자인 시스템과 관련한 부분은 필요한 경우 모두 fun 매핑을 하고 있다. 이렇게 매핑이 필요한지는 이전에 발표했던 자료에서도 이야기했지만 포함하는 것을 추천한다. 당장 디자인 시스템이 없더라도, 개발의 편의성을 고려해 주면 좋다.

Slide 27

Slide 27 text

Core - ui ● UI 모듈에서는 공통으로 활용하는 UI 매핑을 추가 ● 디펜던시로 core-designsystem과 core-model 활용 UI는 list 데이터를 포함한다고 보면 된다. 여기서는 core-model을 포함한다.

Slide 28

Slide 28 text

Core - navigation ● 내비게이션의 router 처리를 위한 interface 정의 router의 navigation interface 통신을 위한 정의를 하고 있다.

Slide 29

Slide 29 text

Feature - UI Layer

Slide 30

Slide 30 text

Feature ● 컴포즈 기반의 UI 모듈 ○ 화면 단위로 분리할 수 있다 ● Now in android에서는 main 제외 한 5개의 feature 포함 ○ feature에는 Navigation 기반의 작업 ○ Main의 NavHost에서 feature 모듈을 불러 활용 feature는 컴포즈 navigation을 기반으로 작업되어 있고, 5개의 화면들로 구성되어 있다. 현실에서는 원 activity 구성은 매우 많은 고민을 해야 한다. 화면 간 이동과 데이터 처리, 데이터 유지 등등 고민할 부분이 매우 많기 때문에 이와 같은 작업은 사전 검토를 꼭 해야 한다.

Slide 31

Slide 31 text

여기서 생기는 궁금증

Slide 32

Slide 32 text

이런 모듈 형태 설계는 One Activity 구성이 필수인가?

Slide 33

Slide 33 text

One Activity 구성이 필수인가? ● 모듈은 단독으로 동작할 수 있는 화면도 존재할 수 있다. ○ Activity 모듈을 만들면 바로 실행할 수 있는 환경으로의 코드 분리도 가능 ● 이런 모듈을 app으로 묶으려면? ○ Hilt, Dagger 활용으로 쉽게 구성 가능 ● One Activity를 활용 한다면? ○ 메모리 관리, 설계 모두 잘 할 수 있다면 도전! ○ One Activity의 라이프 사이클은 앱의 생명 주기와도 같을 수 있다. ● Compose navigation의 생명주기와 Activity 생명주기는 같지 않다. ○ Navigation 사용 시에는 뷰 변경에 따른 lifecycle이 다르다. One Activity는 꿈에 가깝다고 생각한다. 메모리 관리, 앱의 생명주기와 유사한 라이프 사이클, 화면 간 전환 시의 lifecycle 등등 고민하고 적용하여야 할 부분이 매우 많다. 화면 간의 네비게이션 역시 고민이 필요하다. 개인적으론 이런 설계는 고민이 많이 필요하고, 관리의 어려움 등을 고민해야 하여 고려치 않고 있다.

Slide 34

Slide 34 text

모듈 간 화면 전환이나 통신은?

Slide 35

Slide 35 text

모듈 간 화면 전환이나 통신은? ● Navigation을 활용한다면 NavHost에서 제공하는 방식 활용 ○ 데이터는 arguments를 통해 전달 ○ Repository를 활용한 데이터 전달 ● Navigation을 쓰지 않는다면? ○ Activity를 가진 모듈을 직접 등록하여 활용 ○ Router 개념을 도입하여 interface 형태로 접근 ○ https://github.com/android-alatan/LifecycleComponents/tree/main/_router 그렇다면 화면 간의 데이터 전환이나 데이터는 어떻게 하는 것이 좋을까? 이 부분은 기존 원 모듈 형태와 크게 다르지 않다. Activity의 데이터 전달 방법을 그대로 활용할 수도있고, 싱글 repository를 활용할 수도 있다. 다양한 방법이 있으니 그에 맞게 적용이 필요하다.

Slide 36

Slide 36 text

모듈이 많아진다면?

Slide 37

Slide 37 text

모듈이 많아진다면? ● 모듈의 증가는 폴더 구조를 필요로 한다 ● Now in android 샘플 앱에서도 모듈의 수는 23개 ○ 실제로 개발한다면 100개가 넘는 모듈 구성도 가능 ● 모듈을 나누는 전략이 필요 ○ 화면마다 feature를 나눌 것인가? ○ 공통 코드는 core에 담을 것인가? ○ 폴더 구조를 잘 잡아서 Project 형태로 펼쳐볼 것인가? 모듈 구조를 지속하면 모듈이 많아질 수 있다. 얼마나 많은 feature로 나눌 것인지도 고민이 필요하다. 그렇다면 적절한 모듈 관리 방법은 없을까? 오랜 기간 폴더 구조가 생각보다 익숙할 수 있다. 이에 대해 적용 방법을 알아본다.

Slide 38

Slide 38 text

Project 형태로 폴더를 나눠보자 ● Fold 하위 구조를 생성하여 사용 ○ Core 폴더 ■ Model 폴더 ■ Ui 폴더 ○ Feature 폴더 ■ 화면 단위의 feature를 여기 위치 먼저 core, feature 폴더를 구분하여 나누었다. 그리고 core 하위에 model과 ui 폴더를 한 번 더 분리하였다.

Slide 39

Slide 39 text

Project 형태로 폴더를 나눠보자 ● Fold 하위 구조를 생성하여 사용 ○ Core 폴더 ■ Model 폴더 ■ Ui 폴더 ○ Feature 폴더 ■ 화면 단위의 feature를 여기 위치 ● 하지만 폴더 만 나누면 빌드가 불가능 하지만 단순 폴더를 나누는 건 불가능하다. 추가 코드가 필요하니 다음 장을 참고하시길

Slide 40

Slide 40 text

Settings.gradle.kts 코드 추가 왼쪽부터 차례대로 rootProject/settings.gradle.kts에 추가해 주면 되겠다.

Slide 41

Slide 41 text

Settings.gradle.kts 코드 추가 마지막으로 찾은 하위 폴더를 모두 projectDir에 연결시켜준다.

Slide 42

Slide 42 text

● 폴더 이름은 알아보기 편한 방법을 활용할 수 있다. ○ _ 형태로 사용 중 코드 적용 후 동기화 https://github.com/taehwandev/nowinandroid/tree/directory_ref 폴더 구조를 잘 잡아두면 나중에 폴더 찾기가 더 쉬워질 수 있다. 개인적으로는 _를 추가로 붙여 활용하고 있다.

Slide 43

Slide 43 text

Build.gradle 관리도 중요하다

Slide 44

Slide 44 text

Build.gradle 관리도 중요하다 ● 모듈을 생성함과 동시에 build.gradle 중복 코드 증가 build.gradle의 관리도 중요한데 모듈이 많아지면 동시에 build.gradle의 코드 양도 증가한다.(동일한 형태의 모듈이 만아지면, 코드 역시 동일하게 증가하기 때문이다.)

Slide 45

Slide 45 text

Gradle plugins을 활용한 관리 ● plugins에 id(“xxxx”) 형태로 추가하여 관리할 필요성이 있다. Now in android에는 build-logic이 포함되어 있는데 이를 활용하면 plugin을 만들어 활용할 수 있다.

Slide 46

Slide 46 text

buildSrc vs build-logic ● buildSrc ○ 기존 gradle에서 제공하던 방식 ○ gradle.kotlin과 gradle 사용 가능 ○ kotlin-dsl-precompiled-script-plugins을 활용하면 id(“xxx”) 형태의 플러그인 가능 ● build-logic ○ buildSrc와 차이는 크지 않음 ○ Kotlin 문법으로 plugins 추가 가능 ● 디펜던시 버전 관리 ○ libs.versions.toml을 활용하고, 위 2곳 모두에서 활용 가능 지금까지는 buildSrc를 활용하고 있었다. 그럼 변경해야 할까? 그렇지는 않다. buildSrc와 build-logic의 차이는 kotlin 문법 만으로 plugin 개발이 가능하느냐의 차이다. 상수를 활용하는 경우 성능 차이가 살짝 있을 수 있지만 이는 gradle version catalog를 활용하여 해결할 수 있다. 그럼 결론적으로 모든 기능은 동일하다.

Slide 47

Slide 47 text

buildSrc ● buildSrc로도 plugin 구현 가능 ○ 필요한 디펜던시는 build.gradle.kts에 추가 ● Version controller 활용 동일 ● gradle.kts script 생성 시에는 package는 명시하지 않음 buildSrc에 kotlin-dsl-precompiled-script-plugins을 추가하여 gradle을 생성해 줄 수 있다. 이때 package는 명시하지 않아야 한다.

Slide 48

Slide 48 text

build-logic ● 필요한 plugin을 추가 가능 ○ 디펜던시 추가도 필요(build.gradle.kts) ● Version controller 활용 동일 ● Plugin 정의 시 package는 명시하지 않음 build-logic도 모두 동일하다. Plugin 정의 시에는 package 이름을 명시하지 않아야 한다.

Slide 49

Slide 49 text

build-logic vs buildSrc 왼쪽이 build-logic 오른쪽이 buildSrc이다. 전부 동일한 형태라 편한 방법으로 작업하시길

Slide 50

Slide 50 text

Kotlin extension 역시 가능 두 방법 모두 kotlin extension 활용이 가능하다. 이 방법으로 동일한 dependency를 줄여주는 방법 역시 가능하다.

Slide 51

Slide 51 text

plugins 활용 시 build-logic은 Plugin 명칭을 build.gradle.kts 파일에 별도 매핑하고 있고, buildSrc는 적어준 이름에서 뒷부분을 제외하고 파일 명칭을 그대로 활용한다.

Slide 52

Slide 52 text

여기까지 [email protected] https://thdev.tech/ https://github.com/taehwandev/