📖

[Flutter/Ios/Android]モダン設計比較 (DI依存性/非同期処理/データストリーム/通信/ハードウェアフレームワーク)

2024/08/01に公開1

はじめに

Flutter/Ios/Androidにおいてモダンな構成と相違点を簡潔にまとめていきたいと思います。

設計 アーキテクト

どの言語を使用し、プロジェクトを始めるかに関わらず、アーキテクトのベースになるのは、クリーンアーキテクチャとドメイン駆動設計に基づいた設計になると思われます。
クリーンアーキテクチャ

  • エンティティ(Entities)
  • ユースケース(Use Cases)
  • インターフェースアダプター(Interface Adapters)
  • フレームワークとドライバー
    DDD
  • エンティティ(Entities)
  • 値オブジェクト(Value Objects)
  • アグリゲート(Aggregates)
  • リポジトリ(Repositories)
  • サービス(Services)

クリーンアーキテクチャは責務の分離、DDDは責務のカプセル化と捉えていただければ、理解しやすいかと思います。
ネイティブアプリ開発においては、これらを用いたレイヤードアーキテクチャ、単方向データフロー、State Hoistingがモダンな開発において基本になってきます。

責務のカプセル化を行いプロバイダツリーを構成する。

昨今では技術の進化が早く、外部SDKや、生成AIの導入など、拡張性に優れた設計をネイティブアプリ開発でも推奨されているように、個人的には感じており、責務のカプセル化を行いプロバイダツリーを構成、DIにより依存性を注入するというのが今、最もモダンな設計であると言えると思う。
裏付けるように、IosのMV、AndroidのNowInAndrod、FlutterのRiverpodなどが推進されてきている。
※Storeをプロバイダツリーのどこに持たせるかの違いはある。

中規模設計OS毎のアーキテクチャ/依存性グラフ

Ios Android Flutter
MV/Flux MVVMマルチモジュール +Flux Riverpod

大規模プロジェクトOS毎のアーキテクチャ

Ios Android Flutter
VIPPER MVVMマルチモジュール+クリーンアーキテクチャ 向いていない

大規模プロジェクトになると、APPのシステムマネージャのContextをサブクラスへデリゲートして、サブクラス内で、責務のカプセル化を行いプロバイダツリーを構成するのがモダンと言えそうである。

DI依存性

基本的にプロバイダツリーの最上位に位置し、どのようにBind/Inject/Providesするか設定することにより、シームレスな機能提供ができる。

Ios Android Flutter
プロトコル Dagger Hilt Riverpodの依存関係注入機能

Ios プロトコル

パッケージ管理においても、一括でライブラリなど入れ、どこからでもなんでも参照でき利便性が高いが、プロジェクトが荒れやすい傾向にあると思う。
しっかり切り分けて、依存性を入れたいところではあるが、目立ったライブラリ等もなく、プロトコルで、カスタムしていくのが現実的と言えると思う。自由度が高いというのがIosネイティブのメリット、面白さであると思うが、ある意味で一番難易度が高いように思う。

Android Dagger Hilt

Dagger Hiltによってインターフェースが提供されているので、依存関係の注入タイミングを理解していれば、かなりシームレスな実装が可能となっている。

Flutter Riverpod

Riverpodで便利すぎる。しかし、なんでもRiverpodでできてしまうので、AndroidのDagger Hiltを理解した上で、使用するとさらに精密性が上がる気がしています。

非同期通信

Ios Android Flutter
IOS17以降 Observation/Combine StateFlow/FlagmentパターンだとLiveData RiverpodのStateProvider

Ios Observation/Combine

Combine @Publishedで発行 @ObservedObject を使ってUI側で感知
ただオブジェクト単位での感知になるので、プロパティ単位でUIの変更が多いと再描画が過多になる傾向
IOS17以降 Observationdでプロパティ単位の感知

Android  StateFlow

StateFlow を用いUI側でCollectで感知
FlagmentパターンだとLiveDataのライフサイクルオブザーバ

Flutter Riverpod StateProvider

Riverpod StateProviderにて発行

UI

宣言的UI

Ios Android Flutter
SwiftUI JetpackCompose Widget

Ios SwiftUI

Human Interface Guidelines準拠
https://developer.apple.com/design/human-interface-guidelines

Android  JetpackCompose

Material3準拠
https://m3.material.io/

Flutter  Widget

Material component widgets
https://docs.flutter.dev/ui/widgets/material

通信

networkモジュールでサービス、dataSource,
DataモジュールでInterface,Implにてデータ取得
networkモジュールにてカプセル化

非同期データフローでデータストリーム

Ios Android Flutter
Alamofire Retrofit2(okfttp3のラッパー) Retrofit(dioのラッパー)

ハードウェアの固有のフレームワークへのアクセス

メデイア/BLE/カメラ/ストレージなどハードウェアの固有のフレームワークへのアクセスは少し概念が異なってくる

IOS 拡張
Android 依存
Flutter メソッドチャンネルにて呼び出し

まとめ

ネイティブアプリという領域においては、すべて同じだと思うので、差分を理解しながら、すべての言語において、最適解を見つけていきたいです!

よかったらこちらも見てください!

https://zenn.dev/r0w0120/articles/2222b08c99a449

Discussion

JboyHashimotoJboyHashimoto

Flutter Riverpod StateProvider
Riverpod StateProviderにて発行

これって昔からあるアプリが例にだされてるんですかね?
YOUTRUSTさんは使っていたそうですが、FutureProviderやAsyncNotifierをもし最近ので作ろうなら、使いませんか?