Jetpack Compose는 선언형 UI 프레임워크로, 기존 View 시스템과는 완전히 다른 방식으로 화면을 그린다. Compose의 렌더링 파이프라인을 이해하면 성능 최적화와 버그 해결이 훨씬 수월해진다. Compose는 크게 세 단계로 화면을 그리는데, Composition, Layout, Drawing 순서로 진행된다. Composition 단계Composition은 UI 트리를 구성하는 첫 번째 단계다. 이 단계에서 Composable 함수들이 실행되면서 UI의 구조가 결정된다.@Composablefun MyScreen() { Column { Text("Hello") Button(onClick = {}) { Text("Click") ..
안드로이드 모니터링 서비스를 개발하면서 시계열 데이터를 시각화할 필요가 생겼다. MPAndroidChart 같은 라이브러리도 있지만, Jetpack Compose 환경에서 View 기반 차트를 사용하면 AndroidView로 감싸야 하는 번거로움이 있었다. 더 중요한 건, 우리 디자인 시스템에 맞는 커스텀한 인터랙션과 스타일이 필요했다는 점이다. 그래서 Canvas API를 활용해 직접 라인 차트를 구현하기로 결정했다. 기술 스택과 핵심 요구사항Jetpack Compose의 Canvas API와 DrawScope를 기반으로 차트를 그리기로 했다. 주요 요구사항은 다음과 같았다.시계열 데이터를 부드러운 라인으로 연결터치 시 해당 지점의 상세 정보를 툴팁으로 표시평균값을 점선으로 표시최대/최소값 자동 표시 ..
Jetpack Compose에서 부수 효과(side-effect)는 선언형 UI와 비동기 작업, 외부 시스템과의 상호작용을 안전하게 연결해주는 핵심 메커니즘이다. Compose의 철학은 상태(state)를 기반으로 UI를 재작성(recomposition)하는 것이지만, 실제 앱에서는 데이터 요청, 리스너 등록, DB 저장, 로그 기록 등 UI 외부에서 발생하는 다양한 효과를 동반해야 컴포넌트간 연결과 자연스러운 UX를 제공한다. Compose에서 Side-effect의 필요성과 주의점Compose는 함수형 패러다임을 지향하나, 앱은 네트워크 통신이나 DB 저장과 같이 상태(state) 외부의 세계에 계속 개입할 필요가 있다.Side-effect를 무계획적으로 사용하면 예기치 않은 recomposition..
모니터링 시스템의 인스턴스 상세 화면을 개발하면서, 동시에 여러 개의 메트릭 API를 호출해야 하는 상황이 있었다. 이 글에서는 그 과정을 실제 코드, 병렬 처리 원리, 그리고 성능 개선 수치와 함께 구체적으로 살펴본다. WHY — 왜 이 최적화를 했는가?문제 상황초기 구현은 아래처럼 완전히 순차적으로 API를 호출했다.val cpuMetrics = getCpuMetricsUseCase(instanceId, targetDate)val memoryMetrics = getMemoryMetricsUseCase(instanceId, targetDate)val networkReceiveMetrics = getNetworkReceiveMetricsUseCase(instanceId, targetDate)val net..
멀티 모듈 프로젝트를 개발하다 보면 각 모듈의 build.gradle.kts 파일에서 동일한 설정이 반복되는 문제에 직면합니다. 예를 들어 compileSdk, minSdk, Compose 설정, Hilt 설정 등이 모든 모듈에서 중복되어 관리 포인트가 늘어나고 일관성을 유지하기 어려워집니다. 이러한 문제를 해결하기 위해 Convention Plugin 패턴을 활용한 build-logic 구조를 도입하면 빌드 설정을 효율적으로 관리할 수 있습니다. build-logic이란?build-logic은 Gradle의 Composite Builds 기능을 활용하여 빌드 로직을 별도의 독립적인 Gradle 프로젝트로 분리한 구조입니다. 기존의 buildSrc 방식과 유사하지만, build-logic은 더 나은 빌드..
Stateful은 컴포저블이 remember 등으로 내부 상태를 보유하는 형태이고, Stateless는 상태를 보유하지 않고 외부에서 값과 이벤트를 주입받는 형태이며, State Hoisting은 상태를 호출자로 올려 Stateless로 만드는 패턴이다. 실제로는 상태를 읽고 쓰는 모든 컴포저블의 최저 공통 조상으로 상태를 끌어올리는 것이 권장되며, UI 논리와 비즈니스 논리에 따라 컴포지션 내부 또는 ViewModel까지 위치가 달라진다. 핵심 개념 정리Stateful: remember/mutableStateOf 등으로 내부에 상태를 저장하는 컴포저블로 재사용성과 테스트 용이성이 낮아질 수 있다.Stateless: 상태를 보유하지 않고 값과 이벤트를 매개변수로 받아 그리기만 하며, 상태 호이스팅으로 쉽..
오늘은 프로젝트에서 구현한 인증 시스템을 깊이 있게 분석해보자. 단순한 토큰 관리를 넘어, 동시성 문제, 메모리 캐시 전략, Race Condition 해결 등 실전에서 마주하는 복잡한 문제들과 그 해결책을 다룬다. AuthDataStore: DataStore의 확장 함수 패턴private fun Preferences.Key.flowIn(store: DataStore) = store.data.map { it[this] }private suspend fun Preferences.Key.saveTo(store: DataStore, value: String) = store.edit { it[this] = value }private suspend fun Preferences.Key.deleteFrom..
Feature-Driven Modularization(피처 중심 모듈화)은 안드로이드 멀티모듈 아키텍처에서 가장 강력하고 실용적인 설계 방식이다. 이번 포스팅에서는 피처 기반 모듈화의 철학부터 실제 구현 방법, 그리고 build-logic과 benchmark 모듈까지 포함한 부분을 공부한 내 나름대로 풀어보자. Feature-Driven Modularization이란?기본 개념과 철학Feature-Driven Modularization은 비즈니스 기능(Feature) 단위로 모듈을 구성하는 설계 방식이다. 전통적인 Layer-based 접근법과는 근본적으로 다른 관점을 제시한다. 전통적 Layer-based 접근법:app/├── data/ # 모든 데이터 로직├── domain/ ..
이전에도 MVI 구조를 정리했듯, "왜 이렇게 짰지?"를 다시 돌아보는 게 진짜 성장이라고 생각한다. 이번엔 프로젝트를 진행하면서 팀원들과 함께 만든 네트워크 매퍼/처리 유틸리티들을 코드와 이유를 함께 하나씩 해부한다. 1. 네트워크 결과를 Resource로 바꾸는 이유와 실제 코드문제: API 호출 결과가 성공/실패/에러 등 다양한 케이스가 있는데, 뷰 단에서 그걸 하나하나 분기 처리하면 코드가 지저분해진다.해결: NetworkResult → Resource로 변환해서 UI 레이어엔 언제나 Loading/Success/Failure만 보내줌으로써 단일 상태로 관리.fun apiResponseToResourceFlow( mapper: (T) -> R, call: suspend () -> Ne..
문제https://school.programmers.co.kr/learn/courses/30/lessons/299308 프로그래머스SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프programmers.co.kr 어떻게 풀 것인가?이 문제는 사실 QUARTER()과 CONCAT()를 알고 있냐 없냐를 물어보는 문제였다.QUARTER(): 날짜에서 분기를 추출하는 함수로, 1~4 값을 반환한다.1~3월: 14~6월: 27~9월: 310~12월: 4CONCAT(): 문자열을 연결하는 함수로, 분기 번호에 'Q'를 붙이는 데 사용한다. 이 2개를 활용하면 아주 쉽게 문제를 풀 수 있었다. 내 코드 SELECT CONCAT(QUARTER(DIFFERENTI..
최근 프로젝트에서 직접 적용했던 인사이트와 실제 코드 분석을 통해 얻은 깨달음을 공유하고자 한다.안드로이드 개발에서 앱 내부에 간단한 키-값 쌍 데이터를 저장하는 것은 필수적인 기능이다. 사용자 설정, 로그인 토큰, 앱 상태 정보 등을 로컬에 저장해야 하는 상황은 매우 빈번하게 발생한다. 전통적으로 이런 용도로는 SharedPreferences가 널리 사용되어 왔지만, 최근 구글에서는 Jetpack DataStore를 새로운 표준으로 제시하며 기존 SharedPreferences에서의 마이그레이션을 강력히 권장하고 있다.하지만 많은 개발자들이 "왜 굳이?"라는 의문을 가지는 것도 사실이다. 특히 성능 측면에서 SharedPreferences가 더 빠르다는 벤치마크 결과들이 나오면서, DataStore의 ..
이전에 MVI 패턴에 대해서 정리한 경험이 있지만, 당시에는 잘 몰랐고 무언가 투박했던 것 같다. 이에 다시 정리를 해보면서 프로젝트에서 적용했던 인사이트를 업로드하고자 한다.https://superohinsung.tistory.com/148 [Android] MVI 패턴이란?MVI 패턴이란 Android MVI 패턴은 Model-View-Intent의 약자로, 안드로이드 앱 개발에서 사용되는 아키텍처 패턴 중 하나입니다. MVI 패턴은 기존의 MVP, MVVM 등 다른 패턴과는 다르게 데이터 흐름이 단방향superohinsung.tistory.com Model-View-Intent (MVI) 패턴은 단순한 아키텍처 패턴을 넘어서 반응형 프로그래밍(Reactive Programming)과 함수형 프로그래..