はじめに
Googleが公式に公開しているサンプルアプリNow in Androidは、Jetpack Composeを前提としたモダンAndroidアプリの設計・実装例として知られています。
一方で、コード量やモジュール数も多く、「どこから読めばいいのか分からない」と感じる人も多いのではないでしょうか。
そこでこの記事では、投稿日時点のNow in Androidの実装をベースにAndroidエンジニアが設計観点で一度は目を通しておくとよいポイントを3つに絞ってまとめてみたいと思います。
① UI Stateを型で表現し、単方向データフローを徹底している点
Now in Androidでは、Composeを前提としたUI State設計が非常に丁寧に行われています。
代表的な例が、Topic画面のViewModelです。
実装例(抜粋)
sealed interface TopicUiState {
data object Loading : TopicUiState
data class Success(
val followableTopic: FollowableTopic,
val news: List<UserNewsResource>
) : TopicUiState
}
UI が取り得る状態をsealed interfaceで明示し、
- ローディング中
- データ取得成功時
といった状態を型で制限しています。
ViewModel側では、Repositoryから取得したFlowをUI Stateに変換しています。
val topicUiState: StateFlow<TopicUiState> =
combine(
getFollowableTopic(topicId),
getTopicNewsResources(topicId)
) { followableTopic, news ->
TopicUiState.Success(
followableTopic = followableTopic,
news = news
)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = TopicUiState.Loading
)
この構成により、
- UIはStateを受け取って描画するだけ
- ロジックはViewModelに閉じる
- 状態遷移がコード上で追いやすい
といったメリットが得られます。
Composeを使ったプロジェクトでは、「まず UI State をどう定義するか」を考える重要性を再確認できる実装です。
② Repositoryが「データの組み立て役」に徹している点
Now in AndroidのRepository設計は、抽象化をやりすぎず、現実的な責務分離がされているのが特徴です。
実装例(抜粋)
interface NewsRepository {
fun getNewsResources(
filterTopicIds: Set<String> = emptySet()
): Flow<List<UserNewsResource>>
}
RepositoryはFlowを返すだけのシンプルなAPIを公開しています。
実装側ではLocal DBやUserDataを組み合わせて、UIが使いやすい形にデータを整形しています。
override fun getNewsResources(
filterTopicIds: Set<String>
): Flow<List<UserNewsResource>> =
combine(
newsResourceDao.getNewsResources(),
userDataRepository.userData
) { newsResources, userData ->
newsResources.map { news ->
UserNewsResource(
newsResource = news,
isSaved = news.id in userData.bookmarkedNewsIds
)
}
}
ここで注目したいのは、
- ViewModel側でデータ加工をさせない
- Repositoryが「取得+組み立て」を担う
- UseCase層を無理に挟まない
という設計判断です。
理論的なClean Architectureというより、壊れにくさと読みやすさを優先した構成になっており、実務プロジェクトにそのまま応用しやすい形だと感じます。
③ モジュール分割と依存方向が非常に明確な点
Now in Androidは、モジュール分割が進んでいるサンプルとしても有名です。
ただし、目的なく細分化されているわけではありません。
構成を見ると、
-
feature/*:画面・機能単位 -
core/*:データ・共通ロジック -
app:アプリ全体のエントリーポイント
という、責務ベースの分割になっています。
featureモジュールはRepositoryインターフェースに依存し、NetworkやDBの実装詳細には触れません。
この構造により、
- feature単位でのテストがしやすい
- 変更の影響範囲が限定される
- 将来的な差し替えや拡張がしやすい
といったメリットが得られます。
一方で、「将来のために分けすぎる」設計にはなっておらず、現時点で必要な粒度に留めている点も実践的です。
まとめ
Now in Androidは最新技術を詰め込んだサンプルというよりも、
- UI Stateを中心とした単方向データフロー
- 現実的なRepository設計
- 責務が明確なモジュール分割
といった、長期運用を意識した設計判断が随所に見られるプロジェクトです。
すべてを読み込む必要はありませんが、今回挙げたポイントに絞ってコードを追うだけでも日々の設計を見直すヒントになると思います。
さいごに
これだけの規模と内容のサンプルが無料で公開されているのは、かなり恵まれているなと感じます。
コードを追っていると意外と時間が溶けるので、読書代わりに眺めるのも良いですね。
設計に迷ったタイミングで、一度コードを眺めてみるとヒントが見つかるかもしれません。