はじめに
#2ではクリーンアーキテクチャのクラス構成を考えてみました。
今回は#1で理解不足なところ3つ目にあげていた「アプリケーション全体の関心事」の処理について考えてみます。
アプリケーション全体での関心事
iOS, Androidの場合、アプリの種類によっては無視できないイベントがいくつかあります。
アプリがバックグランドに入った/フォアグラウンドに復帰した、通信を行う場合インターネット接続が切れた/復帰したなどなど...
これらは「UIではないframework & driverからの入力」と考えば良い、と言う結論になりました。ちょうど本家の4つの円の絵には左上に「Devices」というのがあり、これがiOS、Android特有のそれらのデバイスイベントを監視、受け取る部分になります。それらがイベントを受け取ったらInterface Adapter経由でUsecase Interactorので処理させる、という流れです。
ここからはこの結論に至るまでの備忘録です。
処理の流れ
Usecase Interactorのイベントを検知するframework & driver層のクラスとイベントに応じて何か行う(UI操作とか)framework & driverをそれぞれ用意します。例えば
「スマートフォンがインターネット接続が切れたことを検知したら、アプリは、画面の特定エリアにワーニングメッセージを表示し続ける」
「スマートフォンがインターネット接続が切断状態から復帰したことを検知したら、アプリは、画面の特定エリアに表示していたワーニングメッセージを消す」
のようなユースケース仕様だったら
- インターネット接続状態を監視するframework & driverの実装
- インターネット接続の切断/復帰のユースケースを担当するUsecase Interactorの実装
- 画面の特定エリアのワーニングメッセージ表示/非表示を操作するframework & driverの実装
という3者で「イベント検知→画面更新」という処理を行います。
ざっくりなイメージはこんな感じ。
Usecase Interactorを介する必要性
上記の例の処理の流れを考えていると、この「インターネット切れた-> 画面に固定ワーニング出し続ける -> 復帰した -> ワーニング消す」という流れは、**iOS, Android特有のイベントの受け取り方をして、iOS, Android特有のViewの制御をするだけなので、はたして「Usecase Interactor」として扱うべきなのか?**という疑問が湧いてきます。
しかし、この疑問についてはやはり「Usecase Interactorを介すべき」という答えになりました。
上記の仕様例はインターネット接続が切断されたイベント発生時に行う処理が1つですが、Usecase Interactorを使わずに実装した場合、仕様変更によって複数の処理を扱うときに不都合が起きます。
例えば、Interactor未使用の実装をしていたとき、「スマートフォンがインターネット接続が切れたことを検知したら、アプリは、画面の特定エリアにワーニングメッセージを表示し続け、かつ、アプリ内部にxxx(何か大切な値)を保存する」という仕様変更があった場合、Usecase 「ワーニングメッセージ表示の画面更新にはUsecase Interactorを使わないけど、永続化処理のことはUsecase Interactorを使う」という実装をしてしまいそうになるのではないでしょうか。
ですが、これではUsecase Interactor以外の部分が「ユースケースの詳細(画面処理と永続化処理を操作する必要がある)」を知っていることになり、役割分担が崩れてしまいます。
将来に渡って各実装の責任範囲を明確に保つことを考えると、たとえその時点ではイベントを横に流すだけだとしても、Usecase Interactorを介するべきと思います。
まとめ
今回は残っていた自分の疑問「アプリケーション全体の関心事」について考えをまとめました。#1の記事では
おそらく外→内→外の部分は変わらず、内→外の箇所でどうやって「全体への周知」を行うか。ま、単純なcallbackではないような気はしている。
なんて書いてましたが、ちゃんと考えると結局外→内→外でしたね。。。
このエントリがどなたかの頭の整理に役立てば幸いです。