第4回Flutterもくもく会@Zoom 実施レポート

# はじめに
2020年5月17日にZoomにて[Flutterもくもく会](https://flutter-okurayama.connpass.com/event/177206/)を実施したので、
そのレポートになります。個人的所感メインです。
何かご意見などありましたらよろしくお願いします。
話題になった内容をトピックとして記載します。
もし良ければ過去のものもご覧ください。
* [第1回](https://qiita.com/glassmonkey/items/7dd8cf2037e17c5131f8)
* [第2回](https://qiita.com/glassmonkey/items/9ed36f0e8f27952c7c6d)
* [第3回](https://qiita.com/glassmonkey/items/95d470bc780e35d079fa)
* 
# トピック
## 多言語対応について
各言語の情報の管理方法で議論になりました。
アプリのローカルで管理するよりも、[locize](https://locize.com/)のようなサービスを使ってリモートコンフィグの操作感で管理するのがアプリの不要なアップデートもせずに済むので、将来的には幸せになりそうという結論にはなりました。参考: [locizeのAPIドキュメント](https://docs.locize.com/integration/instrumenting-your-code#i-18-next)
現状の多言語対応そのものについては
参加していただいた[@muscle_pandasan](https://twitter.com/muscle_pandasan)さんが
[Flutterでの多言語対応をする](https://muscle-girl.hatenablog.com/entry/2020/05/31/191917)に書いていただいたので、そちらをご確認ください。
とても勉強になりました:relaxed:
## ローカルDBについて
ローカルのデータベースに何使うかの話題になりました。
この3つのライブラリが選択肢と考えています。
個人的にはそのうちSQLite推しで採用しています。
参考: [Dart/FlutterのローカルDBの比較](https://kabochapo.hateblo.jp/entry/2020/02/01/144411)
* [Hive] (https://pub.dev/packages/hive)
* [Shared preferences](https://pub.dev/packages/shared_preferences)
* **[SQLite](https://pub.dev/packages/sqflite)(推し)**
### Hiveについて
 処理速度的には`Hive`が一番期待大なんですが、v2を控えてる現状手を出しづらい印象を個人的に持っています。
また、ローカルDBのパフォーマンスの差より、ネットワークIOなどの他の要因の方がパフォーマンスのボトルネックになるケースが多いと考えていることも理由です。
### Shared preferencesついて
 `Shared preferences`は全データがカジュアルにデータの扱いが`Key, Value`になってしまうので、設定項目ぐらいはいいかなと思います。
しかし、本格的なデータは、小回りが効かないので辞めておくのが無難だと思います。`Key`でしかデータが取ってこれないので配列的なデータは全部メモリロードする羽目になります。
### SQLiteについて
以下の理由で個人に推しています。
- [公式](https://flutter.dev/docs/cookbook/persistence/sqlite)に紹介されており世の中に知見が豊富である点、
* SQLiteそのものがわりと枯れているのでクライアントツールがごまんとあるのでDBファイルを生成してDB単体で色々こねくり回せる点が個人的には好みで採用しています。
-またSQLiteのプラグインは[テスト用のモック](https://pub.dev/packages/sqflite)も用意されているので、
+またSQLiteのプラグインは[テスト用のモック](https://pub.dev/packages/sqflite_common_ffi)も用意されているので、
下記で設定しておけばテストでも使えるようになるので、絶賛開発で重宝しています。

```yml
dev_dependencies:
 …
 sqflite_common_ffi:
```
## テストについて
 個人にはFlutter自体はUIに関心が強いフレークワークの認識なので、そこまでテストは必要でない認識です。
特に、プラグイン呼び出しがある箇所は現状`flutter test`で[呼び出せなかかったりする](https://stackoverflow.com/questions/52028969/testing-flutter-code-that-uses-a-plugin-and-platform-channel)ので、これからに期待ですね。Firebase系がわりとテストしずらい印象を持っています。
 一方で、ビジネスロジックはFlutterのエコシステムから切り離して、Dartで表現できるならユニットテストはありだと考えています。（個人的に意見なので、コメントなどでつっこみ待ちです）
### テストのサンプル(Blocを使った例）
最近人気のない気のするBlocアーキテクチャですが、
個人的には[BlocのTest](https://pub.dev/packages/bloc_test)が書きやすいのでそれで書いています。
参考までに現状開発中のアプリにタグ管理機能をつけているのですが、そのタグ管理のテストを貼っておきます。
`act`でボタンをクリック時などで発行されるイベントを列挙しておいて,

```dart
 act: (TagBloc bloc) async {
 bloc.add(const TagCreateEvent());
 bloc.add(const TagCreateEvent());
 bloc.add(const TagSelectEvent(id: 1));
 },
```

`expect`で状態がどう変化していくかを確認する流れになります。

```dart
 expect: <Tag>[
 Tag(id: 1, value: "デフォルト名", enable: false),
 Tag(id: 2, value: "デフォルト名(1)", enable: false),
 Tag(id: 1, value: "デフォルト名", enable: false),
 ],
```
副作用のある内容に関してもモックを注入しておき、`verify`で検証することもできます。

```dart
verify: (_) async {
 verify(tagListBloc.add(const TagFetchEvent())).called(2);
 },
```
イベントとオブジェクトの関係はイミュータブルなオブジェクトをイベントに応じて発行して、それを検証している感じです。
発行しているイベントや、確認しているオズジェクトの詳細に関しては[Blocライブラリ](https://pub.dev/packages/bloc)の仕様と関係しているので、詳しくは説明しません。
Blocのテストに関しては、後日記事を書く予定なので、ご了承ください。
せっかくなので、関連するソースコードのスニペットを記載しておきます。

```dart
String getTestDBPath(String path) {
 String dir = Directory.current.path;
 if (dir.endsWith('/test')) {
 dir = dir.replaceAll('/test', '');
 }
 return join(dir, '.dart_tool', 'test', path, 'test.db');
}
Future<Database> setUpTestDatabase(String path) async {
 return _openDatabase(getTestDBPath(path));
}
group('タグBlocのテスト', () {
 Database db;
 TagRepository tagRepository;
 MockTagListBloc tagListBloc;
 setUp(() async {
 db = await setUpTestDatabase('bloc/tag');
 tagRepository = TagRepository(database: db, listBloc: tagListBloc);
 tagListBloc = MockTagListBloc();
 });
 tearDown(() async {
 await tearDownTestDatabase('bloc/tag');
 });
 blocTest("タグが作成後選択可能",
 build: () async {
 return TagBloc(repository: tagRepository);
 },
 act: (TagBloc bloc) async {
 bloc.add(const TagCreateEvent());
 bloc.add(const TagCreateEvent());
 bloc.add(const TagSelectEvent(id: 1));
 },
 expect: <Tag>[
 Tag(id: 1, value: "デフォルト名", enable: false),
 Tag(id: 2, value: "デフォルト名(1)", enable: false),
 Tag(id: 1, value: "デフォルト名", enable: false),
 ],
 verify: (_) async {
 verify(tagListBloc.add(const TagFetchEvent())).called(2);
 },
 wait: const Duration(seconds: 1));
}
```
## Firebaseのあれこれ
Firebaseのトラブルに遭遇してる方がいたので、[公式](https://firebase.google.com/docs/flutter/setup?hl=ja)のマニュアルに沿って、[Analytics](https://pub.dev/packages/firebase_analytics)から始めるとシンプルでいいよとアドバイスをさせていただきました。
たまにバージョンの依存関係でトラブル感じがあるので、早くバージョン１になることに期待ですね。
[公式リポジトリ](https://github.com/FirebaseExtended/flutterfire)のissueに上がってることもあるので、そこも要チェックですかね。
## その他
今回もちょっとした話を画面共有しながら花を咲かせることができました。
困ってることは意外と言語化が難しいので、リモート時代に画面共有しながらすすめる場が用意できてよかったです。
# おわりに次回開催と宣伝
こちらで定期的にもくもく会を隔週の頻度で実施予定です。次回は6月14日を予定しています。
LTなど発表したい方いましたら [@glassmonekey](https://twitter.com/glassmonekey)にご連絡いただけますと嬉しいです。LTの練習とかも大歓迎です。
下記のコンパスも良ければ登録お願いします。これを機に一緒に始めましょう
https://flutter-okurayama.connpass.com/
# 感想というかメモ
画面共有しながらわいわいできるのは、初心者にとっても、自分たちにとってもいい体験なのかもしれないと思いました。
言語化せずに気軽にできる場にしていきたいですね。