Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Flutter アプリの将来のインフラ移行に備える 疎結合なソフトウェア・アーキテクチャ / Flutter code Architecture for Infrastructure Migration

Flutter アプリの将来のインフラ移行に備える 疎結合なソフトウェア・アーキテクチャ / Flutter code Architecture for Infrastructure Migration

近年、モバイルアプリのクロスプラットフォーム対応を進める目的で Flutter が導入されることが増えてきています。くわえて、とりわけ少数のチームで開発を進める場合、開発効率を高めるために mBaaS が導入されることも少なくありません。そこで課題となるのが、中長期的な運用に足る拡張性やスケーラビリティと短期的な開発効率のバランスをどのように確保していくか、ということです。

本セッションでは、短期的な開発効率を高めつつも将来のインフラ移行に備えることが可能な疎結合なアーキテクチャを Flutter プロジェクトの初期から採用することを提案し、その具体的な設計やコードのサンプルを解説します。

- Flutter とオニオン・アーキテクチャ
- インフラ層を隔離することの意義とその方法
- 疎結合を実現する状態管理モデル(Riverpod, StateNotifier)

Takahiro Ikeuchi

November 18, 2022
Tweet

More Decks by Takahiro Ikeuchi

Other Decks in Technology

Transcript

  1. Flutter アプリの将来のインフラ移行に備える
    疎結合なソフトウェア・アーキテクチャ
    株式会社Hakali 取締役CTO
    Takahiro Ikeuchi - 池内 孝啓
    FlutterKaigi 2022

    View full-size slide

  2. Agenda
    自己紹介 - 2分
    インフラ移行にどう備えるか - 5分
    疎結合なソフトウェア・アーキテクチャを目指して - 20分
    アンチパターン2選 - 5分
    まとめ - 3分
    1.
    2.
    3.
    4.
    5.
    💡 資料およびサンプルコードは公開いたします
    2

    View full-size slide

  3. 池内 孝啓(いけうち たかひろ)
    デジタル認知行動療法アプリ Awarefy CTO。
    https://github.com/iktakahiro
    https://iktakahiro.dev/
    自己紹介
    @iktakahiro
    https://www.awarefy.app
    3

    View full-size slide

  4. Android/iOS 両対応のプロダクト開発のため、2019年9月に
    Flutter を採用、以来となるFlutter歴3年。
    Flutterと私
    https://pub.dev/packages/iso_calendar
    https://pub.dev/packages/fargon2
    OSS (pub.dev)
    4

    View full-size slide

  5. 本日のテーマ
    インフラ移行にどう備えるか
    5

    View full-size slide

  6. 少人数でプロダクトを開発してリリースまで
    もっていかなくちゃ...
    Firebase や Supabase がいいかも....
    ベンダーロックインが心配だな....
    6

    View full-size slide

  7. 実録!Firebase to AWS
    2020年5月にリリース時点でバックエンドは Firebase の
    完全サーバーレス
    2022年7月にAWSに移行
    Amazon EKS x Amazon Aurora Serverless v2
    サーバーサイドアプリを運用開始
    7

    View full-size slide

  8. Firebase 選定の理由 - 2019年
    関心事を Flutter に限定したかった
    リリースまでのスピード!
    SDK もあるしよさそう
    8

    View full-size slide

  9. Firebase 移行の理由 - 2021年
    ビジネスロジックの複雑化への対応
    データマイグレーション時の負担の解消
    運用面の諸々の強化
    (バックアップ、リストア、セキュリティ etc)
    RDB 化を決意。
    ※ ニーズとの相性の問題。Firestore はいいサービスです!
    9

    View full-size slide

  10. 新インフラ - 2022年
    クラウドインフラ選定に関する
    詳細は割愛

    View full-size slide

  11. おもな変更点
    バックエンドアプリのスクラッチ実装(Go + gRPC)
    インフラ基板の刷新(Amazon EKS)
    データストアの刷新(Amazon Aurora Serverless v2)
    ※ データマイグレーションの話は今回取り扱いません
    11

    View full-size slide

  12. Before
    モバイルアプリ Firestore
    12

    View full-size slide

  13. After
    モバイルアプリ Web App PostgreSQL
    13

    View full-size slide

  14. インフラ移行にどう備える(た)か?
    14

    View full-size slide

  15. 結論
    インフラレイヤーの抽象化をしておく
    16

    View full-size slide

  16. 結論
    17
    なるべく早期(できれば最初)から!

    View full-size slide

  17. 疎結合な
    ソフトウェア・アーキテクチャを目指して
    18

    View full-size slide

  18. ドメイン
    ユースケース
    プレゼンテーション(UI

    インフラ
    https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/
    依存性逆転の原則を用いてインフラを
    最も外側に置く
    オニオン・アーキテクチャ
    テスト

    View full-size slide

  19. ドメイン
    ユースケース
    プレゼンテーション(UI

    インフラ
    テスト
    Flutter (Widget)
    = プレゼンテーション層
    Firebase などの mBaaS
    = インフラ層
    20

    View full-size slide

  20. Flutter Widget
    ユースケース
    リポジトリ(インターフェース)
    コードの依存関係 実際のデータの流れ
    Flutter Widget
    ユースケース
    リポジトリ(実装)
    21

    View full-size slide

  21. ドメイン
    ユースケース
    プレゼンテーション(UI

    インフラ
    テスト
    Entity
    Value Object
    Repository
    Service
    ドメイン層
    ドメインモデルと
    リポジトリインターフェースの定義

    View full-size slide

  22. ドメインモデル(Entity)
    ※ モデルやコードはすべて簡略化しています

    View full-size slide

  23. リポジトリ(永続化処理)の抽象化
    Dartとインターフェース :
    https://dart.dev/samples#interfaces-and-abstract-classes
    https://dart.dev/guides/language/language-tour#implicit-interfaces

    View full-size slide

  24. ドメイン
    ユースケース
    プレゼンテーション(UI

    インフラ
    テスト
    DB
    HTTPS
    RESTFul
    gRPC
    インフラ層
    リポジトリの実装
    25

    View full-size slide

  25. 特定のシステムに紐付くものはすべてインフラ
    RDB(MySQL, PostgreSQL)
    NoSQL(Firestore, MongoDB)
    HTTPS / RESTFul API
    gRPC / Protocol Buffers
    SMTP
    SDK
    インフラ
    ≒ 具体

    View full-size slide

  26. Firestore 向けリポジトリ(永続化処理)の実装
    クラス名なども具体的なインフラの命名をつけておくと後々わかりやすい

    View full-size slide

  27. Firestore 向け DTO
    Firestore のデータ(Map)と
    ドメインモデルを相互変換する

    View full-size slide

  28. Dart と DTO (Data Transfer Object)
    インフラ層のデータ構造とドメインオブジェクトをマッピング
    JSON とオブジェクトの相互変換が必要な場合 freezed パッケ
    ージ周辺のツールが便利
    toJson, fromJson が生える
    immutable なデータクラスとしての振る舞い
    https://pub.dev/packages/freezed

    View full-size slide

  29. リポジトリ(インフラ層)抽象化の意義
    ドメインオブジェクトの隔離とテスタビリティの確保が主目的
    副次的にインフラ変更に強くなる
    SOLID 原則 : 抽象に依存せよ
    30

    View full-size slide

  30. ドメイン
    ユースケース
    プレゼンテーション(UI

    インフラ
    テスト
    ユースケース
    CQRS
    ユースケース層
    ユースケースのインターフェースの
    定義およびその実装

    View full-size slide

  31. ユースケース(インターフェース)
    ここでも欠かさず抽象化。プレゼンテーション層のテストがやりやすく
    なります。

    View full-size slide

  32. ユースケース(実装)
    リポジトリのインターフェースに依存(実装には依存しない)

    View full-size slide

  33. ユースケースの初期化と登録
    のちほど取り出して使います。

    View full-size slide

  34. ドメインオブジェクトからのインフラ層の隔離はOK
    NEXT : プレゼンテーション層
    35

    View full-size slide

  35. ドメイン
    ユースケース
    プレゼンテーション(UI

    インフラ
    テスト
    UI(View)
    View Model
    Controller
    Routing
    プレゼンテーション層

    View full-size slide

  36. View
    View Model
    Flutter Widget
    Riverpod
    プレゼンテーション層の View と View Model
    ※ 状態管理は Riverpod である必要はないです。他の選択肢でもOK

    View full-size slide

  37. Flutter Widget
    ユースケース
    リポジトリ(インターフェース)
    コードの依存関係 実際のデータの流れ
    Flutter Widget
    ユースケース
    リポジトリ(実装)
    View Model (Riverpod) View Model (Riverpod)

    View full-size slide

  38. Riverpod + StateNotifier
    Riverpod
    StateNotifier
    freezed
    の3点セット

    View full-size slide

  39. View Model からユースケースを利用
    ユースケースのインターフェースに依存(実装には依存しない)
    40

    View full-size slide

  40. Riverpod + Hooks
    View Model の
    メソッドと状態にアクセス

    View full-size slide

  41. ドメイン
    ユースケース
    プレゼンテーション(UI

    インフラ
    インフラ層をふくめ
    各レイヤーが疎結合な状態を達成
    テスト
    バックエンドに関する変更の場合、
    インフラ層のみの変更で対応可能
    ※ もちろん理想的にいけば、の場合

    View full-size slide

  42. インフラを差し替えてみよう

    View full-size slide

  43. SQLite 向けリポジトリ(永続化処理)の実装
    リポジトリを二重に実装する
    意味はありませんが、例です
    SQLite のデータ(Map)と
    ドメインモデルを相互変換する

    View full-size slide

  44. SQLite 向け DTO
    45

    View full-size slide

  45. これを...

    View full-size slide

  46. インフラの差し替え!!
    こうする!!

    View full-size slide

  47. モバイルアプリ Web App PostgreSQL
    モバイルアプリから見るとここから
    先がインフラ層

    View full-size slide

  48. アンチパターン2選
    50

    View full-size slide

  49. アンチパターン : UIとインフラの密結合
    サンプルコードではよくある(?)やつ

    View full-size slide

  50. インフラ層の変更に Widget が直接影響を受けてしまう
    実質的には1つのインフラ(DB)にのみ対応
    テストが書きにくい、書けない
    コード量が最小限になる
    デメリット :
    メリット :
    アンチパターン : UIとインフラの密結合
    💡 プロトタイピングでは有効な面も(それでもおすすめはしません)

    View full-size slide

  51. アンチパターン : 全知全能モデル
    MVCフレームワークや O/R Mapper を使うとなりがち

    View full-size slide

  52. アンチパターン : 全知全能モデル
    複数のレイヤーの関心事が含まれてしまう
    DBの都合でモデルに変更が入る、とか
    クラス定義が1つで済む
    デメリット :
    メリット :
    💡 DTOに辛みを感じたらスニペット利用やコード生成などで
    単純作業コストを減らそう。

    View full-size slide

  53. 今日話したことまとめ
    インフラ移行は意外と起こる
    コードーベースの初期設計から疎結合に保つことが大事
    Flutter/Dart でオニオン・アーキテクチャは手軽に実践可能!
    56

    View full-size slide

  54. ありがとうございました!
    https://github.com/iktakahiro/flutter-starter
    https://github.com/iktakahiro
    https://iktakahiro.dev/
    @iktakahiro
    サンプルコード
    58

    View full-size slide