はじめに
アプリの前提として
- SNS的なアプリで比較的インタラクションやサーバ側の更新が多い
- 仕様の追加や変更が多い
やりたい事
- ゴリゴリ機能を追加したい
- 読みにくい・学習コストの高いものは避けたい
- 必要に応じて人数を増やせるように
- テストしにくいView/ViewControllerのコード量を減らしたい
- 仕様追加や変更の多いViewModelのコード量も減らしたい
- 古い表示が残る系のバグを根絶したい
- オフラインでもディスクキャッシュされてる情報は表示したい
- DBは使いたいが読み書きのオーバーヘッドは避けたい
- 冗長なAPI通信を無くしたい
- (できれば)重要な情報から早く取得して表示したい
- (できれば)先読みしたい
パッケージ設計案
複雑でバグになりがちなところはなるべく汎化してまとめて、
それ以外の画面や機能をサクサク作れるようにする。
- ViewModels - ある画面の内容と状態とロジック
- 自分を表示できるViewの知識 (protocolで決まる)
- 画面の内容に必要なModel/Resourceの知識
- Viewとの入出力に使うプロパティの実装 (tap, text, hidden, enable, offsetなど)
- UIからの入力に対応するバリデーションやActionの知識
- URIスキーム(ディープリンク)の、画面の内容を表す部分の知識?
- 自身の状態のシリアライズ・デシリアライズ (ログやデバッグ用)
- Views - 特定のViewModel(群)を可視化・操作するUI
- 画面に閉じたUIKit系の実装 (ViewController/View/Cell)
- 注入されたViewModelと双方向バインディング (候補はSwiftBond)
- そのViewとの入出力に使うプロパティのprotocol定義
- 自身では基本的には状態を持たない (計算キャッシュくらい)
- URIスキーム(ディープリンク)の、画面を表す部分の知識?
- 画面遷移やダイアログは基本的には無し (ViewModelがActionを実行した時の副作用)
- Models - GETやPOSTの内容。Resourceの構成要素にも。
- ほぼGETやPOSTで使うJSONのマッピング (ObjectMapper)
- フルの情報を取れるAPIのpathの知識
- Resources - コレクション系のGETやPOSTの内容。
- ResponseとModelとの対応の知識
- APIのpathの知識
- filter、無限スクロール、pagenationと、queryとの対応の知識
- Repository - Model/Resourceの作成、取得・更新と通知
- Model/Resourceの状態管理: none, loading(progress), updated(timestamp), expired, error(info)
- none/expiredなModel/Resourceを取得・更新
- 100ms以上loadingが続いたら通知 (通信中の表示)
- 更新の通知 (Realm.Notification? NotificationCenter?)
- 無限スクロールやpagenationの状態管理、チャンク管理、取得・更新
- 取得の優先度管理
- Actions - 画面遷移・投稿・更新系の処理
- 必要なダイアログの知識 (投稿や削除の確認、アクションシートなど)
- POST系APIの実行
- エラー時の対策手段の提示 (ダイアログのメッセージなど)
- 成功時に影響を受けるResourceのexpire処理
- 遷移先画面の知識 (URIスキーム)
- 複数の画面遷移を伴ってもよい? (チュートリアルやフォームやカート的な)
- Router - ユーザのモード切り替えの知識
- URIスキームのNotificationを処理
- タブやナビゲーションバーの管理
- タブに積まれたViewやActionの情報
- ViewやActionを生成してスタックに積む
- 積まれたActionからのダイアログの表示やインタラクション
- 通信中、通信エラー等の通知
- Storage - Resource/Modelのキャッシュ、リファレンス管理
- 基本はIn-memoryキャッシュ (Realm)
- 非同期で永続化 (Realm)
- ModelのObserverが無くなってしばらく経ったらIn-memoryキャッシュから削除
- Modelが参照されたらIn-memoryキャッシュに復元
- 永続DBも大きくなったら古い情報を削除?
- Service - API通信やリトライ (Alamofire/SwiftTask)
- 複数のトリガーが同時に来ても同じAPI通信を投げない仕組み
- キャンセルやキューイング
- Device
- ネットワーク接続状態の検知と通知 (NotificationCenter)
検討中
- 画面表示だけ簡単にチェックする仕組み (Playground? URIスキーム?)
- GET系は先に画面遷移、POST系は成功/失敗してから画面遷移