Slide 1

Slide 1 text

フロントエンドの開発スタイルの変遷と、 私がFlutterにハマったわけ gothedistance a.k.a ござパイセン https://twitter.com/gothedistance BPStudy#185 at 2023.01.25

Slide 2

Slide 2 text

YUMOTO Michitaka Hello! 2 ● ゆもと みちたか(ござパイセンというHNで生きてます) ● 1979年生まれです。松坂世代。 ● GoTheDistanceというブログを書いてます。たまに。 ● 新卒SIer→雑貨製造業で内製→独立してもうすぐ7年。 ● フロントエンドが好き。修行するぞ修行するぞ。 ● やきうを愛する東京ヤクルトスワローズのファン!

Slide 3

Slide 3 text

経歴等 3 アプリ開発の実績 私の経歴 ● 商社系SIer新卒入社。Javaメイン。 PG→SE→PL→PMなどを経験。 ● 家庭の事情で、叔父が経営してる雑貨 製造業の会社に転職。主に社内のシス テム開発に従事。たまに受託。 ● ブログで出会った人にお仕事を頂いたの がきっかけで独立して、今に至る。 ● 要件定義・ディレクション回りで独立する も、今はFlutterばっかり。

Slide 4

Slide 4 text

【PR】女性限定推し友マッチングアプリをリリース! 4 ➔ Flutter ➔ Firebase ➔ FastAPI ➔ Flask(管理画面) ➔ CloudRun ➔ ほぼ全部俺 Favomatch の告知にご協力頂きたく伏してお願い申し上げる候

Slide 5

Slide 5 text

BPStudy History ● BPStudy#79(野球) ● BPStudy#91(野球) ● BPStudy#92 ● BPStudy#100(野球) ● BPStudy#103(野球) ● BPStudy#108 ● BPStudy#112(野球) 5 ● BPStudy#115(野球) ● BPStudy#122 ● BPStudy#124(野球) ● BPStudy#127(野球) ● BPStudy#140(登板回避) ● BPStudy#142 ● BPStudy#185(NEW!!)

Slide 6

Slide 6 text

お話させて頂くこと 6 ➔ Flutterにハマったきっかけ 〜FE開発スタイルの変遷を添えて〜 ➔ Flutterアプリ開発のTipsあれこれ ◆ Flutterアプリのアーキテクチャ、状態管理、利用したライブラリ ◆ Firebaseと戯れた日々の記録 ◆ アプリ内課金、チャット、広告などの実装 ◆ テスト手法 ➔ 謝辞

Slide 7

Slide 7 text

フロントエンドと私 フロントエンドには3つの開発スタイルがあるのでは? 1 7

Slide 8

Slide 8 text

嗜んだフロントエンド ➔ Windows Form (2011〜2014) ➔ WPF(2018〜) ➔ Android(2015〜2019) ➔ iOS (2015〜2019) ➔ Vue.js (2019.07〜09) ➔ Flutter (2020〜) 8 仕事でやったことがあるフロントエンドを列挙しています。

Slide 9

Slide 9 text

フロントエンドの開発スタイル 9 GUI型 UIをD&Dで貼り付け、対応す る変数やイベントを定義して、 処理を記述するスタイル HTML型 テキストファイルにUIを別 の言語や枠組みで書い て、コードと紐付けるスタ イル ALL CODE型 UIの記述からビジネスロ ジックから全てを、単一の コードベースで書くスタイ ル ◉ Windows Form ◉ iOS(UIKit) ◉ WPF(Xaml) ◉ Android(xml) ◉ jQuery(html/css) ◉ Flutter(Dart) ◉ React(TypeScript) ◉ iOS(Swift UI) ◉ Android(Jetpack) ※ iOSもAndroidも、公式がALL CODE型なライブラリをリリースしている所がポイントです。結局こうなるんです。

Slide 10

Slide 10 text

GUI型スタイル UIをドラッグアンドドロップで貼り付けるやつだね 2 10

Slide 11

Slide 11 text

GUI型(Windows Form) 11 ➔ 最も原始的な開発スタイル ◆ 絶対配置でパーツを貼る ◆ イベントハンドラを作る ◆ ロジックを書く ➔ レスポンシブにならない ◆ やればできるっぽいが、相当頑 張る必要がある。 ◆ 漢はWindowsサイズ固定。

Slide 12

Slide 12 text

Windows Form(コードビハインド) 12 ➔ イベントハンドラと同義 ◆ キーダウン・タップ等の UIが持 つイベントに対して処理を差し 込む。 ◆ Code Behindっていうぐらいな ので、private な関数が生成さ れる。 ◆ ビジネスロジックを実装すると 再利用性が一気に低くなる

Slide 13

Slide 13 text

GUI型(iOS UIKit) 13 ➔ Storyboard ◆ 画面遷移図のようなもの ◆ ViewControllerを継承したクラスを紐付ける ● この例だと6個のクラスが必要。 ◆ スタイルは原則プレビューされない。 ➔ Interface Builder (IB) ◆ Windows Formと同じく、D&Dで貼り付け。 ◆ 貼り付けるのはUIだけで、スタイリングや、 TableViewのセルは別途定義する必要がある。

Slide 14

Slide 14 text

iOS UIKit (ViewController) 14 UIKitの根幹 ➔ UIKItではViewControllerを起点にして画面遷移が動く。 ◆ 先程のStoryboardで表示されたパネルに対応するクラス。これがないと何も出来ない。 ◆ ViewControllerのライフサイクルに合わせてコードを書くのも面倒である。 ● ViewDidLoadでスタイルを書いたりしてしまう。 BaseViewControllerはびみょい。 ● ViewDidAppearで画面が戻ったときの UI更新処理を書いたり。 ◆ ViewController間の値渡しもStoryboard経由で行う(コードでも書けるが) ● Storyboardを使う場合、Segueというものを定義する必要がある。 ● Segueに渡したいデータを定義して受け取る側はキャストして受け取った記憶。 ● 数年前の記憶なので、今は とかでもらえるかもしれません。

Slide 15

Slide 15 text

GUI型(iOS UIKit / Interface Builder) 15 ➔ IBOutlet ◆ GUIで貼り付けたパーツのこと ◆ !があるのは貼り付け先がないと Nullで エラーになるため ➔ viewDidLoad ◆ 画面の初期化時に呼び出される。 ◆ 他にもライフサイクルに合わせたフック が存在する。 ➔ addTarget ◆ イベントハンドラの登録など。

Slide 16

Slide 16 text

iOS UIKit (Auto Layout) 16 https://zenn.dev/mikomokaru_jpn/articles/45a66d84d0acfc ➔ ボタンがあるとしたら... ◆ 上部の要素に対して Margin:10 ◆ 下部に対して Margin:10 ◆ 右と横はスクリーンから各々 Margin10 ◆ 最低のサイズは120px ◆ これをIB or コードで設定する。 ➔ 「直近の要素」とのMarginを上下左右に対し、UI パーツごとに設定する。 ➔ SwiftUIによって直接AutoLayoutを触れなくても良く なったらしい。そらそうよ。

Slide 17

Slide 17 text

GUI型はつらみが多い 17 再利用性・拡張性が乏しい ➔ D&DでUIを貼り付けると再利用性・拡張性に乏しくなる ◆ UIはツリー構造で管理するのに、その構造が表現できない。全部フラットになる。 ◆ 繰り返し(動的な数量)の配置が不可能。 ◆ if文で表示を差し替える等が、表現できない。 ◆ スタイルの共通化が困難。 CSS的な機能が基本的にない。 ◆ 共通化のためにコードで UIを表現すると、全体の見通しが悪くなる。 ● UIを決定するための情報源がGUIとコードの2つに分かれてしまうので。 ◆ メタレベルのコンフリクトが発生することが多々ある。 ● iOSのStoryboard/XIBのメタ情報でコンフリクトするなど。

Slide 18

Slide 18 text

HTML型スタイル UIはテキストファイルで、ロジックはコードで。 3 18

Slide 19

Slide 19 text

HTML型(WPF / XAML) 19 ➔ WPFではXAMLを使ってUIを定義 ◆ UIに応じた属性が定義された XMLです。 ◆ TexBox, Label, ComboBox, Button, Panel, Grid Layout, DataGrid…etc ◆ Bindingを経由することで、UI/Modelの双 方向の更新が可能になります。 ◆ Windows Formから変わりすぎなので、も うちょい手心あってもなと思う Extensible Application Markup Language

Slide 20

Slide 20 text

WPF(データバインディング) 20 ➔ XAMLでは Binding を定義することが出来る。 ◆ 変数を参照先に指定して、変更があったら自動的に変数の中身が更新される仕組み。 ◆ UIとデータを完全に分離できるため、再利用性が高まる。 ◆ お作法がめんどくさいのが難点。 ● UserControlのDataContextを指定する。 ● XAMLでBindingを書いて変数を指定する。 (IDE補完が効かないのが辛い ) ● BindされたデータにはBindableBaseという抽象クラスを実装して、 ● データのsetterでSetPropertyを実装し、双方向のバインディングができる ◆ Prism/LivetあたりのMVVMフレームワークがないと即カオスになると思います。 データの更新を伝搬させ UIを更新する

Slide 21

Slide 21 text

WPF(MVVM) 21 View⇔ViewModel⇔Model View ViewModel Model ➔ MVVMの考え方が提唱されたのは2010年頃っぽい。WPFが先駆者かも。 ◆ View(UserControl 以下 UC)をXAMLで書きます。 ◆ UCのDataContextプロパティにバインドするクラスを定義します。 (ViewModel) ◆ ViewModelからModelを叩き、データのCRUD操作を行います。 ◆ Modelの戻り値はViewModelのプロパティに代入され、 XAMLでBindingされたプロパティが変 更を検知して、UIを更新します。 ◆ Androidもこういうスタイルだと思います。

Slide 22

Slide 22 text

WPF(MVVM/ロジックのバインド) 22 View⇔ViewModel⇔Modelであります。 ➔ WPFには Command インターフェイスがあります。 ◆ イベントハンドラに呼応する ViewModelのメソッドを呼び出すための仕組みです。 ◆ Commandを経由することで、ViewModelを変えるだけで処理の中身を差し替えることが出来ま す。VMと密結合になったらコードビハインドと一緒なので、一枚挟んでます。 ◆ 引数が欲しい場合は CommandParameter を定義して別途渡すことができます。 ◆ ボタンだけでなくキーイベントや、マウスイベントにも対応しています。 ● ●

Slide 23

Slide 23 text

Android(View) 23 XAMLとは言ってないけどほぼ一緒 ➔ XMLを使ってUIを定義 ◆ XAMLっぽいけど、書ける内容は XAMLより全然少ないです。 ◆ IDを定義して、findViewById()で要素 を取得。最も原始的な手法がそれ。 ◆ イベントハンドラが書けません。 ViewModel(Fragment / Activity)側で 実装します。

Slide 24

Slide 24 text

Android(イベントハンドラ) 24 onCreateViewでイベント内容を書く ➔ setOnxxxListenerを定義し、クロージャで処理を 書きます。setOnClickListener、 setOnKeyListener等。 ➔ onCreateViewというライフサイクルメソッドで、イ ベントハンドラの定義を書きます。 ➔ iOSよりライフサイクル管理に苦労した記憶があ ります。Fragmentの中身がキャッシュされず初期 化されちゃった、みたいな。

Slide 25

Slide 25 text

Android(ButterKnife) 25 昔はButterKnife、今はView Binding ➔ ButterKnifeという、アノテーションで Viewとバイン ドできるライブラリを使ってた。 ➔ findByViewIdは実行時例外が出る可能性がある けど、アノテーションならコンパイル時に検出でき てナイス。 ➔ 2014年にリリース、2020年を最後に更新されて いない。JetPack Composeでお役御免? ➔ Android界では有名な、Jake Whartonさんのライ ブラリです。retrofitのメンテナー。 https://github.com/JakeWharton/butterknife

Slide 26

Slide 26 text

Android(View Binding) 26 Android公式でサポートされた仕組み ➔ 命名規則に応じて自動的に ビューをバインドするクラスが生 成され、タイプセーフにビューの 要素にアクセス可能になります。 ➔ 2014年に欲しかったけど、 AndroidのJVMサポートなどの影 響もあると思います。 https://codeforfun.jp/android-studio-how-to-use-view-binding-with-kotlin/ XML ファイル名をキャメルケースにして Binding を末尾につけるという 命名規則。 activity_main.xml → ActivityMainBinding

Slide 27

Slide 27 text

Android(画面遷移と値渡し) 27 どこも一緒だね ➔ 新しい画面を呼び出すには startActivityForResult ➔ 戻りはonActivityResult ◆ Intent経由でデータを入れる。 ◆ オブジェクトはJSONにシリアライ ズして渡していた。 ◆ 今はもう違うかも。 ➔ AndroidはstartActivityすると、Stackし て上にかぶさります。

Slide 28

Slide 28 text

HTML型になったはいいけど、もう一声 28 ➔ UIがテキストで定義されたのは間違いなく良い。人類に必要。 ◆ GUIオンリーはかなり辛い。テキストで UIが表現できるのは正義。 ◆ 階層構造もネストで表現できるようになった。 ➔ ViewModelとViewを行き来するのが面倒。ロジックが追っかけにくい。 ◆ 全体を把握するコストがやっぱり高い。 ➔ テキストで表現できるなら、単一のコードベースにまとめて欲しさがある ◆ iOSは SwiftUI、Androidは Jetpack Composeにより、ALL CODE型の開発スタイルに移行し たと言って良いと思います。結局それが正義なのではと、わたしは感じました。 規模が大きくなると辛くなる

Slide 29

Slide 29 text

ALL CODE型スタイル この出会いからフロントエンドに傾倒していく 4 29

Slide 30

Slide 30 text

ALL CODE型スタイル 30 ➔ 全てをコードで定義し、コンパイル (or トランスパイル)するスタイル。 ◆ Flutterの場合はDart、ReactならTypeScriptですね。 ➔ 最大の魅力は「表現力」です。Viewで表現できるロジックの幅が違います。 ◆ ロジック・バリデーション・スタイル・副作用等がコードで書ける!最高! ◆ これに慣れてしまったら、表現力の小さい開発スタイルに戻れるわけがない。 ➔ Reactが最も有名。FlutterはReactにインスパイアされている部分が多い。 ◆ UIの組み立て方の思想、状態管理のやり方など。先駆者 Reactの功績は大きい。 ◆ SwiftUI / JetPack Composeでやれるリソースのある現場はいいけど、無いなら Flutterでリプ レイスするのが現実的かもしれないですよ! 全部コンパイルできるようにしたらいいんじゃないの

Slide 31

Slide 31 text

宣言的UI 31 ➔ 宣言的UIはグレートです。 ◆ 私がフロントエンドに傾倒する きっかけとなったもの。 ◆ UIは最新の状態によって常に 描画される為、UI自体は不変 であるという考え方。 ◆ コンストラクタでUIを作り、表現 する。コンストラクタなので不 変。 これに慣れたら戻れない

Slide 32

Slide 32 text

宣言的UIの良さ 32 ➔ UIで担保しなければならない動きがスッと頭に入る。 ◆ Reactの場合は、 みたいな書き方。 ◆ 上記の書き方だと公開されるインターフェイスで大まかな仕様がわかる。 ➔ ロジックが書けるので、ifやforeach等と組み合わせてUIを表現できる。 ◆ ある項目をコンボボックスから選ぶ時だけ項目を増やす ◆ 画像の登録があればそれを、ない場合はプレースホルダーを出す ◆ 可変の要素に対して foreach を回してUIを構築できる。ToDoリストみたいなUI。 ➔ Flutterの場合Widgetをネストすることでビューの階層構造が表現できる。 ◆ UIはツリー構造で管理するしかないのよね。 これに慣れたら戻れない Part.2

Slide 33

Slide 33 text

宣言的UIの良さ 33 ➔ 宣言的UIの場合、ビューはimmutable(不変)になる。 ◆ 不変=初期化(ビルド)された時の状態から変更されないこと。 ◆ ビューの更新は状態に応じて再構築すればいいという考え。 ➔ ラベルで合計値を表示する場合で考える。 ◆ 宣言的UIじゃない場合は、sumLabel.text = "10,000" ってやる。UIが可変(mutable)。 ◆ Flutterだと「Text(value)」のみ。合計値は変動するが valueの値を出すのは同じ。 ➔ データの更新をUIに伝搬してリビルドすることで、 UIが更新される。データが先、 UIは後。 ◆ データによって状態 (State)が規定される。UIはデータと状態に準拠するだけが正しい。 これに慣れたら戻れない Part.3

Slide 34

Slide 34 text

UI = f (state) 34 宣言的UIの勝利の方程式 ➔ UIは、ビルド時に渡される 適切なstate によって常に最新化されるという考え。 ➔ stateに変化があったら、もう1度ビルドを呼び出して対応します。

Slide 35

Slide 35 text

Flutterにハマる僕 宣言的UI with バイブルとの出会いで、どハマりすることに 5 35

Slide 36

Slide 36 text

➔ ワンソースで、iOS/Android(MacOS/ Windows / PWA / Linux)で動作するアプリケーションを 構築するフレームワーク、Google謹製。Dart製。 ➔ DartにはPlatform ChannelというAPIがあって、それがFlutter Engineに搭載されていること で、OSの差分を吸収している。バッジを付けたり、カメラやフォトの起動など。 ➔ コロナ禍(2020.01〜)の初期に本番稼働したという記事を見かけて、「え、 mjd?」となり、 2020.05からやり始めたのがきっかけ。独習です。 ➔ 自分でメンテしないといけないネイティブアプリが複数あり、ワンソースで管理するのが悲願 だったので、飛びついたというのが本音。飛びついて大正解でした・・・! 36 Flutter is 何

Slide 37

Slide 37 text

Flutterに出会って脳汁プシャー 37 ネイティブアプリの常識が根本的に変わった。 時が止まったままの僕の心を〜 マジでワンソースでiOS / Androidに対応できるじゃん.. If とか foreachがViewに書ける のは嬉しい。動的な画面の変 更がやりやすいわ! DartだけでUI・ロジック・スタイ ル・状態が可視化出来るのす げぇやりやすいじゃん .. レイアウトがめっちゃ組みやす い. Themeを使えばUIスタイル も一元管理できるんだ ... Hot Reloadすげえ。ほんとに HOTだ。UIの変更がすぐ反映 されてサクサク進められる! FlutterはSwiftUIとかに比べる と簡潔に見えるし、UIが作りや すい。Dartのおかげかな? Widgetなんでもあるじゃん。 なにこれすごい。ありがてぇあり がてぇ... Widgetをネストすることで、 様々なUXが定義できる。 これはすごい発想だな・・・ これが有名なHooksというもの か。これで状態管理できるなら 関数型推しになるわな!

Slide 38

Slide 38 text

バイブルとなるレポジトリと出会う 38 https://github.com/wasabeef/flutter-architecture-blueprints ➔ 最初は全然読めなかった ので、クラっときた。 ➔ Forkして、処理毎にコメント を書いて、処理内容を日本 語化して少しでも読み解く ようにした。 ➔ モダンなアプリの作り方に 触れて、抽象度の高い作 りに脳汁がプシャー。

Slide 39

Slide 39 text

Flutterアプリの礎的存在 39 ➔ 私にとって、Flutterのアーキテクチャの礎となっ たもの。wasabeefさんに圧倒的感謝。 ◆ モダン・フロントエンドのエッセンスを学ぶことが 出来る生きた教材 ◆ HooksやRiverpodというFlutterで愛用すべきラ イブラリの使い方も大いに勉強になった。 ◆ UIをテスト可能にするための抽象化、 Resultクラ スの使い方なども勉強になった。 ◆ ハイクラスのスタンダードを体感できた! このレポジトリに出会ったことで、 Flutterにハマっていく

Slide 40

Slide 40 text

SoCの担保がまずあって 40 ➔ 重要なのはSoCの担保。 ◆ ViewはViewModelしか見ない。 ◆ ViewModelはRepositoryしか見ない。 ◆ RepositoryはDataSourceしか見ない。 ◆ 単方向データフローというものに近い。 ➔ RepositoryはMockできるようにする ◆ ビジネスロジックはMockable必須。 ◆ 外部通信するコードを直接 Viewに書いたら絶 対ダメ。UIテストが単体で出来ない。 依存先は1つでいいの、いいの

Slide 41

Slide 41 text

SSOTが次に来る 41 ➔ アプリの場合、画面遷移が深くなるけどもデータソースは 同じで、孫画面で選択したものを親画面に戻して更新した いみたいなことはとても多い。 ➔ データソースが散らばっているとろくなことがないので、 UI が参照するデータ(同じ型ならば尚更)は1箇所でまとめら れたほうが良い。 ➔ Androidの公式ページやmono0926さんの記事参照。 ➔ https://developer.android.com/topic/architecture?hl=ja ➔ https://mono0926.medium.com/architecture-240d3c56b597 Single Souce of Truth. ビジュアル系バンド名のようだ

Slide 42

Slide 42 text

SoCによる良いテンプレ化 42 ➔ 各々の責務に徹すれば、そんなに複雑なコー ドにならない、はず。 ◆ 人はそれをアーキテクチャと呼ぶのではなか ろうか。品質の担保ってそーゆー話。 ◆ ノウハウは結実するとテンプレになるもんで す。良いテンプレには哲学がある。 ◆ UIデザイン及びUXの最大化に時間を全振り するべきで、SoC/SSOTのあるべき議論に時 間を掛ける意味は薄い。 だんだんテンプレになってくるもの

Slide 43

Slide 43 text

Flutter開発Tips 6 43 ➔ 状態管理 ➔ Riverpod ➔ Hooks ➔ Firebase ➔ 広告とApp内課金

Slide 44

Slide 44 text

StatefulとStateless(状態管理) 44 Flutterにおける最も単純な状態管理手法 ➔ FlutterのUIパーツは、全てWidgetというクラスを継承して作ります。 ◆ StatelessWidgetとStatefulWidgetがあります。もう1個あるけど、都合上割愛。 ➔ 「State」はWidgetが初期化〜破棄までのライフサイクルのことです。 ◆ iOSだとUIViewControllerのライフサイクル。viewDidLoad,viewWillAppear… ◆ AndroidはActivity/Fragmentのライフサイクル。onDetach, onCreated,onResume… ➔ StatefulWidgetは任意のタイミングでstateを強制的に最新化できる。 ◆ Stateを更新するとbuild関数が呼びだされ、最新の状態で Widgetを再構築できます。 ➔ StatelessWidgetにはそれがない。fulとlessの違いはそこです。

Slide 45

Slide 45 text

StatefulとStateless 45 Flutterにおける最も単純な状態管理手法 setState→buildの流れに注目!! Widget のライフサイクル

Slide 46

Slide 46 text

setStateでUIを更新する 46 Stateを操作して、buildを呼び出す ➔ StatefulWidgetが利用できる setState を呼び出します。引数はVoidCallbackです。 ◆ setStateの中でデータの更新処理を書きます。 ◆ build全体が呼び出されるので、この Widgetだけ!という制御はできません。 ◆ この例ですと、 _counterを参照しているWidgetの表示が更新される。

Slide 47

Slide 47 text

setStateのつらみ 47 https://note.com/mxiskw/n/n8e8f4fd1a77c ➔ データの更新が必要な箇所が増えるとだるくなる。 ◆ Stateのメンバ変数に依存してしまうので、ロジックの切り出しが難しい。 ◆ どこもかしこも似たような setStateが増えて、ボイラーテンプレ感が強くなる。 ◆ Widgetをふんだんにネストするようになると、見通しが悪くなる。 ➔ WidgetをまたいだUI更新が困難 ◆ ツリー上で離れた位置にある Widget の更新が難しくなる。setStateは自分のビルドを呼び出すもの であって、別のWidgetのビルドを呼び出すものではないため。孫画面→親画面的な。 ➔ setStateは利用せずに、Riverpodというライブラリに抱かれる現場が多い印象。

Slide 48

Slide 48 text

Riverpod is 何 48 ➔ Flutter界のロックスター、Remi Rousselet さんが作ったライブラリ ◆ データストア、UI状態管理、Mock差し替えができるツールキットが 1つになったもの。 ◆ 元々Flutter公式で「Provider」というパッケージがあったが、イケてない部分が目立つというこ とでゼロからRemiさんを中心に書き直された。 Flutter公式ではない。 ◆ FlutterにはInheritedWidgetというのがあり、Widgetを継承関係にすることで特定の Widgetに だけリビルドを走らせる仕組み がある。それを応用したもの。 ◆ RiverpodはProviderのアナグラム。denoとnodeと同じ関係。 ◆ 先日、Flutter公式YouTubeでも状態管理手法として紹介された。 Riverpodしか勝たん。 ➔ グローバルなデータストアを持って、対象の Widgetがそのデータをリッスンして UI再構築。

Slide 49

Slide 49 text

49 Riverpodの公式ページ https://riverpod.dev 状態管理=双方向なデータ更新が可能で、 キャッシュも可能なフレームワークを使う

Slide 50

Slide 50 text

Riverpod の概要 50 ➔ Providerを定義する。よく使うのはProvider/StateProvider/StateNotifierProvider ➔ 定義したProviderを自分がどう管理したいかを定義する。 ◆ read → その時の最新データを読むだけでよい! ◆ watch → データに変更があったら検知して、 Widgetをリビルドさせたい! ◆ refresh → データの初期化(コンストラクタ)を再実行したい! ◆ listen → 更新前/更新後の差分を管理したい! ➔ readを使う場面はWidgetの更新を伴わないデータストアを保持する時。 ◆ あとはRepositoryに該当するクラスのオブジェクトの DIなど。

Slide 51

Slide 51 text

freezedで自動生成しよう 51 ➔ freezedというライブラリを使うと、 JSONを 任意の型のオブジェクトに変換してくれる コードが自動で生える。 ➔ その他、copyWith等の便利メソッドも生 えてくる。 ➔ Union Typesやパターンマッチに近い コードを自動生成してくれる。 ➔ Dartは様々なコンストラクタの文法があ り、それが一番特色かなと思う。

Slide 52

Slide 52 text

Named Constructor 52 ➔ クラス名.関数でコンストラクタのオーバーロー ドが実装できる。 ➔ Flutter公式の Image クラスで確認できる。 ◆ 画像の取得先が異なると引数が違う ● ファイル(ローカル領域) ● メモリ ● ネットワーク ● アセット(アプリにバンドルされたファイル) ◆ 引数の型は違うが戻り値の型が同じな ので、オーバーロードと同義。

Slide 53

Slide 53 text

Factory Constructor 53 ➔ クラス名.関数は、Named Constructorと同じ。 ◆ Named Constructorは、同じクラスのインスタンスしか返せない ◆ Factroy constructorはサブクラスのインスタンスを返すことが出来る! ➔ デザインパターンの Factory Patternに由来する予約語なのかも。

Slide 54

Slide 54 text

Whenでパターンマッチ 54 ➔ freezedを使うとwhenメソッドが自 動生成され、サブクラスのインス タンスによるパターンマッチが出 来る。 ➔ Kotlin / Swiftではデフォルトであ る言語仕様だけど、 Dartには 2023年1月時点では無いので、ラ イブラリに頼っている。 ➔ Dart3に期待!(2023 Mid)

Slide 55

Slide 55 text

AsyncValueで非同期処理 55 ➔ 非同期処理の制御はフロントエンドの華。 ◆ RiverpodにAsyncValueで、ステータスに応じてパターンマッチするのが簡単。

Slide 56

Slide 56 text

Flutter Hooks 56 ➔ ReactのHooksにインスパイアされたライブラリ。 ◆ useState → 毎度おなじみ。Flutterの場合は、xx.value で値を更新する。 ◆ useTextController → TextFieldの初期値セットや入力値を知るのに使う ◆ useTabController → Tabのタップ・スワイプのイベントなどを拾う ◆ useEffect → initStateの代わりになる。ビルド時に副作用を発生させる。 ◆ useMemoized → 何回ビルドが走っても初期値をキャッシュ。 ◆ useFuture → ビルド時に非同期処理を実行する。 useMemoizedと併用する。 ➔ Hooksには「使いたくなる魔力」がある。関数単位で状態管理ができるのは気持ち良い。 ◆ Hooksに慣れているチームなら Hooksのノウハウを活かせたほうがいいかも https://pub.dev/packages/flutter_hooks

Slide 57

Slide 57 text

Flutter Hooks (useState) 57 ➔ 引数に管理するデータの 初期値を入れる。戻り値 はValueNotifier ➔ .value に新しいオブジェ クトを代入するとリビルド が走る ➔ HookWidgetを継承する 必要があります。 ➔ まぁ簡単。素敵。

Slide 58

Slide 58 text

Flutter Hooks (useFuture/useMemoized) 58 ➔ useFutureで非同期処理を実行 ◆ Riverpodでローティング の出し分けをしている。 ◆ whileLoadingの引数は Function Futureで、戻 り値がFuture ◆ useFutureは毎回実行さ れるため、memoizedで キャッシュ wasabeefさんレポジトリより

Slide 59

Slide 59 text

Flutter Hooks (useEffect) 59 ➔ appLifecycleが変わると useEffectの第1引数の 関数が実行される。 ➔ リスナーとしてuseEffect を使うこともできるのかと 勉強になった。

Slide 60

Slide 60 text

使用した主なライブラリ 60 状態管理等 Riverpod, flutter_hooks, freezed HTTP dio, retrofit ローディング flutter_easyloading チャット flutter_firebase_chat_core,flutter_chat_ui 広告 admob(google_mobile_ads) App内課金 in_app_purchase Firebase core,auth,firestore,analytics,crashlytics,storage,clo ud_function

Slide 61

Slide 61 text

チャット(flutter_chat_ui, flutter_firebase_chat_core) 61 ➔ よくあるチャットのUIを作ってくれる。 ◆ 多くのオプションが用意されているので、 UIカスタマイズはやりやすい ◆ イベントハンドラも豊富にある。 ➔ バックエンドは自分でやりなさいというもの ◆ Streamだけ公開されていて、 バックエンドはお前がやれです ◆ 同じ開発者が公開している「 flutter_firebase_chat_core」 と組み合わせ、Firestoreをチャットの バックエンドとして組み込むことができます。 ◆ 凄くシンプルなライブラリでコードも読みやすいが、チャットする以外の機能はほぼゼロなので、 バックエンドのFirestoreは自前のほうが良いかもです。

Slide 62

Slide 62 text

広告(admob) 62 ➔ バナー広告やリワード広告を実装できる ◆ 実装自体は極めて簡単。設定さえ間違えなければ。 ➔ ユーザーは非常にせっかちなので広告の表示が遅いと離脱される ◆ UIをビルド後に広告を読み込む書き方にすると、 1秒はかかる。その間に別のページに遷移して しまうユーザーがすごく多い。ビビるぜ。 ◆ インタースティシャル広告とネイティブ広告以外はプリロード不可のようです。 ◆ 先に読み込む(Preload)できるものは、Preloadしておくのが吉。 ◆ 自分はバナー広告とリワード広告を使ったので Preloadできなかった。Googleとしてプリロードは NGらしいので。Google Group参照。 https://groups.google.com/g/google-admob-ads-sdk/c/OAGAtvMJyXE

Slide 63

Slide 63 text

アプリ内課金 63 ➔ すごおおおおおおおおおおく面倒 です。色んな準備が必要。 ◆ RevenueCatというアプリ内課金 or サブスクのマネジメント SaaSが良さそうです。 ◆ $10k/月まで無料で、そこから $1K毎に$8が課金されるけど、安いと思う。 ➔ In_app_purchaseで頑張りましたが、ベストプラクティスがない領域。 ◆ サーバーサイドのコードもガッツリ書く必要があります。 ◆ 1つは購入時に渡されるレシートの検証。 iOS / Androidでバラバラです。 ◆ もう1つはサブスクの通知です。 SlackのWebhookみたいなノリで飛んできます。 ◆ サブスクは購読・中止・解約・再開等、色んなイベントが起こります。 ◆ 今の所大きな問題はないけど、ちょっと不安です。運用経験が薄いので。

Slide 64

Slide 64 text

アプリ内課金(レシート検証) 64 ➔ アプリ内課金で最も面倒なのがこれです。 ◆ クライアントからApp内アイテムの購入リクエストを出す。 ◆ プラットフォームからレシートが返却される ◆ 返却されたレシートをプラットフォームの検証サーバに投げる ◆ 正当性が確認されたら購入完了とみなす。不正購入を防ぐために面倒になってる。 ➔ レシート検証の検証内容が明文化されていない ◆ 各プラットフォームでは明文化されておらず、開発者任せ。見つけられなかった。 ◆ iOSがだるい。サブスクと消耗品でレシートのレイアウトが異なる。 ◆ リストア処理(iOSではマスト)でも、同じ検証を行う必要がある。 ➔ iOS及びAndroid双方に個別のデコード処理が必要です。レシートの中身について。

Slide 65

Slide 65 text

アプリ内課金(サブスク通知) 65 ➔ サブスクが発生すると、任意のエンドポイントにリクエストが飛んでくる。 ◆ iOSはJWT形式、Androidはbase64エンコード。 ◆ JWTのヘッダのデコードをやったことがなく、ハマった。証明書チェーンなる概念を知らなかっ た。X.509証明書のことが少しわかった気がします。 ◆ 各プラットフォームで各々 10数個のイベントがあり、イベントが発生するとリクエストが飛ぶ仕組 み。とりあえず飛んできたら DBに保存するのが鉄則。 ◆ 200以外を返しちゃうと Appleは一定回数がすぎるとリクエストが飛ばなくなる。 Googleはデフォ ルトでエンドレスに再送信される。 ◆ 更新通知ならリワード付与、解約通知ならプレミアムユーザーから一般ユーザーに戻す等の処 理を行っています。

Slide 66

Slide 66 text

Lintはpedantic_monoで 66 ➔ みんな大好きLint。眺めてるだけで勉強になりますね。 ◆ 良い(人間にとってストレスのない )コードを書く習慣を身につけるもの ◆ ロジックの中身のレビューに集中できますね。 ➔ 日本のFlutterエンジニアのオピニオンリーダー的存在、 mono0926さんのLint ◆ https://pub.dev/packages/pedantic_mono ➔ Lintは後から導入すればするほど対応コストが高くなるので。。。 ◆ できればプロジェクト開始当初から導入しましょう。 ◆ 「use_build_context_synchronously」は無視してます。 ◆ 書き方を直してもらえると勉強になって楽しいですね。 https://dart-lang.github.io/linter/lints/index.html

Slide 67

Slide 67 text

Firebaseと戯れる アプリ開発でFirebase使わない人いないのでは 7 67

Slide 68

Slide 68 text

Firebase is 何 68 ➔ Googleが買収した、BaaSプラットフォーム。アプリ開発のマブダチ。 ◆ Cloud Firestore → KVSなデータストア ◆ Firebase Cloud Messaging → プッシュ通知 ◆ Firebase Authentication → ソーシャル認証 ◆ Cloud Functions → AWSのLamdba ◆ Cloud Stroage → AWSのS3 ◆ Crashlytics → アプリのエラーを検知してトラックし、レポート生成。 ◆ Analytics → アクセス解析。カスタムイベントを送ることも出来る。 ◆ Dynamic Links → よくある「アプリで開きますか」的な URLを生成する。

Slide 69

Slide 69 text

Cloud Firestore 69 ➔ KVSなデータストアです。 ◆ テーブルに該当する概念はコレクション ◆ レコードに該当するのはドキュメント ◆ ドキュメントの読み込み・書き込み件数に応 じて課金が入ります。 ◆ スキーマレスです。ドキュメント単位で全然 違う構造のデータを入れられます。 ◆ 「卒業生」を多数輩出しています ... 癖がスゴい! by 心の千鳥ノブ

Slide 70

Slide 70 text

70 https://zenn.dev/mitsuruokura/articles/5ec6511efeff48

Slide 71

Slide 71 text

71 https://speakerdeck.com/keisuke69/migrate-from-firebase

Slide 72

Slide 72 text

Firestoreのデータ取得における制約(1) 72 ➔ RDB脳では考えられない制約が・・・ ◆ ==での検索はすごい得意です。どのフィー ルドでも何個でもネストできる。 ◆ ”>=, <=, !=” 等の比較演算子の利用に制限が ある。1つのフィールドしか使えない。 ◆ WHERE price >= 5000 and stock > 0 はダメ です!! stockAvailable == trueならいける ◆ 「==」と「>=」はOK。複合インデックスの構築が 必要ですけど。 卒業したくなる背景もわかる

Slide 73

Slide 73 text

Firestoreのデータ取得における制約(2) 73 ➔ 数字や文字などのスカラー値の OR検索にはin 句が用意されています。 ◆ IN句に入れられるのは最大 10個まで。 ➔ リストの場合は、array-contains を使う。 ◆ やっぱり10個までしか入らない。 ➔ in array-contains array-contains-any は WHEREで共存できない。1個だけ。 ◆ 最大10個までしか入らないIN句が1つだけ使 える。あとはわかるよな?な? ➔ 1つのドキュメントに入るデータは 1MBまで。 IN句に入れられる要素は 10個まで

Slide 74

Slide 74 text

Firestoreのデータ取得における制約(3) 74 ➔ 集計関数が存在しない (最近になって、count関数がオフィシャルでリリースされた) ◆ GROUP BYがないので、sum/max/min/avg等の集計関数がない。 HAVINGあるわけない。 ◆ どうするかって?クライアント側で頑張る or Cloud FunctionsでViewを作る等。 ➔ EXISTS / NOT EXISTS / サブクエリ/ Window関数、当然ございません。 ➔ SELECT文もない。このフィールドだけ取得するという構文がありません。 ◆ SELECT文でデータを加工するという発想がゼロ。 CASE式なども当然ありません。 ➔ データ取得の制約がビジネスモデルの変遷についてこれなくなる恐れアリ。 ◆ 卒業生を生み出している背景に共通しているのはこの点ではないかと、と。 集合演算が存在しない。 GroupByがないので

Slide 75

Slide 75 text

Firestoreで比較を使わないテクニック 75 ➔ 全部AND条件で絞っていいなら、やれなくもない。 ➔ Mapのキーに条件、値にTrueを当てれば、複数条件の絞 り込みができる。TrueMapって言うらしい。 比較を全てTrue/Falseに置き換える

Slide 76

Slide 76 text

RDBとKVSのデータモデリング 76 ➔ FirestoreのデータモデリングはRDBより難しい。制約が強いから。 ◆ RDBはOne Fact, One Place/ ライフサイクル管理を意識すれば及第点になるはず。 ● RDBってテーブル追加 or カラム追加の2択しかないんで。やれることが。 ● テーブル分割で複雑さを吸収し、吸収した複雑さをSQLで単純に出来るが腕の見せ所。 ● 詳しくはそーだいさんや川島さんにお問い合わせ下さい。 ◆ 限定的なユースケースから投入するのが無難に感じる。ビジネスは Firestoreの制限を良しとし てくれないし、できない要件をできるようにはできない。 PaaSの制約だから。 ◆ B向けの場合セキュリティルールでは担保できない要件 (IP制限/ロール制御等)があり得る。出て きたらぶった切るしかないのかもしれません。 KVSで全部やりきるのはマジで難しいと思う

Slide 77

Slide 77 text

こういう検索は無理 77 ➔ Favomatch開発当初、Firestoreをデー タストアに出来るかどうかも、検討し た。スキルセットな問題で。 ➔ 右記のようにSQLにおけるEXISTS or NOT EXISTSをネストする仕様は無理 と 判断し、RDBにした。 ➔ 限りなく正しい判断だと思ってる。 僕は無理だと判断した

Slide 78

Slide 78 text

簡単なチャットの設計 78 User - nickname - avaterUrl - createdAt - updateAt rooms - roomName - imageUrl - createdAt - updateAt - userIds[List] - lastSeen[List] - lastMessage - messages[collection] messages - authorId - text - type - createdAt - updateAt - status flutter_chat_firebase_coreの設計を元にアレンジ ➔ 基本的には、ユーザー・ルーム・メッセージの 3つ。 ◆ LINEのようにメッセージ単位で既読にする場合は、 Cloud Functionsで頑張ることになりそう。 ◆ messageが作成されたら、その部屋にいるか否かを検知して、いるなら statusを既読に更新等。

Slide 79

Slide 79 text

セキュリティルール 79 ➔ Firestoreは直接クライアントからデータをCRUDするコードを書く前提の代物。 ➔ そのため、セキュリティルールが存在する。 ◆ ドキュメント or コレクション単位でCRUDできる権限を指定するものです。 ◆ FirebaseAuthで未認証のユーザーは一切何もできない、とかですね。 ◆ チャットにぶら下がったメッセージは、 userIds というコレクションの中に自分の userIdがない場 合、一切のCRUDができない。という感じのルールが作れます。 ◆ セキュリティルールのテストは DockerのFirebaseエミューレーターイメージを活用。 ➔ RBACを期待していると痛い目にあいます。 ◆ ロールの概念がないので、ロールに沿った権限を表現するとすぐカオスになる。 firestoreはクライアントから直接データを更新する前提の代物

Slide 80

Slide 80 text

セキュリティルールの例 80 ➔ ドキュメントIDがFirebaseAuthのuserIdと同じでなければ、読み取れない設定例。 ◆ 自分以外の他のユーザーに対して、usersに入っているデータは見られないようにしています。 独自のフォーマットで書きます。

Slide 81

Slide 81 text

Cloud Functions 81 ➔ サーバレスで任意の処理を書くことが出来るやつ ◆ AWSのLambdaみたいなもの。Node/Python/Ruby/Go…お好きなランタイムでどうぞ! ➔ HTTPかイベントドリブンで発動することが出来る ◆ GCP上のサービスが持っているイベントをトリガーに処理を走らせることができる。 ◆ Firestoreのusersコレクションに新規にドキュメントが作られた、みたいな感じ ◆ messagesコレクションにcreateされたら、PUSH通知を送るなどを書いている ➔ FIrestoreの制約とうまく付き合うための緩衝材というイメージが強い ◆ 例えば、プロフィールに公開したい項目とそうでない項目があった場合、Firestoreではフィールド単位のアクセス 制限はできないので「公開用」「非公開用」でコレクションを分ける処理をCFで書くなど。 AWSのLambdaみたいなもんだね

Slide 82

Slide 82 text

Cloud Functionsの実例 82 https://docs.flyer.chat/flutter/firebase/firebase-cloud-functions ➔ roomsの任意のドキュメントでメッ セージが作成されたら、 lastMessagesというリストを書き換 えるというCloud Functions ➔ Firestore と Cloud Functionsだけ でイケるんじゃねって思うかもしれ ないけど、こんなトリガーがいっぱ いあったら、カオスになるような気 がしてならない。 ➔ あんまり使い込むもんじゃないと思 いますぞ、個人的にはね。

Slide 83

Slide 83 text

Firebase Cloud Messaging 83 ➔ PUSH通知を送ることが出来る。これがないとアプリの意味がないレベル。 ◆ 端末にデバイストークンが発行され、トークンに対して通知を送る。 ◆ 一斉通知の場合は「トピック」を作る。 Slackのチャンネルみたいな感じ。 ◆ トピックに対し短期間に連続してメッセージを送ると Too Manyって言われて怒られます。気をつ けましょう。狙い撃ちなら、デバイストークンで PUSH通知を送る。 ➔ バックグラウンドリスナーが鬼門で動かないことがあった。 ◆ アプリが起動していない状態でも通知は受け取れる。ここまではよい。 ◆ 起動してない時にアプリのバッジを更新する処理がバッググラウンドリスナーの例。 ◆ iOSで苦戦。なぜか動かない。 Whyなぜに。 これがないと生きていけない

Slide 84

Slide 84 text

通知を送る時のフォーマット 84 ➔ 通知を送る一定のフォーマットがある。 ◆ Androidはpriorityをhighにする ◆ APNSはiOS専用の設定 ◆ content_available, mutable_content を Trueにセットする。これで OSが受け取った 通知をアプリリダイレクトしてくれるような雰 囲気の記述が公式にあった。 ◆ tokenは複数ある場合がある。 2台持ちと か。なので配列で渡す。 プロダクションのコード持ってきました

Slide 85

Slide 85 text

Method Swizzling よーわからん 85 ➔ info.plistで「FirebaseAppDelegateProxyEnabled」を「false」にする。 ➔ これをやらないとバックグラウンドリスナーが動かなかった。 iOSで。 https://firebase.google.com/docs/cloud-messaging/ios/client#method_swizzling_in iOSなんもわからん

Slide 86

Slide 86 text

Firebase Cloud Messaging(Flutter) 86 バックグラウンドリスナーはエントリポイントである main関数内で定義する必要がある。 @pragma(‘vm:entry-point’)というアノテーションが必要だった。

Slide 87

Slide 87 text

Firebase Authentication 87 ➔ SNS認証・電話番号認証・メール認証などを組み込むことが出来る。 ◆ 昨今のソーシャル認証は、全部これで実装しているのではなかろうか? ◆ 電話番号認証はお金が発生することがある。 ◆ カスタム認証(LINE認証と連携する等)もできる。 ➔ iOSはAPNs Keyが必要、Androidはフィンガープリント(SHA-1/SHA256)が必要。 ◆ これらをアップロードしないとあかん。認証だけじゃないけれど。 ◆ Androidはdebugビルド、releaseビルドでフィンガープリントが異なるので注意。 ◆ AndroidはGoogle Playに用意されたアプリ開発者専用のフィンガープリントを登録しないと、 Google Playに配信した時だけ認証がコケるという罠があるので気をつけたい。

Slide 88

Slide 88 text

authStatusChangesを拾え 88 ➔ 認証ユーザーをcurrentUserというプロパティでアクセス可能。 ◆ しかし、このフィールドは Null許容型になっている。 ◆ 認証してない場合もあるなって思ったら、もう 1つNullになるケースがあった。 ➔ 認証後はCredential情報を端末のローカルに書き込むらしく、そいつが正当なのかを問い 合わせて認証済みであるかをチェックしている。 ◆ そのコールバックが authStatusChanges ◆ このコールバックを通さないと、 Firebase認証済なのに認証されていない状態でアプリが起動し てしまう罠があった。ごくまれにこういう事が起こる。 ◆ 公式ドキュメントにしれっと書いてある。一番前に持ってきてほしいなぁ!

Slide 89

Slide 89 text

89 https://firebase.google.com/docs/auth/flutter/manage-users 公式ドキュメントのスクショ

Slide 90

Slide 90 text

これは本質情報なのですが 90 Firebaseは特にそう ➔ FirebaseのようなmBaaSを使う場合、ハマる時は大抵コード以外に原因がある。 ◆ SDKへの理解・知識不足が原因になることが多い。自分はそうだった。 ◆ Exceptionの内容を見ても「error_no=10ですか!それで?」みたいな事が多い。 ◆ 設定方法が間違っている or バージョンアップした時に変わっている可能性もある。 ◆ OS固有のパラメーターがあり、それを設定しないと解決しないこともあった。 ➔ 前提知識がないと解決できない=コード以前の問題。 ◆ 公式ドキュメント(英語)を関係なさそうとか判断せずにまずは全部見よう。 ◆ StackoverflowよりもGithubのissueを漁る。情報が新しい事が多いから。 ◆ 読み込む必要はさほどない。まず翻訳かまして、ざっと眺めて拾っていくのが良い。

Slide 91

Slide 91 text

Flutter Testing RiverpodとMockTailでやっていきだ 8 91

Slide 92

Slide 92 text

Flutterには3つのテストがある 92 Widget Testで留める現場が多いのでは? Unit Test ビジネスロジック等を テストするためのもの。 あまり使ってない。 Riverpodの単体テストなどを書 いている人もいるみたい。 WidgetTestで担保すれば良い のではと思ってしまう。 Widget Test Widgetをエミュレートして、 UIの動作確認を行うテスト。 外部接続・ローカルのファイ ル読み込み等が一切できな いが、高速に動く。 テストコードはコスパ重要だ と思っているので、何の指定 もないならここだけを書く Integration Test いわゆるE2Eテスト。外部通 信もどんとこい。 FlutterでE2E書いて回して るって話、個人的に聞いたこ とがない。大抵はチームが 分かれるので。 どうしても必要な箇所だけ書 けばいいと思います。

Slide 93

Slide 93 text

Widget TestとMock 93 ➔ Widget Testでは外部接続が一切できない。 ◆ ネットワーク接続、sharedPreference、ローカルDBのアクセス不可 ◆ Widgetから直接この種の処理をベタ書きすると終わり。差し替えられない。 ➔ データアクセスを伴う処理は「メソッド単位で」差し替えたくなる。 ◆ RepositoryクラスをまるっとMock。 ◆ Mockしたメソッドの振る舞いを上書きする。 ◆ Riverpodの override機能を使ってmockしたクラスをDIする。 ◆ これで本番コードを一切汚さず Widget Testが実行できる。 外部接続を伴うコードを Mockする

Slide 94

Slide 94 text

MockTail with Riverpod 94 これでテストを書いていたのですが ➔ MockTailで、Fakeのレポジトリクラ スを作る ➔ メソッドの振る舞いを定義 ➔ Widgetを起動してfindXXして、ア サーションを実行。比較対象は Widgetになる。 ➔ https://qiita.com/KKusumi/items/f 458a42bbbf1958ad8d1

Slide 95

Slide 95 text

Fakeクラスで充分かもしれぬ 95 ➔ Flutter公式のテスティングライブラリに Fakeクラ スがあります。 ➔ Mocktailとほとんど同じだけど、メソッドの引数・ 戻り値を複数ケース用意できない。 ➔ 自分はMockTailで慣れちゃったけど、 Fakeで充 分かも。公式ってのが良い。 Mocktailは、ここ 10ヶ月更新がないのがちと心配。 シンプルで分かりやすいです

Slide 96

Slide 96 text

Widget Testの観点 96 正常系のデグレを検知するためのものだと思う ➔ イベントが適切に動くかを重点的に書いている ◆ タップ、スワイプ、スクロール、画面遷移、ダイアログ ON/OFF ◆ これが意図した状態で動かないとマジで死亡。 ➔ 状態の変化に応じたUIの切り替え ◆ 色が変わる・ボタンが押せる押せなくなるなど。 ◆ 商品一覧→詳細→カート追加→ボトムタブからカートへ →最新化されてる!とか ◆ 検索条件を追加する度に「 XX人が該当します」みたいな UIのテストとか。 ➔ アイコンはこれじゃないと!みたいな UIデグレを拾うテストはほぼ書いてません。 ◆ UIのデザインレベルのデグレを拾う良い方法を知らないのもある。スクショ比較?

Slide 97

Slide 97 text

Flutter Hooks Library 97 wasabeefさんが精力的にメンテされている ➔ Flutter Hooksの便利カスタムHooksを集めた flutter_use ➔ Flutter Hooksを使ってWidget Testを簡便に書けるflutter_hooks_test等がある。 ➔ Hooksに慣れたチームであれば、Riverpodをグローバルなデータストアとして活用して、 UI の描画まわりは flutter_hooksで統一して良いのではないでしょうか。 ➔ Flutter_Hooksは、バージョンが0.18.5。1.0になる気配が見えない。 ◆ 破壊的変更がほぼないので、枯れてきているのかなと感じるぐらい。 ◆ 1.0にならない背景はよくわからない。

Slide 98

Slide 98 text

アプリの難しさ 98 Webと違って修正が即時に適用できない ➔ ネイティブアプリは、Webと違って即時に修正できない ◆ AppStoreやGoogle Playにリリースするまでのタイムラグがある。 ◆ アップデートの強要はできない。強要させるダイアログは出せるけど。 ◆ 複数のバージョンが共存する前提で、サーバーサイドは組まないといけない。 ● JSONのスキーマ、追加は簡単だけど変更するのは難しくなります。 ➔ 実行時例外が即死につながる。 コンパイル段階で可能な限り潰す。 ◆ 最大の敵は「NullPointerException」であります。即クラッシュにつながってしまう。 ◆ Lintで実行時例外が出る可能性があるなら警告出して潰せるのが理想。 ◆ ライブラリ・Flutterのコア・Firebaseなどで実行時例外が出るケースが多い(苦悩

Slide 99

Slide 99 text

アプリの難しさ その2 99 特定の端末・ユーザーに不具合が出る ➔ ネイティブアプリは、100人中98人は動くけど2人は動かない的なものが多い ◆ チームメンバーの端末では動くが、ユーザーから不具合報告があがる事が多い。 ● このユーザーだけローディングが終わらないんですけど... みたいな ◆ ライブラリのバグもあって、画像のキャッシュのライブラリで数名例外はいてた。 ◆ バックエンドに比べて環境依存・ユースケース依存のバグが多く、癖が強い。 ● 画像も数枚ならいいけど、 50枚フェッチするとあかん、とか。 ◆ AndroidのSamsungの機種だけにバグ報告が上がっている issueがあったりする。 ◆ 実行時例外の多くが、 Flutterコア/ライブラリの内部コードで引き起こされる。 ➔ 不可解な不具合を踏んだら、まずは使ってるライブラリの issueを漁ろう!

Slide 100

Slide 100 text

流れの速いFrondEnd 大切なのは思想(お気持ち)の理解 9 100

Slide 101

Slide 101 text

フロントエンドのおもしろさ 101 ➔ フロントエンドが「設計」する対象が拡大し続けている ◆ Google MapのUIが2005年に誕生して、17年が経過した。あの UIは衝撃だった。 ◆ ページの表示→イベント実装→状態管理/ロジック実装→コンポーネント設計→そして伝説へ ◆ コンポーネントを適切に作って開発者体験をあげていく。その結果、 UXが上がる。 ◆ Developer Experience重要。 ➔ ヒトの導線を設計する面白さを感じている ◆ 「どういう情報を、どういう見せ方で提供すれば、腹落ちしてくれるのか?」を考える。その過程 が好き。要件定義が好きだったのもそれの延長線上かも。 ◆ ノーヒントでタスクを渡され、ユーザーはスッと入れなかったら負けじゃん。やっぱ。 ◆ 導線を実装する武器を強くするために、モダン・フロントエンドに入門しますた。

Slide 102

Slide 102 text

FEは抽象的な概念が多い 102 各プラットフォームのお言葉を噛み締めないといけない ➔ フロントエンドは特に抽象的な概念が多い気がする。バックエンドに比べて。  ◆ 似たような話なんだけど言葉が全然違っていることも多い。アーキテクチャの話が多い。 ● Flutter → StatelessWidget, StatefulWidget ● iOS → UIWindow, ViewController, IBOutlet ● Android → Activity, Fragment, BindView ● Windows → Form, UserControl, ViewModel ➔ カタカナを鵜呑みにせず、言い換えて自分の言葉に出来る必要がある。 ➔ 人間が絡む世界は複雑なんでしょうきっと。ほっほっほ。 ➔ 自分もFlutterのコードを最初見た時は何これ状態でした。

Slide 103

Slide 103 text

“お気持ち”を理解することに務めるのがFE修行かもしれん 103 FWの勃興にペインあり。ペインの腹落ちをする努力。 ➔ フロントエンドの速さは思想のアップデートの速さだと感じる ◆ Reactが特にそう。シンプルな APIセットがたくさんあって、これをお前らナイスに使えというフレー ムワークは、思想の理解がないと戦える気がしないんですね。 ◆ 言語仕様だけではなく、ビルドやランタイム回りも思想のアップデートが速い。 ● node → deno、webpack → vite 等。 ● アイランド・アーキテクチャ のようなJS配信まわり。 ● レンダリング1つとっても 、色んな考え方が存在する。 (CSR/SSG/SSR/ISR) ● バンドルサイズを縮小することがパフォーマンスに直結する世界線。 ● GraphQLに代表されるエンドポイントまわりの考え方も色々ある。

Slide 104

Slide 104 text

Flutterはそこまで速くないかも 104 全てがOSSのWebモダンフロントエンドに比べるとね ➔ Webアプリに比べると追いかける対象は少なくてよいのかな、という印象 ◆ 環境構築・ビルド周りはプラットフォーム依存なのである意味楽。もちろんアプリサイズは小さい に越したことはないけど、バンドルサイズとパフォーマンスは直交しない。 ◆ CSSやHTMLがなく、Widgetしかない。Material Designありきなので、ある意味楽。 ◆ Flutterのコア、人気のあるライブラリの更新速度はかなり速い。 issueが多いのでね... ➔ 状態管理の流派はたくさんある。 公式もお前ら好きにしろ状態。 ◆ 状態管理の仕組みでアーキテクチャの大半が規定される。 ◆ 僕のまわりではRiverpod推しが多い。Remi is GOD.

Slide 105

Slide 105 text

テンションが上がるものに出会えた 105 Flutterフォーーーーゥ! ➔ 2019年頃にエンジニアとしての頭打ち感を強く感じてた ◆ 当時よく書いていたのは Pythonでしたが、書いているだけって感じでした。 ◆ 発想が変わらないのでエンジニアとして頭打ち感 ➔ Flutterに出会えたおかげで、新鮮な驚きがたくさんあった ◆ プログラミングを覚えたての頃に戻った感覚。四十の手習い、楽しいです。 ➔ 2023年はTypeScriptをちゃんとやりたい。表現力を活かしきれていない。 ◆ まずは type-challenges から始めます。 ◆ T3 Stackの開発体験にビビッときたので、これをやっていきたい。 ◆ GraphQL興味あります。スキーマ駆動の向こう側へ。

Slide 106

Slide 106 text

Fluterは天下を取るかもしれぬ こんなお気持ち、OSSのフレームワークに感じたことはなかった。 行けるところまでFlutterと付き合って、少しでも恩返しがしたい。 裾野を広げることにちょっとでも貢献できたら嬉しい。 106

Slide 107

Slide 107 text

107 https://speakerdeck.com/wasabeef/flutterkaigi-2022-keynote?slide=26

Slide 108

Slide 108 text

Happy Development Experience with Flutter! Thanks! 108 フロントエンドの海をもう少し泳ぎたいのだ ◉ @gothedistance ◉ [email protected]