「ロジックとデータの一体化」とは
以前、私が所属するコミュニティでプリンシプルオブプログラミング輪読会を行なっていました。
プリンシプルオブプログラミングとはその名の通り、プログラミングをする上で原理原則となるような概念や知識が書かれている名著です。
その本の3.7章(p74)に「ロジックとデータの一体化」というテーマがあります。
その章の内容を要約すると以下の通りです。
- データとその操作は近くに
- ロジックとデータをコード上で近くに配置する
- データと操作は修正タイミングが同じだから
当時の私
この章を読みたての頃は、自分の経験に落とし込めていなかったので、あまりよく理解できていなかったです。
具体的にはこのような疑問が頭に浮かんでいました。
- この文脈でいうデータってなに?
- ロジックって例えば?
- 近くに置くってどういうこと?
Androidで言うとこういうこと!
最近個人開発をしていて、やっと経験に落とし込めたので共有します!
結論から言うと、「ロジックとデータの一体化」はUIStateを適切に実装する上で必要な考え方です。
[前提]
-
ViewModel
…データがあるところ、UIに表示する要素の状態(state
)を保持しているところ→state holder -
UIState
…データ(表示する要素)を持っているクラス
この前提を踏まえると、「データを加工するロジックをデータの近くに置く」を、「データを加工するロジックをUIStateに書く」と言い換えることができます。
例えば以下は実際に私が個人開発を通して実装したコードです。
これは、connpass上からAndroid/kotlinに関連するイベントを選択して表示するアプリで、各イベントにいいねも押すことができます。
従って、以下のソースコードにあるevent
は取得してきたconnpass上のイベントのことで、isFavorite
はいいねの状態を保持するデータです。
// EventViewModel
data class EventItemUiState(
val event: Event,
val isFavorite: Boolean
) {
// 取得してきたイベント開始日から「月」のデータを取得
// 「◯月」みたいな表示になるように取得したデータの後ろに「月」を付ける
private val calendar = Calendar.getInstance().also {
it.time = event.startedAt.date
}
val month = calendar.get(Calendar.MONTH).toString() + "月"
}
この実装で言うと「データを加工するロジック」とは、取得してきたイベントの開催日程から「月」のデータを取得して、「○月」みたいな表記にするロジックです。
データ(UIStateで保持されているデータ)を加工するロジックを、データの近く(UIState内部)に書いております。
もしデータとロジックが別々の場所にあったら?
そもそもどうして「ロジックとデータの一体化」を実現しなければいけないのでしょうか。
もしデータとロジックが別々の場所にあったら何か困ることがあるのでしょうか。
他の場所でも同じロジックを使いたいとなった場合コピペになる。
もしロジックに変更が入った場合、同じロジックが複数箇所に散らばっていると、
全てのロジックを修正するのが難しくなり、バグが生じる可能性があります。
ここで、同じロジックを使いたいだけなら関数に切り分ければいいのでは?となりますが、
下手な関数を作成して、使用者が「この関数を使うのが適切かどうか」の判断を行わなければいけない状態になると、コードの品質が開発者の腕前に左右されてしまいます。
まとめ
- 「データとデータを加工するロジックは近くに置こう」とはAndroidでいうと、「画面に表示したいデータを加工するロジックはUIStateに書こう」ということ。
- データとデータを加工するロジックを近くに置くと、UI層がデータ加工ロジックで汚れないので可読性が上がる
- 同じロジックを使い回す時にも有効
Qiitaのアドカレ初めて参加しました!
読んでくださりありがとうございました!!