旨辛チキンおいしい

よくある備忘録みたいな奴です。

データ層は全てのデータに責任を負う層ではないし、ドメイン層は全てのロジックに責任を負う層ではない

Clean Architecture ではしばしば Presentation 層、 Domain 層、 Data 層の三層にレイヤーが分割されます。

これはそれぞれ表現、ロジック、データに関して責任を負う層なのですが、そのままの意味で捉えると危険です。

とある件で Android Clean Architecture のリポジトリを眺めていると、こんなイシューを見つけました。

AutoLoadImageView breaking the rules? · Issue #64 · android10/Android-CleanArchitecture · GitHub

このイシューでは、 AutoLoadImageView のような、指定した URL から画像をフェッチしてきてキャッシュして画面に表示するようなロジックを持ったコンポーネントを Presentation 層内で完結させるのは、 Clean Architecture のルールを侵害しているのではないか?という疑問が示されています。

この質問者と全く同じ考えかどうかはわかりませんが、自分も以前同じような疑問を抱いていたのを思い出しました。

例えば、ユーザーの情報を画面に表示するアプリがあるとします。 ユーザー情報にはユーザー名と簡単なプロフィール情報の他に、ユーザーの画像が含まれているとします。 ユーザー情報を表示する画面では、 GetUserProfileUseCase のようなユースケースクラスを経由して、 UserProfileRepository から UserProfile エンティティを取得します。 UserProfile エンティティを取得したあとはそこに含まれる情報を画面に描画しますが、ユーザー画像は Picasso を用いてインターネットから取得して、角丸に加工してから画面に表示します。

このとき、 Picasso が Presentation 層の中で URL をもとにインターネットから画像を取得してキャッシュし、それを角丸に加工してから画面に表示するという動作は、Clean Architecture のコアとなるルール、表現に関することは Presentation 層、ビジネスルールやそのロジックに関することは Domain 層、データの入出力に関することは Data 層に分けて記述するというルールを侵害しているのではないか?このルールを侵害しないようにするためには、画像を管理するためのリポジトリと、それを取得したり加工したりするためのユースケースドメイン層に定義し、画像の入出力の実装についてはデータ層で行わなければならないのではないか?という疑問です。

結論から言えば、 AutoLoadImageView や Picasso を用いたこれらの方法は、 Clean Architecture のルールを侵害しません。

先程のイシューでは次のように議論されています1

I think that you should not look at it as "oh, it accesses the disk so it must be in the data layer". The "data" is not about files, bitmaps or objects, but about the entities that your app uses.

雑に意訳すると、 「お、これはディスクにアクセスしているな。これはデータ層に違いない。」と考えるべきではない。「データ」とは、ファイルやビットマップやオブジェクトのことではなく、あなたのアプリが使用するエンティティのことである。 という感じでしょうか。

こんなふうにも書かれています2

You have an issue with the AutoLoadImageView component because you see that it caches bitmaps to disk, and think "this belongs in the data layer" because of that. But the data layer is not about "all stuff that comes from network or disk". But you have to think about data in more of an abstract way. "Data" in this example is "users". From an application perspective, bitmaps are not "data", they are just bytearrays that are only shown by the UI. There is no demand that states that these bytearrays are important to the application and can be used in other parts of the application.

この引用内では AutoLoadImageView で議論されていますが、 Picasso の場合も同じです(イシュー内では Picasso についても触れられています)。

ここで気付かされたのは、ディスクやインターネットにアクセスしているからといって、必ずしもそれがデータ層の関心であるということではないということです。 今回例示したアプリでは画像のキャッシュをローカルのディスクから取得したり、画像をインターネットからダウンロードしたりしていますが、だからといって、すぐにそれがデータ層の関心事だということにはならないということです。

同じ理由で、画像を角丸に加工するというロジックはドメイン層の関心事ではありません。ドメイン層はあくまでアプリケーションが実現したい機能を実現するためのロジックやビジネスルールを記述するところであって、アプリケーションに含まれる全てのロジックに対して責任を持つ層ではないのです。

このアプリがもし画像を加工するアプリなのであれば、画像はそのアプリケーションを実現するために必要不可欠なモデルなので、ドメイン層で定義されその入出力のためのリポジトリとロジックのためのユースケースが存在するべきです。 しかし今回の例のように、ユーザー情報を表示する上でプロフィール画像を画面に表示するという程度の場合、そのプロフィール画像はアプリケーションに必要不可欠なモデルではないでしょう。

したがって、そのような場合は AutoLoadImageView や Picasso が Presentation 層に存在し、それらがファイルの入出力やネットワーク接続、画像の加工などを行っても Clean Architecture のルールを侵害することにはなりません。

まとめ

何でもかんでも、表現に関することだから Presentation 層、ロジックやルールに関することだからドメイン層、ディスクアクセスやネットワークアクセスを行うから Data 層、のように単純に考えず、今作ろうとしているアプリケーションが達成したいことは何か、中心的で必要不可欠なモデル(エンティティ)は何か、ということを常に考え、そのエンティティを中心にユースケースリポジトリを設計していく必要があるなぁと思いました。