What's 宣言的UI（Jetpack Compose)？と思ったので調べた話

## 前ふり
ども、八流エンジニアです。
ここ数年、流行っている宣言的UI・・流行ってますよね
耳にもするし、なんとなくは知っているけど、聞かれた時に恥ずかしくないように調べてみました。

個人的には、`Flutter`で大変嫌な思いをしているので、
宣言的UIに対するモチベーションが低いですが、やっていきます！

## 宣言的UIとは？
### そもそも
`宣言的`という単語が、いかにもなIT用語な感じで、わかりにくいですよね（？）
[そういう時はWikipedia](https://ja.wikipedia.org/wiki/%E5%AE%A3%E8%A8%80%E5%9E%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)ですよね。

wikiによると、
>宣言型プログラミングでは対象の定義 =「何（What）を得たいか」を宣言してプログラムを構成し、逆にそれを得る過程・手続き・アルゴリズム =「どうやって（How）得るか」を記述しない[1][2]。すなわち、出力を得る方法ではなく、出力の性質・あるべき状態を記述することが「宣言型」である。

概要だけでなんとなくわかった気がします！
「何を得たいか」？ってことねー

ちょっと見えないっす。。

### 具体的に
#### 昨今の宣言的UIと言われているモノタチ
* [SwiftUI](https://developer.apple.com/jp/xcode/swiftui/)
* [Jetpack Compose](https://developer.android.com/jetpack/compose?hl=ja)
* [Flutter(2)](https://medium.com/flutter/whats-new-in-flutter-2-0-fe8e95ecc65)
* [React](https://ja.reactjs.org/)

他にもあるでしょうが、今回はここら辺。（Reactはやってないですw）


#### 実際のコード

##### SwiftUI
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            MapView()
                .ignoresSafeArea(edges: .top)
                .frame(height: 300)

            CircleImage()
                .offset(y: -130)
                .padding(.bottom, -130)

            VStack(alignment: .leading) {
                Text("Turtle Rock")
                    .font(.title)

                HStack {
                    Text("Joshua Tree National Park")
                    Spacer()
                    Text("California")
                }
                .font(.subheadline)
                .foregroundColor(.secondary)

                Divider()

                Text("About Turtle Rock")
                    .font(.title2)
                Text("Descriptive text goes here.")
            }
            .padding()

            Spacer()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }

```
##### SwiftUI、眺めてみて
画面構成と内容を、コード上で表現していますね。
レイアウトファイルに近いので可読性はかなりいい。
xibファイルからしか手段がなかった（気がする）の時に比べると格段にいい気がする。
swift自体はとても読みやすい言語なので、
iOS開発者はandroiderのためにも、SwiftUIの採用お願いします。

##### Flutter
```dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Material Design',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Material Design Layout'),
        ),
        body: Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}
```

##### Flutter、眺めてみて
画面構成と内容を、コード上で全て書いている。。
`()`が多すぎ、`;`がだるい
やっぱ、`dart` は・・・ないかなー


##### JetPackCompose
```kotlin
@Composable
fun Home(onSnackSelected: (Long) -> Unit) {
    val (currentSection, setCurrentSection) = rememberSaveable {
        mutableStateOf(HomeSections.Feed)
    }
    val navItems = HomeSections.values().toList()
    JetsnackScaffold(
        bottomBar = {
            JetsnackBottomNav(
                currentSection = currentSection,
                onSectionSelected = setCurrentSection,
                items = navItems
            )
        }
    ) { innerPadding ->
        val modifier = Modifier.padding(innerPadding)
        Crossfade(currentSection) { section ->
            when (section) {
                HomeSections.Feed -> Feed(
                    onSnackClick = onSnackSelected,
                    modifier = modifier
                )
                HomeSections.Search -> Search(onSnackSelected, modifier)
                HomeSections.Cart -> Cart(onSnackSelected, modifier)
                HomeSections.Profile -> Profile(modifier)
            }
        }
    }
}

```
##### JetPackCompose、眺めてみて
画面構成と内容を、コード上で全て表現している
ボトムナベゲーションのパターンで、enumによって切り替わるように見える。

### 一旦まとめ
確かに、wikiの通り、を１コードに「何を得たいか」を書けば、画面が素直に構成できそう。
ただ、機能（リスナー関連）は、外に出さないと、見通しが悪くなると思うので、
ここまで素直に、定義していくことはない気がする。

## 今までのコードをみる (android)
### xml
```xml
<Button
android:id="@+id/simpleButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test"/>
```
### kotlin
```kotlin
simpleButton.setOnClickListener {
  textView.text = "${it.text} is pushed"
}
```

#### 今までレイアウトを眺めてみて
いつもの。レイアウトリソースに動きをコードでつけているんだからこうなるよね。

実装進めている中で、レイアウトはこうで、ここにこういう処理が入って、と考えるより
ここの画面は、こういうレイアウトでこういう機能でってのを一括で描きたい人には宣言的の方がいいのかも。
慣れすぎてて違和感はないけど、これが直感的でないってことなんだと思う。

個人的には、レイアウトが別ファイルになっているのはわかりやすいと思うんだけどなー

## 比較して思ったこと
宣言的UIは、機能が少ないシンプルな構造なアプリにだったらいいんじゃないかな。
命令的であろうが、コードがfatになれば、自然と分離したくなるんだから、

はなからレイアウトがファイルとして分離しているのは、そこまで悪いことではないと思う。

## 重要そうな概念 （jetPackで調べる）
### [Compose](https://developer.android.com/jetpack/compose/mental-model)
>ビューを手動で操作すると、エラーが発生しやすくなります。データの一部が複数の場所でレンダリングされている場合、それを示すビューのうちいずれかの更新を忘れがちです。また、2 つの更新が予期せず競合すると、不正な状態が作成されやすくなります。たとえば、UI から削除されたばかりのノードの値を設定しようとすることがあります。一般に、更新を必要とするビューの数が多いほど、ソフトウェアのメンテナンスの複雑さは増します。
ここ数年、業界全体が宣言型 UI モデルに移行し始め、ユーザー インターフェースの構築や更新に関連するエンジニアリングは大幅に簡素化されています。この手法は、概念的に画面全体をゼロから再生成し、必要な変更のみを適用することで機能します。このアプローチでは、ステートフルなビュー階層を手動で更新する複雑さを回避できます。Compose は宣言型 UI フレームワークです。
画面全体を再生成する際の課題は、時間、コンピューティング能力、電池使用量という点で、コストが高くなる可能性があることです。このコストを軽減するために、Compose は常に、UI のうち再描画する必要がある部分をインテリジェントに選択します。これは、再コンポーズで説明するように、UI コンポーネントの設計方法に影響する可能性があります。

更新するは、デバイス開発のわかりやすい課題。
ただ、命令的でもMVVMとか通して、似たことはできるが、書いてあるように、漏れが発生しする可能性はあるため
flutterでも出てくる、`ステート`が重要そうに思う

### [ステート](https://developer.android.com/jetpack/compose/state)
>アプリにおいて状態とは、時間とともに変化する可能性がある値すべてを意味します。これは非常に広範な定義であり、Room データベースにも、クラス内の変数一つにも当てはまります。

ボタン押されたら、何か命令するのではなく、
ボタン押された後の姿を、状態として持っておく
みたいなイメージなのかな・・たぶん。

## まとめ
宣言的UIが、"あまりよくわかってない最近の流行りのUI"から、命令的（今まで）とは明確に違う、
「こういう状態にしたい！」という思いを、そのままコードにぶつけて実装進められるというのが
一番わかりやすい利点なのかなとは思いました！！

これで、宣言的UIという単語が来た時に、怖くなくなったと思います！以上！！
部分的導入もできるので、やっていきたいですね〜


### 長〜い、あとがき
宣言的UIはあくまでUIの実装部分の話で、
コードの可読性に当たる話とは別だと思いうなー

アーキテクチャとか、どれだけFatにしないかは別で解決する必要があるはず（？）
宣言的UI周りで流行っているアーキテクチャ（[Flux](https://qiita.com/knhr__/items/5fec7571dab80e2dcd92)とか）は、
親和性が高いけど、宣言的UIと一緒に使わなければダメというわけでもなさそう。

android初心者には壁となりやすそうな、`Fragment`や`savedInstanse`を無視できる可能性もありそうで
これからandroid始める人にはお勧めしたい気がしますね。

宣言的UIは、「Html+Js or CSS」みたいに、domを操作で肉付けするのがわかりにくいところから来てて
実態が見辛いのが問題だったんだと思うんすよね。
android開発ってそんなに見辛くならないよ？？とは思ってしまう。

正直、今までいろんな現場のレイアウトリソース見てきたけど、`tools`うまく使いこなせてなかったり
`ViewGroup`の階層がカオスになってたりするのが多かったから可読性が悪いんじゃないの？
とは思ってしまう。
宣言的にしないでも可読性も上がるし、描きやすさは大きく変わらないとは思うんだけど、
頭の整理のしやすさの選択肢として、宣言的である手法を選択できるのはいいんじゃないかとは思います。

僕の中の宣言的UIに対してのイメージは、
もともとFlutterやってて描きづらいし、読みづらいし、どうなっとんねん！！となってたけど、
jetPackComposeなら多少マシにできるかも？とは思えたので、少し前向きになれました。

いやーそれにしてもwikipedia偉大ですね！
みなさん、wikiにちゃんとお布施しましょうね？
僕は毎年元旦にお布施してるからセーフ（？）
お粗末！！！！！

## 参考資料（まとめ）
### vue.jsとhtmlの比較だけど、`出したいものを、UIに載せておくイメージ`はわかりやすい
https://qiita.com/Yametaro/items/3c27305072464e1d6230
### 公式Jetpack Compose
https://developer.android.com/jetpack/compose?hl=ja

### 宣言プログラミング wiki
https://ja.wikipedia.org/wiki/%E5%AE%A3%E8%A8%80%E5%9E%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0

### SwiftUIのコード探した
https://github.com/ivanvorobei/SwiftUI

### jetPackComposeのコード探した
https://github.com/android/compose-samples

https://github.com/DroidKaigi/conference-app-2021


### flutterのコード探した
https://flutter.ctrnost.com/basic/interactive/form/button/

### Reactでの宣言的の意味
https://www.fenet.jp/dotnet/column/language/3816/#Declarative

### Fluxについて、わかりやすかった
https://qiita.com/knhr__/items/5fec7571dab80e2dcd92