JetPack Composeについて学んだことを徒然なるままに書いていく # フォルダ構成編

## はじめに
Jetpack Composeについて学びたいと思ったので、勉強がてら名刺アプリを個人開発してみました。その時に検討した内容を備忘録的に書いていきます。
この記事では、フォルダ構成検討時に学んだこととを書いてます。（時間があれば他のことも書いてみる予定）

## アーキテクチャーとフォルダ構成
Kotlinは、MVVM（Model/View/ViewModel）が主流のようなのでそのまま採用します。
ただ、UIロジックを分離させないとViewModel層がかなり肥大化するので、そこを考慮した上でフォルダ構成を考えてみました。

#### フォルダ構成
```
/app
├── /src
│   ├── /main
│   │   ├── /java/com/example/app
│   │   │   ├── /data
│   │   │   │   ├── /model
│   │   │   │   │   └── BusinessCard.kt
│   │   │   │   ├── /repository
│   │   │   │   │   └── BusinessCardRepository.kt
│   │   │   │   └── /network
│   │   │   │       └── BusinessCardNetwork.kt
│   │   │   ├── /domain
│   │   │   │   └── /usecase
│   │   │   │       └── RegisterBusinessCardUseCase.kt
│   │   │   ├── /ui
│   │   │   │   ├── /screen
│   │   │   │   │   ├── /home
│   │   │   │   │   │   ├── HomeScreen.kt
│   │   │   │   │   │   └── HomeViewModel.kt
│   │   │   │   │   ├── /detail
│   │   │   │   │   │   ├── DetailScreen.kt
│   │   │   │   │   │   └── DetailViewModel.kt
│   │   │   │   │   └── /profile
│   │   │   │   │   │   ├── ProfileScreen.kt
│   │   │   │   │   │   └── ProfileViewModel.kt
│   │   │   │   └── /component
│   │   │   │       ├── CustomButton.kt
│   │   │   │       └── CustomCard.kt
│   │   │   ├── /di
│   │   │   │   └── AppModule.kt
│   │   │   ├── /navigation
│   │   │   │   └── AppNavigation.kt
│   │   │   ├── /util
│   │   │   │   └── Constants.kt
│   │   │   └── MainActivity.kt
│   │   └── /res
│   │       └── /image
│   │       └── /icon
│   │       └── /values
```

## フォルダごとの役割
ここではそれぞれの役割について簡単に説明します。

#### Data層
<table>
    <tr>
      <th>フォルダ名</th> <th>説明</th>
    </tr>
  <tr>
    <td> model </td> <td>データ型を管理する</td>
  </tr>
  <tr>
    <td> repository </td> <td>データの取得先・取得方法を管理する</td>
  </tr>
  <tr>
    <td> network </td> <td>API通信などを管理する</td>
  </tr>
</table>

#### Domain層
<table>
    <tr>
      <th>フォルダ名</th> <th>説明</th>
    </tr>
  <tr>
    <td> usecase </td> <td>ビジネスロジックを管理する</td>
  </tr>
</table>

#### UI層
<table>
    <tr>
      <th>フォルダ名</th> <th>説明</th>
    </tr>
  <tr>
    <td> screen </td> <td>画面を管理する同じ階層にViewModelファイルも配置する</td>
  </tr>
  <tr>
    <td> component </td> <td>ボタンやダイアログなどのパーツを管理する</td>
  </tr>
</table>

#### DI層 (Dependency Injection)
<table>
    <tr>
      <th>フォルダ名</th> <th>説明</th>
    </tr>
  <tr>
    <td> di </td> <td>依存性の注入（Repository、ViewModelなどをまとめて組み立てる）
</td>
  </tr>
</table>

#### Navigation層
<table>
    <tr>
      <th>フォルダ名</th> <th>説明</th>
    </tr>
  <tr>
    <td> navigation </td> <td>画面遷移を管理する</td>
  </tr>
</table>

#### Util層
<table>
    <tr>
      <th>フォルダ名</th> <th>説明</th>
    </tr>
  <tr>
    <td> util </td> <td>よく使う定数や関数を管理</td>
  </tr>
</table>

#### Res層
<table>
    <tr>
      <th>フォルダ名</th> <th>説明</th>
    </tr>
  <tr>
    <td> image </td> <td>画像を管理する</td>
  </tr>
    <tr>
    <td> icon </td> <td>アイコンを管理する</td>
  </tr>
  <tr>
    <td> values </td> <td>色や文字サイズを管理する</td>
  </tr>
</table>

## フォルダ構成検討時に学んだこと

#### １、UI 層は「画面」と「コンポーネント」を分離する
UI のロジックは Composableアノテーションを使って呼び出すらしいので、再利用できるパーツは componentフォルダに分離しておくことで「画面」と「ロジック」をスッキリさせました。

例：Composeアノテーションの使い方
```
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApplicationTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    HomeScreen(Home().text())
                }
            }
        }
    }
}

@Composable
fun HomeScreen(text: String) {
    Text(text = text)
}
```
---

#### ２、ViewModelの状態管理にStateとFlowを使う
Stateは聴き馴染みがありましたが、Flowは初めて知りました。

State: 現在の状態を表すオブジェクト。UIがどのようなデータを表示するか、またはどのような状態（読み込み中、エラー中、成功した状態など）であるかを管理してる
Flow: データのストリームを提供するKotlinの機能らしい。非同期でデータを受け取り続けることができるのでデータの変化を監視できる。

---

#### ３、sealed classでUIの状態 (Loading, Success, Error) を管理する
sealed class（シールドクラス）は、例えば、以下のようなUIの状態を管理できるらしい。
Loading: データを読み込んでいる最中
Success: データの取得が成功した状態
Error: データの取得に失敗した状態

---

#### ４、ビジネスロジックの考え方
ビジネスロジックは、pureなJava(Kotlin)で実装してフレームワークなどに依存しない作りにした方がよい。
将来的にフレームワークを変更する必要が出てきた時に移行することが容易になり、ビジネスロジックをそのまま使える。

## まとめ
小規模〜中規模：ちょっと工夫は必要だけど、基本的にはMVVM構成でよさそう
大規模：クリーンアーキテクチャーを採用したい
マルチプラットフォーム：Modelにビジネスロジックを集約し、異なるプラットフォームでも再利用しやすい構成になっているMVI（Model-View-Intent）がいいのかも？

という感じで、フォルダ構成を検討するだけでも、いろんな考え方、やり方があるんだなと大変勉強になりました。