AndroidもiOSもWebもサーバも触れるエンジニアがFlutterとAWSでサーバレスアプリ(ワイン専用SNS)を実装した話

## はじめに
ある程度タイトル通りのエンジニアですが、昨年の秋くらいから思い立って空き時間でガチめにFlutterとAWSでAndroid/iOS/Web向けにサーバレスアプリ作ったよというお話。
Android(Java/Kotlin)、iOS(Objective-C/Swift)、Web(Java/Python/PHP/etc...)がそれなりに出来て、サーバもLinuxサーバやEC2/ECS構築などまあまあイケる人がプロダクトを開発する手段としてFlutter＋サーバレスはどうなのかを試すためにやってみました。
目的はサーバレスの運用感覚を味わうことと、Flutterの学習、提案時の選択肢とするためとなります。
またただ作るだけというのは性格的に困難を極めるためワイン専用SNSの作成をテーマにするということでいきました。
(2020年1月の第一弾リリース時点ではSNS要素は入れず、ただのワイン記録アプリの予定です。)

## 構成
サーバレス視点での構成図となります。
WEBはコンテナを使わずS3で完全サーバレスにしました。
<img width="817" alt="Screen Shot 2020-01-03 at 11.12.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559103/1b357c1e-0beb-2df7-47ba-35b92862147d.png">

## アプリ
WEB/Android/iOSの3プラットフォーム展開です。
・・・ですが、WEB版は閲覧のみという形になりました。理由としてはFlutterの一部ライブラリが足並みが揃っていないものがあり、無理やりデバイス毎に機能実装するよりもライブラリの充実を待つことにしました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559103/8e006c18-d6b9-e5b0-493b-0418f31f35a1.png" alt="タイムライン" width="240"/>&nbsp;<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559103/e3ff37f7-f033-e70e-40cc-adeb620e1702.png" alt="場所選択" width="240"/>&nbsp;<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559103/bdf0135b-0ddf-d3ee-7cc7-dba0c8cbd4bc.png" alt="お店検索" width="240"/>&nbsp;<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559103/b1599d7c-ef1c-26ad-0cc9-f6310d06e351.png" alt="投稿" width="240"/>&nbsp;[![Flutterアプリ - grane](https://img.youtube.com/vi/21ZlwMt98uo/0.jpg)](https://www.youtube.com/watch?v=21ZlwMt98uo)


### WEB (2020年1月現在はChromeで見ることをオススメします)
WEB版は見ると分かりますが、描画処理が不完全で、一部レイアウトが崩れている箇所がありますが、参考のため公開します。(初回ロードは少し長いです)
[grane - グラン] (https://app.grane.jp/)
※アカウント登録からとなります。

### iOS
iOS版はフル機能対応となります。
&nbsp;&nbsp;&nbsp;&nbsp;[<img width="160" alt="download ios app" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559103/89fb0e93-0d5e-ecd7-37f8-1d06b4c671c8.png">](https://apps.apple.com/jp/app/id1493695963?mt=8)

### Android
Android版はフル機能対応となります。
[<img width="200" alt="download android app" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559103/e46ce914-429f-586f-1a46-305b4f3373f3.png">](https://play.google.com/store/apps/details?id=net.jp.found.grane.android)


## 構築までのQA
<dl>
<dt>Cognitoはどうやって使いましたか？</dt>
<dd>[amazon_cognito_identity_dart](https://pub.dev/packages/amazon_cognito_identity_dart)を使用してます。</dd>
<dt>GraphQL、Cognito認証はどうしましたか？</dt>
<dd>Amplifyがないので[http](https://pub.dev/packages/http)を使用して通常のhttpクエリとして実施しています。</dd>
<dt>S3はどうしましたか？</dt>
<dd>認証はCognitoのIDプールを使用したので前述と同じ[amazon_cognito_identity_dart](https://pub.dev/packages/amazon_cognito_identity_dart)。S3自体は[こちら](https://github.com/jonsaw/amazon-cognito-identity-dart/#for-s3-uploads)を参考にして使用して通常のhttpクエリとして実施しています。</dd>
<dt>RDS Proxyは何目的で使用してますか？</dt>
<dd>Lambda - RDS連携をする際にコネクション数の問題がありましたが、昨年12月にRDS Proxyのプレビュー版[Using Amazon RDS Proxy with AWS Lambda] 
 (https://aws.amazon.com/jp/blogs/compute/using-amazon-rds-proxy-with-aws-lambda/)がリリースされたので前向きな人柱として試しました。
Flutterアプリ公開準備中に1/16から課金対象になるよって連絡がきました。[Amazon RDS Proxy pricing](https://aws.amazon.com/jp/rds/proxy/pricing/)・・・いくらくらいになるんでしょうかね？
</dd>
<dt>辛いなと思うことはありましたか？</dt>
<dd>ありません。基本的にやれるか諦めるか(とても手間かかるか)の二択だと思います。出来る事であれば大抵Widgetがかなり整っているので約7年前初めてAndroidを触った時と比べると色々な障壁が低くなったと思います。</dd>
<dt>WEB版は何が足並み揃っていなかったのですか？</dt>
<dd>「投稿」という1機能は、画像の取得、一時表示、テキスト等と一緒にPOST(今回の場合は画像に関してはcognito認証でのS3へのPOST)だったのですが、取得、一時表示、POST処理で全てがiOS/Androidと異なりました。簡単に言ってしまえばWEB版をFlutterで開発したいという案件があった場合は、端末のローカルから画像を取得してPOSTする場合は少し頑張る必要があるというのと、もし複数PF同時対応でという場合は効率面から非推奨だと個人的に思いました。
これは端末による処理の分岐をしすぎるとFlutterの良い面がかなり減ってしまうためとなります。

例えばFileを扱う[dart:io](https://api.dart.dev/stable/2.7.0/dart-io/dart-io-library.html)ライブラリは「support for non-web applications.」と記載がありますし、WEBでも使用できる[universal_html](https://pub.dev/packages/universal_html)は一部機能に関して分岐をしていても[Androidビルドができなくなる](https://github.com/flutter/flutter/issues/47589)という問題がありました。</dd>

## Flutter的感想
特性を理解した上でであればサービス提供、運用視点でFlutterを採用するのは以下の理由からかなりアリだと思いました。

* 複数プラットフォームに対して自然に仕様(画面設計、内部ロジック)が共通化される  
->似たようなロジックを何度も書きたく無い性格としてはこれはかなりプラスになりました  
正直今後一人で複数プラットフォームをカバーするアプリを業務以外で作ると思っていなかったので・・・
* Hot reloadが早い  
->WEBでもAndroidでも1秒しないくらい
* 一度書けば複数端末に反映できる

その他ネガティブ要素としては以下の感じになります。

* シンプルが故にコードがネストしがち
* Javaに似た文法でネストして記載するのでプログラムの美しさを求める人には向かない
* UIのパーツカスタマイズ観点での自由度はかなり低い。Widget自体をカスタマイズするというより、いかにWidgetを組み合わせるか。
* WEB版は未熟な点(ネットワーク上の画像表示時にorientationが認識されない、ファイル読み込みなど足並みが揃っていない等)がある
* WEB版向けのライブラリを入れるとネイティブビルドできなくなるものがいくつかある。

全体としてベンチャーや試作品を低コストで素早くリリースしたい時に向いているという印象を受けました。
商用としていけるか、いけないかの間の時期から一歩踏み出したという感じがします。
AWSとの連携はFlutter向けAmplify SDKが無いので地道に書く必要があったりなど機能によっては事前に調査した方が良さそうです。

## 今後
* RDS Proxyの性能参考がわかるといいな
* Firebaseでのスクリーン履歴はどうなるのかな(Flutterには画面という枠組みでのWidgetは決まってないので)
* アークテクチャ周り[Flutter Architecture Samples](http://fluttersamples.com/)とか見てみても面白いのかも


## 追記(2020/03/06)
* ええじゃないかという深夜のTV番組で紹介いただいたので動画差し替えました。