GoTheDistance

ござ先輩と言われています。(株) クオリティスタートという会社をやっています。

フロントエンドの開発スタイルの変遷とFlutterというお話をさせて頂きました

毎度おなじみBPStudy。治夫さん、ありがとうございました!

bpstudy.connpass.com

108枚のスライドはこっちです。50分で話すボリュームではないですね... 煩悩が多くて、申し訳ありません。

speakerdeck.com

GUI→テキスト→全部コードへの流れ

前半部分は、僕なりのGUI実装考古学みたいな感じの話です。Webブラウザが業務システムで使われる前はWindowsしかない時代で、Windowsデスクトップアプリケーションが作られていました。その時使われていたのが Windows Formで、GUIでテキストボックスとかボタン等をペタペタとドラッグして貼り付けるというスタイルです。このスタイルは一見簡単そうに見えますが、ロジックの再利用性は低く、テキストじゃないのでデザインの再利用性も低いです。IDEのプロパティウインドウでスタイルとイベントハンドラの有無を見るみたいな世界なので、今だと考えられないっすよね。

iOSも、UIKitの時代はGUIベースでした。Interface Builderにパーツを貼り付けて、IBOutletで紐付けてロジックを書くのは同じです。UIKit用語が多くて癖があるのでぱっと見て何のコードか分かる人は少ないと思います。昔はStoryboardもなかったので画面遷移は全部コードで表現したので、画面遷移の全体像を追うことが難しかった。Storyboardで少しは良くなかったと思いますけど、もう戻りたくはないです!ごめんな!

GUIだと再利用性が低く、画面の動的な動きもUIでは一切表現できない。可読性が高いようで低いので、この縛りプレイの中で秩序あるフロントエンドのコードを書くのは相当な習熟が必要だと思います。

テキストでUIを書き、ViewModelとバインドする

GUIはさすがにない!ということで、WindowsForm→WPFに進化したのが最初だと思います。WPFになると、XAMLというXML拡張セットでビューを書くことができます。TextBox Value="{BInding UserName,UpdateSourceTrigger=PropertyChanged"} HorizontalAlignment="center" みたいな感じのXMLがズラズラ続きます。XAMLそのものはよくできていて、Androidxmlファイルのスキーマよりずっと直感的でした。AndroidXMLスキーマ中途半端。

XAMLで定義したビュー情報に差し込むデータとロジックはどーするのって話ですが、ここでViewModelが登場します。TextBoxに差し込む値や、TextBoxのChangeイベントを受け付けるためのモデルクラスが登場して、ビューと紐付けます。WPFではこれらの仕組みを「データバインディング」と表現しています。テキストボックスの値が変わると、ViewModelのプロパティのSetterが自動的に呼び出されます。そのためのお作法がちょっと複雑なんだけどね。

ViewModelと特定のビューのイベントハンドラが紐付いてしまうと密結合になって再利用性がないので、UIが特定のイベントを実行したい場合には「Command」というインターフェイスを1枚挟みます。Commandを挟むことで、Commandを実装するViewModelのインスタンスが隠蔽されますので、ViewとViewModelが差し替え可能になります。GUI開発では、イベントは同じだけどコールバックだけ差し替えたいケースがメニーメニーなので、Commandインターフェイスで1枚挟む設計はワンダホーです。

UIがテキストで表現できたのはいいんですけど、今度はデータバインディングに必要な規約が重く感じます。素のWPFでMVVMやると即カオスになりますので、Prism/LivetのようなMVVMフレームワークも学ぶ必要があると思います。簡単なことをやってるのに結構なコードを書かねばならないので、重苦しい感じを受けるかもしれません。Webだと、サーバーサイドのテンプレートエンジンで吐き出したHTMLをjQueryでDOM操作して状態管理するみたいなコードを書いてしまうとカオスになって辛い、という経験をされている方は多いと思います。

やった!全部コードでかけるぞ!

React, SwiftUI, Jetpack Compose, Flutter。コードでUIを表現できコンパイルできるようになりました。Flutterで言うと、TextFieldというクラスのキーワード引数に、フォントの太さや下線などのデザインの設定、changeイベントなどのイベントハンドラ、入力チェック等のバリデーションロジックを全部書くことができます。見通しメッチャ良くなるのと、ロジックが書けるのでコンポーネントとして切り出して再利用することが容易です。表現力の高さは正義なのである。

これらのフレームワークに共通している、宣言的UIという考え方があります。 UI = f(state) という公式があって、UIは、その画面が持っている状態(state)によってその都度ビルドされ、ビルドされたUIを可変にしないということ。つまり、textBox.text = "aaa" みたいなコードは1度書いたら終わり。なので、FlutterのWidgetが持ってる変数は(多分)全部finalです。finalになってるので、stateの変化によって何が変わるのかViewに書かないといけないので、UIで担保する動きが把握しやすく、見通しが良くなります。やっぱこうだよな〜。

UI = f(state) を考えると、キーとなるのは state です。状態をどうやって管理するのかで、アーキテクチャがだいたい決まります。画面ローカルの状態とサービス全体で管理する状態の2つがあると思いますが、それらをいい感じに管理する方法を考えないといけなくて、Flutterも色々な流派が生まれました。2023年1月時点で最も勢いがあるのは、おそらくRiverpodです。Flutter界のロックスター、Remiさんの傑作でございます。

2022年にアーカイブとなりましたが、私がFlutterを始めた時にバイブルとして愛読していたのが、こちらのレポジトリです。Flutterでアプリを作るために必要な考え方や主要なライブラリのサンプルがいっぱいあるので、是非Forkして読むといいです!!!

github.com

自分はUIKit→Flutterにジャンプしたので、宣言的UIと全部コードで書けることの嬉しみ、上記レポジトリで教えてもらったコードの書き方や設計思想の違いにぶったまげてしまい、この2年ぐらいFlutterにハマってしまいました、というわけでございました。

全部コードでUIを書くスタイルは関数に関数を取る関数型プログラミングの書き方に慣れないと何もできないので、苦手意識のある方はそこに慣れることから始めると良いと思います。map/filter/reduce/extendみたいなリスト操作が関数型の書き方をしてます。これに慣れると、ロジックが全て式で表現できるので見通しが良くなります。

後半のFirebaseとか使ったライブラリの実装などは特に捕捉することはないです。Flutter関係ないけど、Cloud Firestoreってホンマに使うのが難しいプロダクトだなと思います。クエリの制約がいつか牙を向いてしまうリスクがずっとあるので。当初は必要ないと思ってたけど、Havingに近いことやらないといけなくなっても、未来のことはわからないもの。RDBのようにクエリの表現力が無限大であればプロダクトの価値にデータストアが後追いできるけど、KVSでは厳しい。Firestoreのデータモデリングは奥が深いです。

GUIってプログラミング教育に良いなと思った

発表内容とは関係ないですが、GUIオブジェクト指向を学ぶのにメッチャ良いと思います。自分が作ってるオブジェクトがUIとして表現できて、結果を目で見ることができる。視覚から入れますから。たい焼きの型がクラスで、たい焼きがインスタンスなのだという寓話より、2つTextFieldがあって、ひとつはフォントサイズが違う、ひとつは文字色が違う、でも元は同じTextFieldで、属性が個別に定義されているだけを例に取るほうがピンと来てくれるんじゃないかと。こういうのを目の前にすれば、オブジェクト指向のイメージが広がると思う。

次はたぶん3月です

RDBのデータモデリングについて、野球を絡めて資料を作って発表する予定です。BPStudyのBPは、BeProudでもあり、BaseBall Playでもあります。野球というドメインRDBに落とし込む、マニアにはたまらない構成にしたいと思いますので、どうぞよろしくお願い致します。

SQLを学習できるWebサービスを作りました。