目的
Interface Adapterのコード(Presenter、Repository、Gatewayなど)は、どのような役割を負うべきかを調べる。
動機
ローカルとサーバーのデータベース同期ライブラリを開発していて、「どのデータベースであろうとも、アプリケーションロジックを変更する必要はない」というデータベースの独立性を持ちたかったので、CleanArchitectureの導入を考えた。
そこでまだMVC,MVP,MVVMで消耗してるの? iOS Clean Architectureについて
を参考にしながら進めていたのだが、Domain層の中にTranslatorが含まれているのに疑問を覚えた。
上の記事のサンプルコードを元に、データベースをRealmからCoreDataに取り替えた場合のことを考えてみたところ、ユースケースを書き換えなければいけないことに気がついた。
以下のコードでは、ユースケースがTranslatorに依存しているので、データベースを変更した場合Translatorの別クラスを作って書き換えなければいけない。
func loadTimelines() -> Observable<TimelinesModel> {
let login = loginAccountRepository.getSelectedTwitterAccount()
let accounts = socialAccountRepository.getTwitterAccounts()
return Observable.combineLatest(login, accounts) { ($0, $1) }
.flatMap { (identifier, accounts) -> Observable<TimelinesModel> in
guard let identifier = identifier, let selectAccount = accounts.filter({$0.identifier.isEqual(to: identifier)}).first else {
return Observable.error(AppError.notAuthorized)
}
return self.timelineRepository.getTwitterTimelines(selectAccount)
.map(translator: TimelineTranslater()) #この部分
}
}
これは、データベースの変更によってドメインレイヤを書き換えさせられているのでおかしいのでは?と思ったため、調査をした。
調査
ボブおじさんの元記事の翻訳をよく読み直したところ、こう書いてあった。
(長いのでまとめまで飛ばしても可)
インターフェイスアダプター
このレイヤーのソフトウェアは、アダプターの集合だ。これは、ユースケースとエンティティにもっとも便利な形式から、データベースやウェブのような外部の機能にもっとも便利な形式に、**データを変換する。**たとえば、このレイヤーは、GUIのMVCアーキテクチャを完全に内包するだろう。プレゼンター、ビュー、そしてコントローラーは、すべてここに属す。モデルは、コントローラーからユースケースに渡され、そして、ユースケースからプレゼンターやビューに戻される、単なるデータ構造である可能性が高い。
同じように、データはこのレイヤーで、エンティティーやユースケースにもっとも便利な形から、どんな永続化フレームワークが使われているにしろ、それにとってもっとも便利な形に変換される。例えば、データベースなど。**この円よりも内側のコードは、データベースについてなにも知るべきではない。**もしこのデータベースがSQLデータベースであるならば、どんなSQLであれ、このレイヤーに、もっと言うと、このレイヤーの中のデータベースに関連した部分に、制限されるべきだ。
また、このレイヤーには、その他すべてのアダプターもある。それらは、外部の形式(たとえば外部サービス)から、ユースケースとエンティティーで使われる内部形式にデータを変換するために必要なものだ。
重要だと思った部分は以下の部分
- ユースケースやエンティティに最も便利な形式から、データベースやウェブのような外部の機能に最も便利な形式に、データを変換する。
- 外部の形式(たとえば外部サービス)から、ユースケースとエンティティーで使われる内部形式にデータを変換する。
- **この円よりも内側のコードは、**データベースについてなにも知るべきではない。
→つまりInterface Adapterはデータベースについて知っていてよい
結論
ボブおじさんの元記事から考えると、Interface Adapterは
単なるI/Fではなくデータ変換の責任を持っており、そのためにはデータベースに依存しても良い。
となる。
なので、TranslatorはRepositoryが依存するようにすれば良いと思う。
同様に、ドメインモデルからUIで使うViewModelに変換を行う必要があったとすると、Presenterで変換を行えば良いと思う。