はじめに
こんにちは!
先日、Jetpack Composeでシンプルなメモアプリを完成させたのですが、今のままではアプリを閉じるとデータが全部消えてしまいます。これではただの儚い夢ですね(笑)。
Jetpack Compose初心者がメモアプリ実装でつまずいた3つの壁とその乗り越え方
そこで今回から、このアプリにデータの永続化機能を追加していきます。
この記事では、その第一歩として**「何を」「どういう思想で」作るのか**という、要件定義と基本設計のプロセスをログとして残します。
なぜRoomを選ぶのか?Repositoryパターンって導入するとどんないいことがあるの?といった、設計の「WHY」の部分にフォーカスしてまとめてみました。
1. なぜやるのか?何をやるのか?(要件定義)
実装に入る前に、まず「なぜこの機能が必要で、具体的に何を実現したいのか」を明確にします。これがあやふやだと、後で「あれ、何作りたかったんだっけ?」と迷子になってしまいますからね...。
1.1. なぜやるのか? (Why)
-
現状の課題: 今のアプリは、メモを
ViewModel内のただのリストで管理しています。これは「メモリ」という名の、電源を切ると全てが消える**「一時的な作業机」**の上にメモを置いているようなものです。これでは、ユーザーがせっかく書いたメモも、アプリを閉じれば跡形もなく消えてしまいます。 - 目指す姿: アプリに**「記憶力」**を持たせ、一時的なおもちゃから、ユーザーが安心して使える本物のツールへと進化させたい。これが今回の機能追加の根本的な動機です。
1.2. 何をやるのか? (What)
上記の「Why」を実現するために、以下の2つの機能要件を定義します。
- データの保存: ユーザーが新しいメモを追加した時、そのメモはアプリを完全に終了しても消えないように、端末内に永続的に保存されること。
- データの読み込み: ユーザーがアプリを起動した時、以前に保存した全てのメモがリストに表示されること。
2. 「どう作るか」の骨格を決める(基本設計)
やりたいことが決まったので、次はそれを実現するための「骨格」となるアーキテクチャと技術選定を考えます。
2.1. データベースの選定:「Room」一択な理由
Androidでデータをローカルに保存する方法はいくつかありますが、今回はGoogleが公式に推奨するデータベースライブラリ**「Room」**を採用します。
Roomのメリットは数多くありますが、特に僕が好きなのはコンパイル時のSQLチェックです。SQLのクエリを間違えると、アプリがクラッシュする実行時ではなく、コードを書いているコンパイルの時点で「このクエリ間違ってるよ!」と教えてくれます。この安心感は計り知れません。
2.2. アーキテクチャの進化:Repositoryパターンという名の「司書」を雇う
これが今回の設計の肝です。
今までのViewModel→データ操作というシンプルな構成から、間に**Repository(リポジトリ)層**という新しい階層を設けます。
Repositoryは、ViewModelとデータ層(今回はRoom)の間に立つ、いわば**「データの司書」**です。
-
ViewModel(シェフ)の仕事: 「こういうデータが欲しいんだけど」と、Repository(司書)に依頼するだけ。 -
Repository(司書)の仕事: 依頼されたデータがどこにあるかを知っている。今回はRoom(書庫)からデータを探してきて、ViewModelに渡す。
この司書を雇うことで、ViewModelはデータベースの細かい仕組みを知る必要がなくなり、「UIに表示する状態を作ること」という本来の仕事に集中できます。この疎結合な設計が、アプリを長期的にメンテナンスしやすくする鍵なんですね。
2.3. プロジェクト構成とViewModelの進化
この新しいアーキテクチャに合わせて、パッケージ構成とViewModelの役割も進化します。
com.example.simplememoapp_android
│
├─ data
│ ├─ local <-- ★NEW! (ローカルDB専門の部屋)
│ │ ├─ dao
│ │ │ └─ MemoDao.kt
│ │ └─ AppDatabase.kt
│ │
│ ├─ model
│ │ └─ Memo.kt
│ │
│ └─ repository
│ └─ MemoRepository.kt <-- ★NEW! (データの司書)
│
└─ ui
└─ ...
└─ viewmodel
└─ MemoViewModel.kt <-- ★進化!
ViewModelはどう進化するのか?
- BEFORE: 自分でリストを管理する、何でも屋の店長。
-
AFTER:
Repository(司書)に全てを任せる、司令塔としてのシェフ。
具体的には、今までViewModel自身がMutableStateFlowでメモのリストを管理していましたが、これからは**RepositoryからFlowで流れてくるデータストリームを、UiStateに変換してUIに渡すだけ**という、より宣言的でシンプルな役割に変わります。ViewModelは、データの「保管場所」を一切意識しなくなります。
まとめ
というわけで、今回はアプリに「記憶」を与えるための、設計の「WHY」の部分を整理してみました。
- ユーザーが安心して使えるツールにするために、データを永続化する。
- その手段として
Roomを使い、安全かつモダンに実装する。 Repositoryパターンを導入して、関心を分離し、見通しの良い設計にする。
この骨太な設計方針を元に、次回は**「じゃあ具体的にどうコードを書くの?」という、実装レベルの詳細設計**の記事を書いていこうと思います!
ここまで読んでいただきありがとうございました!
