天の月

ソフトウェア開発をしていく上での悩み, 考えたこと, 学びを書いてきます(たまに関係ない雑記も)

BPStudy#185〜フロントエンドの開発スタイルの変遷とFlutterに参加してきた

※一部ニュアンスが違う部分がありましたので、1/26に修正しました。

bpstudy.connpass.com

こちらのイベントに参加してきたので、会の様子と感想を書いていこうと思います。

会の概要

以下、イベントページから引用です。

フロントエンドが好きじゃなかった私が、Flutterに出会ったことでモダン・フロントエンドに傾倒していく経緯を、WIndows Form, WPF, iOS, Androidの開発を体験した中で感じた「フロントエンドの開発スタイルの変遷」を添えて、お話します。2020年のGW開けからやり始めて「おおお、Flutterすげえええ」となったワケをアツくご説明します。

「Favomatch」というマッチングアプリを開発した中で感じたFlutterの可能性・Flutterアプリの開発のTips等も紹介しつつ、今後Flutterをやろうとしている・もしくはFlutterでアプリを作っていらっしゃる皆さんへ、少しでも参考になる情報が出せればと思います!

登壇資料

speakerdeck.com

会の様子

登壇資料の通りではあるのですが、ざっくりとメモを書いておきます。

フロントエンドの開発スタイル

フロントエンドの開発スタイルとして、GUI型, HTML型, ALL CODE型の型に関してそれぞれ紹介がありました。

GUI

2005-2015年位に流行ったもので、Windows Form, UIkitなどが代表例。再利用性と拡張性の観点で非常につらいことが多い。(UIをツリー構造を使わずに管理する必要がある, if文で表示の差し替えができない, スタイルの共通化が困難, メタレベルのコンフリクトが発生する...)

Windows Formは絶対配置でパーツを作る原始的なやり方。レスポンシブルにならない。イベントハンドラ(コードビハインド)なので、Privateな関数が生成されることになり、やはりコードの再利用性が低い。

UIkitは画面遷移図のようなStroyboardを使い、Storyboardに配置されるUIと関連付けるためにIBを活用する必要がある。*1コードにはかなり癖があり、ViewControllerのライフライクルに合わせてコードを書く必要があるので非常に面倒くさい。
更に、単純な画面遷移を書くのに専門用語や複雑な仕組みを多数覚えないといけない。*2

Auto Layoutの制約もかなり面倒くさい。

HTML型

GUI型のつらさを解消するために開発されたもので、WPF, Android(View), JQuery(html/css)などが代表例。UIがテキストで定義されたのは大きな進歩だったが、ViewModelとViewを追っかけするのはコードが読みにくいというデメリットはある。

WPFXAMLを用いて、データの更新を伝搬させることでUIを更新することを実現する。Bindingを経由することでUI/Model双方向で更新することが可能であり、再利用性はGUI型と比較して高くなっている。
GUi型であったイベントハンドラのデメリットを解消するために、Commandという仕組みを用いて、ViewとViewModelの密結合を解消する。
ただしお作法が面倒くさく、MVVMフレームワークを活用したりしないとすぐにカオスなコードができあがってしまう。

Android(View)は、おおまかに言えばWPFとそこまで変わらない。
onCreateViewがライフライクルメソッドになっていて、ここでイベントハンドラの定義を書く。
ただ、onCreateViewを使ってちまちま書いていくのが辛いというのはあって、ButterKnifeライブラリでアノテーションを用いてViewとバインドできるようにすることが多かった。

ALL CODE型

ロジックやバリデーション、スタイルがすべてコードで書けるため、極めて表現力が高い。Flutter, React, TS, Swift UI, Jetpackなどが代表例。(FlutterはReactの影響をかなり受けている)

UIは最新の状態によって常に描画されるのでUI自体は不変(immutable)であるという思想から考えられた宣言的UI(UI=f(state))がとにかく画期的で、UIで担保しなければいけない動きがすぐに頭に入るメリットがある上、コードなので表示の切り替えもif文で制御可能。
宣言的UIにより、データの更新をUIに伝搬してリビルドすれば、ビューを変化しないまま画面を更新することができる。

Flutterにはまったきっかけ

続いて、今日の登壇者だったござ先輩がなぜFlutterにはまったのか?という話をしてくれました。

ござ先輩は、wasabeefさんのリポジトリに出会ったことで、モダンフロントエンドのエッセンスを一気に学べることができたということで、今までの常識が覆るような衝撃を受けたということです。

github.com

Flutterの状態管理

時間がなくてざっくり駆け足ではありますが、Flutterの状態管理に関して説明がありました。

StatefulWidget

setStateの仕組みを用いることで、WidgetをまたいだUI更新が難しいのが難点。

RiverPod

双方向なデータ更新が可能でキャッシュ可能な特徴がある。

パターンマッチがDartの言語仕様でないので、Whenメソッドを用いたパターンマッチを実現するfreezedが重宝されている。

Flutter Hooks

ReactのHooksにインスパイアされたもので、関数単位で状態管理できる心地よさを覚えるとなぜか知らない間に使いたくなってしまう魔力がある。

Flutterのチャット

flutter_chat_ui, flutter_firebase_chat_coreを使ってござ先輩は実装をされたそうです。
UIのカスタマイズはやりやすいが、バックエンドはflutter_firebase_chat_coreと組み合わせて自分でやる必要があるということでした。

Flutterの広告

admobを使うのがおすすめということでした。

注意点として、UIをビルド→広告を読み込むという実装にすると、広告を読み込む間(1秒)にユーザーが離脱してしまう体験談が挙がっていました。

Flutterのアプリ内課金

まともに実装しようとすると非常に面倒くさい上にベストプラクティスが存在しない領域なので、RevenueCatというアプリ内課金やサブスクのマネジメントSaaSにおとなしく頼ったほうがよいと思っているということでした。

FlutterのLint

monoさんのLintを使いましょうということです。

pub.dev

Firebase

続いて、Firebaseの説明がありました。

Cloud Firestore

Cloud Firestoreは卒業生を多数生み出してしまっているということで、どういう部分がきついのか?という話がありました。以下、箇条書きできついポイントを書いていきます。

  • 比較演算子の利用は1つのフィールドのみ
  • IN句に入れられる要素は10個まで
  • 1つのドキュメントに入るデータは1MBまで
  • 集計関数が存在しない(最近count関数がリリースされるような状態)
  • Select文すらない
  • 制約が強すぎてKVSだけでデータモデリングするのはめちゃくちゃ難度が高い
チャット設計

ユーザー・ルーム・メッセージの3つを使って設計するということです。

セキュリティルール

直接クライアントからデータをCRUDするコードを書く前提になっているということでした。
RBACを期待していると痛い目に遭うので注意してほしいそうです。

Firebase Cloud Messaging

PUSH通知を送ることができるもので、アプリを作る際に必須と言っても過言ではないということでした。

鬼門はバックグラウンドリスナーだということで、iOSでは特に苦戦されたそうです。*3

認証周り

Firebase AuthenticationでSMS/電話番号/メール認証を組み込むことができるということで、比較的簡単に実現ができるというお話でした。

なお、ハマるときは大体コード以外*4に問題があるということで、コードを読んでいくのではなく、SDKへの知識/理解を深めることが先決になるというお話もありました。
ハマったときは、コードではなく、まずドキュメントを全部見て、その後にGithubのIssueを見るのが重要だということでした。

Test

まず、Widget Testでテスタビリティを上げるために、外部接続をWidgetから直接書くようなことは絶対にしない方がいいというお話がありました。

モック化はMocktailを使うと実現できるということですが、Fakeクラスでも充分なんじゃないのか?と思えるそうです。

Widget Testはイベントが適切に動くか?という正常系のデグレ確認に使うもので、UIのデザインレベルのデグレを拾うのにはあまり適していないということでした。

モバイルアプリ開発の難しさ

次に、モバイルアプリ開発のフロントエンド部分の難しさについてお話がありました。以下のような部分が難しさとして挙がっていました。

  • リリースする際はAppStoreなどを経由する必要があるため、即時修正が難しい
  • 実行時例外が発生すると即動かなくなる
  • 端末依存の不具合がある。100人中2人だけ動きません、とかが普通に起きる

モバイルアプリ開発の面白さ

難しさのあとは面白さの話がありました。以下のような部分が面白さとして挙がっていました。

  • コンポーネントを適切に作れば開発者体験とUXを向上できる
  • ヒトの導線を設計する面白さがある
  • アップデートが早い
  • Flutterに関しては、自分の常識が変わって、初めてプログラミングを始めたときのような気持ちで触れた

フロントエンド開発に慣れるために

最後に、フロントエンド開発に慣れるために必要だと思うことについて話がありました。

抽象的な概念のキャッチアップ

似たような言葉でも違う思想を扱っていたりするので、言葉を鵜呑みにせずに、言い換えて自分の言葉で説明できるようにする必要があるということです。

思想を理解する

思想のアップデートが次々に行われる(node→deno, webpack→viteなど)ため、ここに慣れることが重要だということでした。なお、FutterはWebアプリと比べればそこまでアップデートが早くないのは救いだということです。(ただし人気ライブラリはIssueが多い分頻繁にアップデートが入るので注意)

会全体を通した感想

ござ先輩の熱がこもった発表で、楽しく発表を聞くことができました。
歴史の部分から入り、Flutterはどのあたりがこれまでと比べると画期的で面白いのか?という順序で説明をしてくれたので、これまでいまいちありがたみがわかっていなかった部分が、如何にありがたいものなのか?というのが理解できてよかったです。

*1:Windows Formと同じ

*2:数年前の話なのでもっと今はモダンになっている可能性あり

*3:FirebaseAppDelegateProxyEnabled=falseにしないとバックグラウンドリスナーがiOSでは動かなかった

*4:つまり設定