この文章の目的
最近CleanArchitectureを採用したプロジェクトに参加したのですが、そのプロジェクト内で各層の意味と責務に付いての認識が今ひとつあやふやであり、コンポーネントをどのレイヤーに収めるのかの判断が実装者やレビュアごとに異なっているという現実にぶつかりました
開発自体はなんとなく進んでいるものの、コードに今ひとつ統一感がなくて気持ちが悪いので、いつかやるかもしれない用語定義に向けて個人的な考えををまとめておく為に、この文章を書きました
Insrastructure
- 自分たちが開発しているアプリケーションが制御できない、特定のデータフォーマットやプロトコルの使用を強要してくる、外部の仕組み全般
わかりやすい例
開発対象のアプリケーションとは異なるプロセスで動いているプログラム
よくある例では
- DB
- mailerデーモン
- その他、様々なプロトコル(HTTPだったりGRPCだったり)で提供される外部API
などがあります
これらについては、はっきりと別の事情に従って動いているプログラムなので、Infrastructureとして扱うことに特に異論はないと思います
わかりにくい例
- 同一マシンのファイルシステム
- インメモリのデータベース(sqliteなど)
これらは、自分たちが作っているアプリケーションと同一のプロセス、同一のメモリ空間で動くため、一見外部というより内部のものに見えますが
その動作そのものは制御することはできないので、Infrastrucureとして扱うこととします
Infrastructire層の責務
- 特定のInfrastrucureに対し、それが求めているプロトコルやデータフォーマットを使い通信し、結果を内部的に最低限理解可能な表現に変換して次の処理に引き渡すことが、Infrastructire層の責務である
あくまでInfrastructureとの通信がメインの責務で、その結果返された値が内部的にどのような意味を持つかについては考えません
また、レスポンスデータに対する処理も最低限のもので、JSON文字列を連想配列や、それと全く同じ構造を持った構造体にいわば直訳するだけで、ビジネスロジック上でそのデータをどのように扱いたいかまでは考えません
エラーについても、それがHTTPのステータスコードであったり、あるいはレスポンスデータフォーマットに含まれるエラーコードといったプロトコルの範疇に含まれたエラーであるならば扱うが、それ以上の判断は行わない
Adapter層の責務
Adapter層の責務を以下のように定義します
- インフラストラクチャ層から受け取った「直訳的で技術寄りのデータ構造」を、ドメイン層が理解できる「文脈に沿ったデータ構造」へ翻訳することが、Adapter層の責務である
当然、ビジネスロジックからInfrastructureに向かって制御が向かう場合は、Adapter層は逆の変換を行う責務を負います(Presenterとか)
この層で考えるべきなのは、ある意味体系に属するデータを、別の意味体系に属するデータに変換することであって、Infrastructureが求めているプロトコルの知識や、あるいはビジネスロジックについては考える必要がありません。
最後に、依存性の方向について
ここまで述べた通り、Infrastructure層が扱っているものは自分たちには制御できないものである以上、
Infrastructure層をAdapter層の制御下におくことはできません(実装上そのような依存関係を実現することはできますが、いかにもわざとらしい作りになるでしょう)
なので、Robert.Martin式のCleanArchitectureを採用している場合はこの定義は使えないでしょう
クリーンアーキテクチャを採用している場合に、どのような定義するべきかは私には考えがないので、意見をいただけると助かります