Flutter に入門しました
こんにちは。支払い.comのサーバサイドエンジニアの水村です。
業務とは全然関係がないのですが、個人でアプリを開発しようと思い最近 Flutter を始めました。
Flutter 実践入門 という Zenn の記事や Flutter Doc JP を読みながらアプリの開発を進めています。
いろいろな情報があり大変助かっています😆
最初のアプリは飼っているインコの健康管理アプリ。Flutter 以外の選択肢として次のライブラリなどを検討しましたが、色々と考えた結果 Flutter を採用することに決めました。
React Native
普通にネイティブアプリを作る
Kotlin Multiplatform(KMM)
React Native
最初はなんとなく「マルチプラットフォームのアプリを作るなら React Native がいいのかな」と思っていたのですが、アプリ開発について少し調べていくと複数の選択肢があることがわかりました。
React Native も Flutter と同じように iOS や Android のアプリが開発できるフレームワークになります。React を使って開発を行うことができるため、普段 React を使って開発をしているフロントエンドエンジニアであれば、最初の学習コストが低く始められると思います。ただ、エラーが発生したときにネイティブ側のソースコードを追う必要があったり、アプリのバージョンアップに苦労するケースがある認識です。React Native に関しては、僕が参画している別のプロジェクトでも採用しているため、最初に候補に上がった形となります。特徴は以下の通りです。
Pros
React を使って開発を進めることができる
そのため、普段 React を書いているフロントエンドエンジニアであれば導入がしやすい
Cons
アプリのバージョンアップに苦労することがある
最近の事情はそこまで追えてないのですが、めちゃくちゃ破壊的な変更が入ってアプリ開発チームが苦労するのを見ていた(特に Hooks が入ったあたりのバージョンはやばかった)
エラーの解決にネイティブ側のソースコードを見ないとわからない事象がある(Objective-c のソースを読んだり、build.gradle の依存関係を調査したりなどの作業が発生するケースがある)
ネイティブアプリ開発に詳しいエンジニアが最低一人はいた方が安心できる
最近のトレンドを追ってみると、React Native よりも Flutter のほうが勢いがあるように感じられました。次の画像は Google トレンドで Flutter と React Native を比較したものになります。しかし、個人的には単純に今流行っているから採用するというのはアンチパターンだと思っています。技術的、ビジネス的な要件であったり、採用のしやすさであったり、3年後、5年後くらいにエコシステムがどうやって発展していくか、そもそも開発がしやすいのか、今後ネイティブアプリにコンバートする予定はあるのか・・などといったことも考えてから何を採用するか決めるといいのかなと思います。ただまあ、趣味と仕事は別だと思うので、趣味で何かを作る分には特に深く考えずに、自分が興味のある技術を試すことができるのでとてもいいですね✌️
普通にネイティブアプリを作る
ネイティブアプリで作るのもいいかなと思って検討しましたが、次の理由により別の手段を検討することにしました。
最終的には iOS, Android の両方でアプリをリリースしたい
Swift は簡単なアプリを作ったことがある程度、Kotlin は書けるが Android は未経験のため、開発工数や学習コストが倍かそれ以上かかりそう
開発速度やリリース速度を重視するプロジェクトの場合は、Flutter や React Native などのマルチプラットフォームなライブラリで開発してひとまずリリースし、会社の規模やプロジェクトの規模が大きくなってきた段階でネイティブアプリに置き換えるというやり方が良さそうに思えます。理由としては上記に書いた事項になるのですが、会社でネイティブアプリを開発するとなると、iOS, Android エンジニアをそれぞれ採用するのも大変ですし、人件費も倍かかり、iOS, Android のチームをマネジメントする必要があるので PM が複数人必要かもしれない・・などといった点を考慮すると、最初からネイティブアプリで作るのは結構リスクがあるかもしれないなと感じました。今回は個人開発なので考慮不要ですが、もし自分が技術選定をする立場にあり、チームの組成やマネジメントなども考慮するとなると、最初からネイティブアプリで開発するという判断を下すのはかなりリスクがあるように感じました。
ただ、ネイティブアプリならではの滑らかな UI や高速な描画やレスポンスといった体験を重視するような場合、マルチプラットフォームアプリだと少し劣る部分はあるかもしれません。
Kotlin Multiplatform
アプリの開発について調べていくと Kotlin Multiplatform(KMM) で開発する資料も見つかりました。実際に業務で開発されている事例で、とても参考になりました。次の資料は サイバーエージェント社の事例になります。
Kotlin Multiplatform MobileのおさらいとABEMAでのマルチプラットフォーム対応 | CyberAgent Developers Blog
チームラボ社も KMM を採用しています。
https://speakerdeck.com/teamlab/kotlin-multiplatform-mobile-for-ios-iosdc2022
Wantedly 社も同様に KMM を採用しています。
こちらは2020年の記事ですので、現在は状況が変わっているかもしれません。
Wantedly VisitにおけるKotlin Multiplatformの導入と実装 | Wantedly Engineer Blog
僕は普段サーバサイド Kotlin で開発をおこなっているのですが、KMM がアプリの開発に使用されていることを知らなかったので、「お、マルチプラットフォームアプリ開発で Kotlin 使えるのええやん!」と嬉しく思いました。普段から Kotlin を書いているため、 Kotlin の null-safety な構文やスコープ関数の使いやすさなどといった恩恵を受けており、KMM でアプリ開発するのも良さそうに思えました。が、上記の事例を見ると、おそらく次のようなプロジェクトの場合が適しているように思えました。
すでに iOS, Android のネイティブアプリで開発したアプリをリリースしていること
iOS, Android のネイティブアプリの資産(流用できるソースコードなど)があること
ある程度の規模のチームで iOS, Android アプリを開発する分業体制が整っていること
iOS, Android のビジネスロジックを KMM で共通化したい(UI は iOS, Android で各々作成する必要があるため、ビジネスロジック部分のみ KMM で共通化する)
すでにネイティブアプリをリリースしており、iOS, Android を開発するチームがあり、ある程度複雑なビジネスロジックを iOS, Android で共通化するために KMM を採用するのは非常に理にかなっているように思えました。KMM によってビジネスロジックが1箇所に集約されるのでドメイン駆動との相性も良さそうに思えます。元々 Android でアプリを開発していたエンジニアでしたら Java か Kotlin を書いていると思いますし、Swift の文法は Kotlin とかなり近いので、学習コストもそこまで高くないように思えます。
支払い.comのバックエンドチームは Java の経験はあるが Kotlin 未経験でジョインしている方が複数いますし、僕も別プロジェクトで SpringBoog + サーバサイド Kotlin をやっていたのですが、元々 Java のエンジニアで Kotlin は未経験でした。iOS アプリで Swift をやっていたエンジニアも Kotlin 未経験でジョインしたのですが、Kotlin の文法にすぐに慣れて開発を行うことができています。Kotlin 未経験でも Java か Swift あたりの経験があれば特に問題なく Kotlin で開発できる印象です。サーバサイド Kotlin で開発する場合は Java + SpringBoot などの経験があればより良いと思います。
作るアプリについて
アプリ開発について色々と調べた結果、 Flutter でアプリを開発することに決めました。現在はセキセイインコの健康管理アプリを開発中です。うちではセキセイインコを2羽飼っておりまして、セキセイインコの健康をどうやって管理するかを日々模索しております。この画像のように、セキセイインコは小型のインコで体重は30〜40グラム程度です。
セキセイインコは人間と大きく違う生態のため、人間の常識があまり通用しません。健康管理が難しく、主に次の点を考慮する必要があります。
セキセイインコ(成鳥)の適切な温度は26〜30度程度
1日の食事はだいたい体重の10分の1程度
うちのインコたちは32-33グラム程度なので3.2〜3.5グラムぐらいを1日にあげています。体重が日によって違うので調整する必要があります。
食事は基本的にペレットが最適
皮付きの餌だとタンパク質やビタミンなど必要な栄養素が足りないので病気になりやすいです
発情を予防するため食事の回数はランダムにしており、1日3〜5回ぐらいご飯をあげています
理由としては、セキセイインコが安心した環境になってしまうと発情して卵を産むのですが、発情は体の負担が大きく、卵も卵管が詰まってしまうと命の危険があります。インコの健康を考慮すると発情を抑制したほうがいいため、うちのインコたちも発情を抑制するようにしています。野生のセキセイインコはオーストラリアの砂漠に生息しており、雨季が存在しません。雨が降った後に主食となる植物が成長して餌が豊富な状態になるタイミングで発情し、卵を産みます。人間が飼育する環境下のセキセイインコは1年中餌が豊富にあり、外敵もおらず、温度管理も適切になされています。そのため、年中発情する環境が整っていると言えます。体重を適切に管理することや、ご飯がいつ食べられるのかわからない状況を作ることでインコが発情しないように制御するという感じです。
上記の理由により、鳥専門の獣医さんの勧めもあり、うちでは以下のことを実施しています。現在は LINE グループを作って毎日の体重を計測して、あげたご飯の量と回数を記録していますが、データがストックされないことや体重変化の推移をグラフにして管理するといったことができないこと、ランダムで通知を送ってご飯をあげる機能などが欲しいと思ったのでアプリを作ろうと思った次第です。
朝の空腹時点の体重を計測して記録をつける
1日にあげるご飯の量を調整し、ご飯の回数をランダムにする(いつご飯がもらえるかわからない状況を作る)
アプリでインコの健康を管理したい
LINE グループで簡易的に体重管理することに不便さを覚え始めたため、アプリを作成しインコの健康状態やご飯のあげた量を管理しようとしています。まだ作成し始めたばかりなのですが、体重の推移をグラフ形式で表示したり、複数ユーザーでインコのデータを共有して健康管理できるようにする予定です。年内中のリリースを目標にしております。
Flutter で使用する Dart は、オブジェクト指向かつ null-safety で lambda, generics, 非同期処理が使用できるといった感じです。まだそんなに Dart を書いていないのでちゃんとした評価はできないのですが、最近の言語で必要な機能はだいたい一通り揃っている印象があります。final と const の両方があり final はビルド時に評価され const はコンパイル時に評価されるようなので、基本的に const を使ってコンパイル時にエラーを検出できたほうがよさそうに思いました。また、final で生成したオブジェクトのフィールドは mutable ですが、 const で生成したオブジェクトはフィールドも immutable になるといった違いがあります。この辺りは Dart の language tour が参考になりました。個人的には Kotlin の scope 関数のような機能が追加されるとめちゃくちゃ嬉しいです。
Dart の language-tour で一通りの文法が学べる
最後に
技術的な話とセキセイインコの話が混ざった謎なブログになってしまいましたが、個人的な趣味でプロダクトを開発するのは新しい刺激があり楽しいですね。年内のリリースを目標に頑張って開発しようと思います。
このブログはワーケーション中の沖縄で書きました。UPSIDER のエンジニア組織はフルリモート、フルフレックスのためどこで働いても問題ありません。土日はのんびり沖縄を観光できたので、とてもリフレッシュすることができました。
UPSIDER はフルリモート、フルフレックスに興味があるエンジニアを募集しています!
https://career.up-sider.com/#engineering