안드로이드 앱 개발의 즐거움

2025-04-189 분 소요0

시리
시리니

요즘 저는 안드로이드 앱 개발에 빠져 있습니다. TSBOARD로 개발하여 운영중인 저의 첫 커뮤니티, sensta.me 사이트 사용자분들을 위한 안드로이드 전용 앱을 만들고 있는데, 정말 재밌습니다. TSBOARD를 만들면서 접했던 여러 개념들이 비슷하게 등장하는 것도 신기했는데, 타입스크립트와 Go 언어에 이어서 코틀린 언어의 매력에 허우적거리는 제 모습이 낯설기도 하고 신기하기도 합니다. 그 중에서도 안드로이드의 클린 아키텍처는 정말 배울만하다는 생각이 들었습니다.


안드로이드 클린 아키텍처

안드로이드는 공식 아키텍처로 클린 아키텍처를 소개하고 있습니다. Presentation / Domain / Data 이렇게 크게는 3개로 모듈을 나눠서, 각각의 역할을 분리하는 것이 핵심입니다. 처음에는 별로 크지도 않은 앱을 만드는데 무슨 모듈을 3개씩이나 만들지? 라고 생각하고 그냥 하나의 모듈에서 개발을 했습니다만, sensta.me 앱을 만들면서 그게 아니라는 걸 금방 깨달았습니다.


저에게 있어 모듈을 나누는 가장 큰 이유라고 한다면, 약간 이상할 수 있는데 파일이 많아서라고 답하고 싶습니다. Presentation 모듈이 UIViewModel 부분을 담당하고 있는데, 여기도 Jetpack Compose기반으로 앱을 만들다보면 목적에 따라서 여러 컴포저블 함수들이 생성되고, 대부분은 별도의 파일에 속하게 됩니다. 당연히 파일도 엄청 많아지고 덩달아서 파일들을 패키지로 묶어야 하니 패키지도 많아지게 됩니다. 충분히 하나의 독립된 모듈로 빼둘만 하더라구요.


Domain 모듈의 경우 설계상 순수 코틀린 언어로만 작성이 필요합니다. 안드로이드 코드가 있어선 안되고, 원칙적으로는 외부 라이브러리에 의존하지 않습니다. 이곳에서는 리포지토리의 인터페이스들을 정의하고, 모델들을 정의합니다. 그리고 UseCase라고 부르는 것들을 작성하는데, 하나의 UseCase를 보통 하나의 파일에 저장하니까 이 역시도 파일이 많아질 수 밖에 없습니다. 여러 모델들과 리포지토리 인터페이스, 그리고 ViewModel에서 기능 호출할 때 사용하는 UseCase까지 파일이 많아지니까 자연스럽게 이걸 하나의 독립된 모듈로 구성하는 게 낫겠다는 생각이 들더군요.


Data 모듈은 실질적으로 데이터 입출력과 관련된 일들을 하는 곳이고, Domain 모듈에서 정의해둔 리포지토리 인터페이스들을 구현하는 곳이니만큼 당연히 파일들이 많아집니다. 특히 저의 경우는 앱 자체가 외부 서버에서 JSON 타입의 데이터를 가져와야 하다보니 JSON 타입과 매칭되는 DTO를 여기서 정의해 두었습니다. DTO가 거의 대부분 모델과 일대일 매칭이 되므로 역시 파일이 많아집니다. 결국 독립된 모듈로 구성하는 것이 정답이었다고 할 수 있습니다.


마법같은 Coroutine

안드로이드 앱은 사용자에게 보여지는 UI가 있고, 해당 UI에서 특정 버튼이나 행위(예: 스크롤)를 했을 때 그에 맞춰 동작이 일어나야 합니다. 때로는 시간이 소요되기도 하겠죠. 그러나 어떠한 경우에도 사용자의 UI는 멈춰선 안됩니다. 버튼을 터치했을 때 날씨를 가져와서 보여준다고 가정하면, 날씨 데이터는 결국 인터넷 망을 통해서 가져와야하니 시간이 걸리게 됩니다. 가령 5초가 걸렸다고 합시다. 이 때 안드로이드 앱의 화면 여기저기를 터치하거나 했을때 먹통이 되어버린다면 어떨까요? 당연히 해당 앱은 쓸 수 없는 앱이 됩니다.


이걸 막기 위해서 코틀린은 코루틴(Coroutine)을 지원하고 있습니다. 이게 참 신기하게도, TSBOARD를 개발하면서 백엔드를 Go언어로 재작성 할 때 이미 고루틴(Goroutine)을 맛본 상태라 다행히 개념이 어렵진 않았습니다. 고루틴이 언어 자체적으로 지원하는 기능이라는 점과 사용이 훨씬 쉽다는 점을 제외하면, 코틀린 언어의 코루틴도 정말 훌륭한 동시성 구현이라고 생각합니다.


안드로이드 앱 개발을 할 때는, UI에서 특정 버튼이 터치되었다고 가정해보면, 해당 버튼의 onClick 이벤트 리스너에서는 ViewModel의 특정 함수를 호출하고, 해당 함수는 내부적으로 viewModelScope.launch { … } 블럭을 실행하면서 그 블럭 안에서 UseCase를 호출하도록 보통 구현한다고 합니다. 저도 조금 생소하긴 했었는데, 몇번 하다보니 금새 익숙해 졌습니다.


    // 개별 알림 확인 처리하기
    fun checkNotification(notiUid: Int) {
        viewModelScope.launch {
            val user = getUserInfo()
            if (user.token.isEmpty()) {
                return@launch
            }

            checkNotificationUseCase(user.token, notiUid).collect {
                if (it is TsboardResponse.Success) {
                    loadNotifications()
                }
            }
        }
    }


viewModelScope.launch 블럭은 코루틴 영역이고, 기존 코드 흐름과는 별도의 영역에서 실행됩니다. 그리고 그 안에서 호출되는 UseCase는 보통 Flow를 반환하는데, collect 함수가 호출되면 그 때 emit 함수로 필요한 데이터를 가져옵니다. 저는 이 과정이 정말 굉장하다고 생각했는데, 일반적으로 Blocking을 하면서 데이터 받는 걸 기다리는 게 아니라, Non Blocking으로 메인 스레드를 막지 않으면서도 데이터를 가져오는 이 흐름이 정말 낯설면서도 한편으로는 익숙하다는 느낌을 받았습니다. TSBOARD를 처음 만들때 Node.js의 비동기 I/O 개념을 배운 게 여기서도 도움이 되더라구요.


Node.js의 혁신적이었던 비동기 I/O 동작과 콜백 기반의 처리, 그리고 Promise를 통해서 해소된 콜백 지옥… 이 배움들이 코틀린 언어의 코루틴을 사용하면서도 그대로 적용되었습니다. 코루틴에서도 새로운 코루틴 영역을 만들어주는 async {…} 블럭이 있고, await 함수를 통해서 비동기적으로 동작하는 함수들의 실행 결과를 기다렸다가 받아서 처리할 수도 있었습니다. 타입스크립트와 Node.js 그리고 Bun과 함께했던 시간들이, Go언어와의 시간들이 헛되지 않고 계속해서 새로운 배움의 마중물이 되어준 것입니다.


만족스러운 네이티브 앱의 성능

안드로이드 앱 개발을 즐겁게 만들어주는 가장 마지막 요소라고 한다면, 단연 네이티브 앱이 보여주는 성능이 아닐까 싶습니다. 물론 Flutter와 같은 크로스 플랫폼 개발 프레임워크가 여러 장점들이 있다는 것을 잘 알고 있습니다. Dart 언어 역시 훌륭하고, 지금 생각해보니 Flutter의 선언형 UI 개념들이 Jetpack Compose에서도 자연스럽게 이어지는 것 같다는 생각이 들었습니다.


그러나, 크로스 플랫폼을 위해 별도의 UI 엔진을 불러와야하고, 코틀린이 아닌 Dart 언어로 개발해야 한다는 점 등이 조금 걸렸습니다. Dart 언어는 물론 훌륭한 언어이고, 한 때 자바스크립트를 대체하기 위해 야심차게 소개된 것도 알지만 현실적으로 Flutter외에는 잘 안쓰이는 언어이다보니 배우고 싶다는 동기부여가 잘 안되었다는 점도 말씀드리고 싶습니다. 초기 로드 외에도 네이티브 앱이 조금이라도 더 빠릿하게 반응하고 더 부드럽게 애니메이션을 해주며 더 빠르게 데이터를 처리하지 않을까 하는 믿음도 있습니다. ㅎㅎ


그런 관점에서, React Native는 애초에 고민하지도 않았습니다. 웹 기반 기술은 브라우저가 가장 적합한 플랫폼이라고 생각합니다. TSBOARD의 경우 지금까지 타입스크립트를 계속 사용했었고, 한 때 백엔드에서도 썼던 만큼 안드로이드 앱을 만든다고 하면 가장 좋은 선택지가 React Native입니다. 하지만 지금 다시 생각해보면, 오히려 React Native를 선택하지 않은 덕분에 코틀린 언어에 대해서 알게 되고 기존에 배우고 써왔던 다른 언어와의 공통점들도 발견하게 될 수 있었습니다. 결정적으로 Flutter와 비교했을 때 성능 차이가 확연히 드러났을거라 생각합니다.


딱 한가지 아쉬운 점은, vscode를 사용할 수 없다는 점입니다. 엄밀히 말해서 쓸 수 없는 것 까지는 아니지만, 안드로이드 스튜디오가 압도적으로 개발 생산성이 좋습니다. 딱 이 점만 제외하면, 코틀린 언어와 함께하는 안드로이드 앱 개발은 정말 즐거운 여정입니다.


곧 소개하겠습니다 : Sensta 앱

TSBOARD 기반 커뮤니티에서 쉽게 활용 가능한 안드로이드 앱, Sensta 프로젝트는 GitHub에 전체 코드를 공개(https://github.com/sirini/sensta)하고 있습니다. 우선은 sensta.me 사이트 사용자분들을 위해서만 개발되고 있지만, TSBOARD로 운영되는 그 어떤 커뮤니티에서도 쉽게 활용 가능합니다. 1차 목표는 4월 30일까지 구글 플레이에 등록 가능한 수준으로 만들어보는 것인데, 잘 될 수 있도록 응원을 부탁드리겠습니다!

sensta
android
app
kotlin
coroutine
native
flutter
dart

최근 댓글들