はじめに
年末なので言いにくいことを書く。
私はFlutterを本業として3年以上やっており、またReactNative1は(期間内での取り組みの濃淡はあれど)6年以上やっています。
現在、本業ではFlutterに取り組み、副業でReactNativeに取り組んでいます。そんな中で今年Flutterに取り組んでいて特に思ったことを書こうと思います。
これからFlutterの悪口を書くのですが、しかしFlutterは学習ハードルが低く、割と早くそれなりの品質のアプリを出すことが出来るというのは大きな強みです。 いろんな意味合いを含んだ表現ですが、こと日本の受託案件によって制作されたアプリのクオリティは向上したように見受けられます。ここは認めるべき大きな利点ではあります。
それから、今後の改善でFlutterやその取り巻きが改善されていくかも知れない。明日は今日よりも良い日になっているはずです。とはいえ、今日の苦しみ自体はまた事実として存在します。それを書き留めるのもまた未来への価値があるのかも知れません。
少なくともこの記事はお前に宛てた記事ではない
この記事は、FlutterとReactNativeを横断して実装している自分から見た、Flutterの気に入らないところを上げている文章です。
技術を主体的に選ぶ視点を持ち得ないビギナー とか、 単にアプリを作るという目的が果たされればそれで良い立場の人 からしたら、ここに書かれていることなどどうでも良いように思います。
また、(RNのときに同様の構造はよくあったけれど)Flutterを選ばない理由として記事引用されるのも、まぁ自分が書いている内容に自信はあるんだけど、別によその誰かの記事を引用せずとも、君の気に入らないという意見くらい自分の言葉で表現したらどうか?とも思います。
まぁそんなExcuseを並べつつも本題に行きます、レッツゴー。
①: Flutterチームの方針決定のベクトルが俺好みではない
Forkしたくなる気持ちは分かる、分かってあげられるよ。。。2
とはいえ同情するのは、母屋(Google)の調子が悪い余波を多少受けており、更に規制当局からの締め付けも厳しく、分割・解体論まで出始めているところです(実行性は疑わしいが)。 レイオフに伴うFlutterチームの減員があったりしたなかで、やることをやっているのは理解するものの、その以前・以後を見ると我々にすぐ効くような改善を感じられなくなっている。 人員数が少ない中で、本来すべきこと・しないことを判断することは死活問題に関わるので、貧するときほど判断能力は問われると、僕は思うのですが。
WebやWasm対応は個人的にはそんな要らない、にもかかわらず、Flutterチームはリソースを注ぎ続けている
- Flutter Webで作られた、Flutterをちゃんとやってる人達が作った、FlutterKaigiのWebサイトがあんな感じなので、純粋なWeb Frameworkとは品質にはるかに差があることは残念ながら明白
- そもそもそういう方向性には不向きなのにWebサイトとして使ってる技術選定がヤバいのかも知れません
- Webサイトではなく、ヘルプページのような「閉じた」ページとか、カジュアルゲームとかだったらアリだと思う
- ちょっと具体が言えない話ですが、実際にアプリのヘルプページをFlutter Webでやって体験を一致させているプロダクトは、ある。
--dart-define-from-file
のNative側反映をサイレントでdropする判断はあり得ない
- この機能は地味だがFlutterの特色だったと思う
- しかしこの機能は3.19の開発中に削除され、それがbreaking changesページで知らされることもなかった
- このような機能は3rd partyで補完するには大変であり、出来れば公式機能としてあったほうが良いのだが、それを捨ててしまったのは本当に残念
Flutterチームの推奨アーキテクチャ構成が出ていたが賛否あるような感じ
- アプリアーキテクチャ のページができた
- 「MVVMって言ってるけどMVCのほうが適切な名付けじゃないの?」というIssueが立った
- 僕はこういうアーキテクチャガイドラインは初学者向けであって、中級者以上は自分の好きな概念を作り上げられるから要らないと思っている。
- だからこそ初学者が正しく理解をしているか不明瞭なMVVMという言葉を使わず、そういった概念を説いた方が良かったと思う(Unidirectionalなアーキテクチャだと言うに留める)
- あとこのアーキテクチャは公式の資料であるが故に公式のコンポーネントで物事を解決しようとしていることに留意。Riverpodなどは使ってない(それはそう)
一応擁護すると、アプリアーキテクチャのページはMVVMどうのこうのという話を置いとくと、例えばディレクトリ構成などは「なるほどね」ってなるので一読の価値はある。
Decorator、うーん
- FlutterInProductionというイベントの中の後半で紹介された話
- あくまで検討中の機能という温度感なのかも知れないので、情報の取扱いについてはなんとも言えないが。
- そのなかでDecoratorというコードシンタックスが紹介された
- Flutterでは伝統的に、あるコンポーネントを装飾するのにもおおむねコンポーネントを使う必要がある(themeとかstyleもあるけれど)
- Decoratorでは、あるコンポーネントを装飾するのに、コンポーネントから生えているメソッドをチェーンする(できるようにするという案)
- DecoratorはSwiftUIやComposeから影響を受けていると思われるが、それ必要なんか?
- 混在しないようにレビュー規則を敷くのか?
- Decoratorの実体が単に拡張関数なのであれば、WidgetやElementのツリーと実装表現が乖離する
- ネストが深くなることへの対応は、意味合い毎にコンポーネントを分割することで達成されるべきであって、それで今のFlutterでもうまくいくはずなので、必要性が見いだせない
②: Dart言語の技術的・ポジション的な問題
「Dart言語」などと言われているけれど、言語と言われるほどポータビリティがなく、乱暴に言えば「Flutterの為のDSL」でしかない問題。
近年利用されているプログラミング言語のなかで、中途半端に機能が足りてない
- あえてそのようにデザインされているGo言語はともかく、近年プロダクションで採用される言語と比較してDart言語には機能が足りていない
- 例えば children 内で条件分岐があるときの記述がイマイチ
- 配列をスプレッダで展開する必要がある e.g.:
children: [ if (cond) ...[ Text() ] ]
- 配列をスプレッダで展開する必要がある e.g.:
- 例えば Union type がDartに存在しないことで渋々Enumなどを使う事例はかなりある
- 機能が足りない故にコード生成を濫用しがちであるがしばしばビルドのトラブルにつながる
- macrosが導入されたらだいぶマシになるのではないかとは思う
サーバーレスアーキテクチャへの公式採用ランタイムがほぼ提供されていない
- AWS Lambdaは公式ライブラリが提供されていない
- AWS Lambdaのカスタムランタイムを用いるとDartも使えるのだが、それは「なんでも動かせる」のでちょっと違うかな
- AWSはともかくGoogle CloudのFirebase Functionsが対応していないのはいかんでしょ
- サーバー実装のためのフレームワークはある
- ServerpodやDart Frogなど。
- ただ、アプリからDart始めた人がいきなりホスティングが必要なものを選ぶのは、厳しいんじゃないかと思う。
Google Cloudを有するGoogleの製品であるDartがFunctionsで使えないのが本当に謎である。いや謎でもなくて、要するにGoogle Cloud側がDartをサポートする優位性がないと判断しているということで、政治的に負けていることが露呈してしまっていることが問題(無関係な企業がDartをサポートするしないを判断するならともかく、同一企業の製品で忖度もされてしかるべきものが忖度されずにサポートされない事実は重い)。
③: ベターな書き方を模索すると、けっきょくReactを書いた方がいいのではないか?と悩む問題
俺はいまのところこれに苦悩している。書き心地だけで言えばFlutterである必要がないのだよな。。。
FlutterのUI構築がクラス継承で作っていくのがバッドプラクティスを産む
クラス継承は便利。それはそれとしてUI構築でクラス継承が出来ることは混沌をもたらしてきた経験をしているので好ましく思わない。
- いまのモダンなUI開発は、クラスではなく関数(Function)ベースとなっている
- Android: Jetpack Compose
- iOS: Swift UI
- Web: ReactのFunctional Component (やReactフォロワーな言語体系)
- Flutterは
State(ful|less)Widget
などを継承してUIをつくるbuild()
メソッドをoverrideしてWidgetを返すcreateState()
メソッドが返す、State
を継承したクラスのbuild()
をoverrideしてWidgetを返す
- 常にフレームワークのクラスだけを継承しているならクリーンだが、なんらかの共通実装を用意するために
BaseStatelessWidget
などと出来る余地があるのがよくない- それはFlutter API以外の知識を必要とされるので、プロジェクトの新参者に余計な知識を覚えさせる必要が出てくるので良くない設計だと俺は思っている
- Androidにおいて
BaseActivity
を用意することが「オレオレフレームワーク」などと揶揄された時代が確かにあったんじゃよヨボヨボ…
Riverpodやflutter_hooksを導入するとFunctional Componentっぽく書けて大分マシになる
Riverpodやflutter_hooksは、モダンな開発体験を得られる。そうReactのようなね。
- https://riverpod.dev/
- https://pub.dev/packages/flutter_hooks
- UIに絡むロジック実装がきわめてReactライクに実装できる
- パフォーマンスは多少悪くなるらしい
これは別にFlutterでなくてもいいのでは・・・?
Flutterでアプリを作るために、Dart言語を用いて、Riverpodやflutter_hooksで実装するなら、React Nativeでアプリを作るために、TypeScriptを用いて、ReduxやHooksで実装するのと、どうしても対比が出来てしまう。
前者のフレームワークのために使われる技術構成(これはFlutterのための技術です)は、後者のフレームワークの技術構成(これはモバイルアプリだけでなくフロントエンドWebでも利用できる技術です)よりも「幅」が狭いんですよね。この「幅」は、バックエンド転用などのキャリアプランに関わる幅でもあるし、利用者数という意味での幅でもあるし、投資されているコスト面での幅でもある。
まぁそれは技術選定の都合しょーがないところもあるんだろうけれど、それを少しでも後押しするものがGoogleから出てこないのが残念(Cloud FunctionsのDart対応とか、なんでないのか不思議なくらいだ)。
そんなわけで、Flutterに取り組めば取り組むほどFlutterでなくても良い感じがしてきた今日この頃です。
終わりに
まぁとはいえ「モバイルアプリを誰でもサクッと書ける」ようになったのは間違いなくFlutterの功績である。3
若いチームとか数的不利のあるチームだったら技術選定でFlutterを選ぶことで、技術で困らずに組織作りに注力できそうだし、テックリード的な立場でもまだまだ検討候補には挙げられるフレームワークではある。
けれども、個人的にはどうも「天井に当たってる感」「スケールのしなさ」みたいなのを感じることがあり、プログラマーとしての僕は楽しさや深さを求めて、緩やかにFlutterから撤退していくような気がしています。
まぁでもそんな気に入らんところも改善されるかも知れないからね。どうなるかは神のみぞ知る。
-
正式名称は
React Native
という具合に単語間にスペースが入るが、組版上の都合でスペースを取り除いて記述することにする。 ↩︎ -
僕個人のスタンスとしては、“Fork"はPR出すのに普通にやる行為であるし誰でも出来るわけで、Forkされたことよりも、「どちらかというとFlutterを推進している人が」「意味をもって」Forkをしたというコンテキスト自体が重要だと思っています。Flockがどういう成果を出すかは成果物を見るまで判断できないからそれ自体には意味がないと思っています。 ↩︎
-
それゆえになんか変なサロン?的なものが乱立していて、個人的にヤな感じでもある。そういうグループ自体は否定しないけれど、マルチ商法とかには気をつけてね・・・。 ↩︎