個人開発アプリの設計を見直してみた

image

初めに

最近はクリーンアーキテクチャとかドメイン駆動設計とか「変更に強い設計」がキーワードなような気がして、設計に強みを作っていきたい自分としてはどんどんそういう世界に飛び込んでいきたいです。 まずは可茂IT塾で関わったアプリを参考にしつつ、個人開発アプリの設計を改善していきます!

アプリの説明

今回扱ったアプリはアルバイト先の飲食店に向けて開発している、食材の発注作業を楽にするアプリです。
発注作業はしんどい作業です。 というのも、発注量を決める目安の数字があるにはあるものの、実際には色々な要件が絡み合っていて考えるべきことが多く、面倒な計算が求めらるからです。
とても面倒でつらいので、自動化を目指しています。。

扱う数字たち

このアプリでは主に3つの数字を扱います。

  • 売上予想額
  • 食材の在庫数
  • 食材の単位量あたりの売上見込み

具体例として牛肉の発注量を考えてみましょう。

  • 明日は3000円の売り上げ予想です。
  • 明日の朝イチの時点で、牛肉の在庫は5パック分あります。
  • 牛肉1パックあたり500円の売り上げが見込まれます。

この時、初めに明日の牛肉の出庫量を考えます。3000 / 500 = 6パックの消費が見込まれます。
牛肉は明日の朝イチ時点で5パック分しかないため、1パック不足します。
結果として、1パック分発注すれば足りそうです。

めちゃくちゃシンプルにするとこんな感じの計算をします。

実際には、1箱12パックで送られて来るので送料の無駄がないように牛豚鶏の合計が12の倍数になるように発注する、などの縛りがあります。。。
例)牛 3P, 豚 4P, 鶏 5P の合計12パック

見直す前の設計

売り上げの予想額を扱うSalesクラスと、食材の在庫数と単位あたり売上を扱うItemクラスを作り、providerで管理するような形にしていました。 Itemは品目ごとにproviderをハードコーディングし、Salesも今日、明日、明後日の三日分ハードコーディングでproviderを作っていました。

また、それぞれのproviderをwatchしたStoreクラスのproviderを使って統括的な処理をするようにしていました。

クラス図(before)

改善前の悪い所

providerがバラバラなため、処理やUIの記述もバラバラになってしまう。

苦肉の策で親からproviderを引数で渡す対応をしていました。。。
それでも結局こんな感じで個別に書く必要があってなんか違う。

Column(
  child: [
    ItemCard(porkProvider),
    ItemCard(beefProvider),
    ItemCard(chickenProvider),
  ],
)

全てのItemに対して処理をするのにもproviderごとに個別にやってあげる必要があり、複雑な実装に入るとぐちゃぐちゃのスパゲッティコードに。

StoreクラスでItemやSalesを持っていても、結局個別のproviderが必要になる。

今思えば、初めからStoreクラスのproviderだけを用意するようにして、ItemやSalesの変更に対しても全てStoreで処理するようにすれば動くようにはできたのかも。(それでも深い構造になって分かり辛そう。)
今回の設計では、StoreクラスのItemに対して変更を加えてもproviderに何の変更も通知されないので、結局個別のproviderを使ってあげないといけません。

//通知されない
for(final item in store.itemList){
  item.amount++;
}

処理してるつもりなのになんで通知されないんだと詰まるポイントになり得る。。

見直し後の設計

クラス図(after)

.family

今回の悩みに関しては、ほとんどこれのおかげで解決しました。 idとproviderを紐づけることができるので、idをリスト形式にして持っておけば、

for(final itemId in itemIds) {
  ref.read(itemProviderFamily(itemId).notifier).incrementAmount();
}
Column(
  children: itemIds.map((itemId) {
    final item = ref.watch(itemProviderFamily(itemId)).item;
    return ItemCard(item);
  }).toList();
)

こんな具合に全てのItemに対しての処理なんかも簡潔に書けます。 バラバラのproviderにガッツリ依存していた時期に比べ、providerとの結びつきを緩めることができました。

状態管理

状態管理は全てitem, salesで管理するようにしました。それぞれidを持っているので、UIにインスタンスさえ渡してしまえばidを使って目的のproviderに対して処理を通知できます。 各UIはItemやSales,もっと言えばidさえ持っていれば良くなったので、複雑さが抜けて直感的に分かりやすくなりました。

結果

idに紐付いたproviderを引っ張って来れば良くなったことで、データの流れが分かりやすくなりました。12の倍数問題もかなりいい感じにクリア。
Firestoreとの連携もしやすく、在庫状況などをFirestoreに保存する機能の追加などが実現しました。 自動化に向けて大きく前進です。

フォーム画面 発注画面

まとめ

直感的で分かりやすい状態管理が大事! 今後は凝集度、依存の方向とかにも気を配れるようになりたいです。

アプリに関して、今は単位あたり売上には手動計算したものを入れています。
今後は売り上げデータの保存機能や、出庫量の算出機能を実装して、そこの計算まで自動化したいです!

新しく勉強したことを個人開発に取り入れてみるのは良い勉強になっている気がしてます🙂

お知らせ

11月5日開催のアプリ開発講座の参加者募集中!!

11月5日開催のアプリ開発講座の参加者募集中!!

11月5日にアプリ開発講座を開催します!会場は岐阜県美濃加茂市のコワーキングスペース「こやぁね」です。興味のある方は是非ご参加ください!

Read More
可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。

Read More

関連の記事

お知らせ

11月5日開催のアプリ開発講座の参加者募集中!!

11月5日開催のアプリ開発講座の参加者募集中!!

11月5日にアプリ開発講座を開催します!会場は岐阜県美濃加茂市のコワーキングスペース「こやぁね」です。興味のある方は是非ご参加ください!

Read More
可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!

可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。

Read More