🦁

Flutterで個人開発していて感じたこと。

2023/04/28に公開

はじめまして。 草野 洋平と申します。

本職は別のため、大体1つのアプリの作成は1日1時間程度、子供が寝静まってから開発しています。

基本業務を改善するためのWebアプリを中心にして作っています。
大体1つのアプリで1機能、1月(50時間)ほどで開発出来ています。

そこで得られた知見が3つありますので、そちらをシェアします。

Firebase使おう

Firebase、言わずと知れたBaasです。
これを使うことでバックエンドをすべて任せることができます。
制約も多いですがAPIを作ったりSQLを書かずに済みます。
これでやる仕事が半分になります。

UI側にロジックを寄せてしまいましょう。

クリーンアーキテクチャなどは大規模に開発するときの手法だそうです。
もちろん本職がプログラマーな方々は業務に沿った作成方法のほうが早い場合もえてしてあると思います。

しかしノンプログラマーの個人開発だとコードの短さ、簡単さによる恩恵は計り知れません。
エラーが出た時もどこがおかしいのか、調べるところを減らせます。

DataclassをUIに持ち込むのは気持ち悪いかもしれませんが、めちゃくちゃ楽になります。
例えばこんな感じ。

UI側のサンプル
// UI側にロジックを持たないとき
ref.watch(itemProvider.notifier).setItemId(id:currentItemId);

//UI側にロジックを持たせるとき
ref.watch(itemProvider.notifier).setItem(item:currentItem);

下段のが感覚的だと思います。

Provider側も

Provider側

CollectionReference<Item> ItemRef(ItemRefRef ref,
    {required User user}) {
  final db = FirebaseFirestore.instance;
  final path = "user/${user.uid}/items";
  final items = db.collection(path).withConverter(
      fromFirestore: Item.fromFireStore,
      toFirestore: ((Item item, options) =>
          item.toFireStore()));
  return item;
}

Query<Item> FindItemByID(FindItemByIDRef ref,
    {required User user, required String id}) {
  final itemRef = ref.watch(itemRefProvider(user: user));
  final query = itemRef.where("id", isEqualTo:id);
  return query;
}


位でOKで、さらにfirestore_ui_firestoreFirestoreQueryBuilderを使うとSnapshotのハンドリングすらよしなにしてくれます。

ui.dart
 
  Widget build(BuildContext context, WidgetRef ref) {
    String id = "SOMEIDFROMCONSTRUCTOR"
    final query = ref.watch(findItemByIDProvider(user: user,id:id));
    return FirestoreQueryBuilder(
      query: query,
      builder: (context, snapshot, child) {
        if (snapshot.hasData) {
         return //someWidget
        } else {
          return const CircularProgressIndicator();
        }
      },
    );
  }

UI側にロジックを露出させているため、気持ち悪いかもしれませんが、コードは短いです

Flutterで有名なAndreaさんもDIで完全に隠匿するよりも少しだけleakyな方がシンプル、といっています。特にFirebaseQueryBuilder推しっぽい。以下のツイッターの連投はすごく参考になりました。

https://twitter.com/biz84/status/1653050251262009355

unidirectional data flowを意識する

これはFirestoreを使うと自動的に達成されるのですが、Firestore全体をReduxのように単一のStateと考え、 Collection/DocumentReference作ってそれを描画するだけのProviderと、それとは別にCRUDするHandlerクラスを作ることで
描画→Collection/DocumentReferenceの描画、CRUDは別クラス、と切り分けるることができます。
こうすることでUI側にもDI側にも状態を持たせないことができます。
これで管理すべき状態をなくせました。

この3つを徹底することで、短い時間でもソコソコのPOCができると思います。

最後に

こちらは自分なりの知見です。
もしそうじゃない方が早い、という意見がありましたら教えていただきたいです。

Discussion