これまでの十四章
腐敗防止層
動機
前回、腐敗防止層を採用する動機として、上流のモデルを下流で扱うのが困難な場合とありました。
相手がレガシーの場合は特に、モデルが貧弱であるのが普通ですし、今回のプロジェクトとの要求に合わないことも。
エンジニアの心情としては、なんでそのレガシーを作り変えないんだ!と文句が出るところですが、予算的・政治的なところもありなかなか実現はしないものです。
プリミティブなデータに曖昧なところがないという幻想
システム間のデータのやり取りは大体プリミティブなデータだと思います。
intやbooleanなどに曖昧なところはないので、そのデータがどういうデータなのか間違うことはないと考えてしまうことは多いと思います。
大体こういう想定は間違いであるとEvansは言っています。
データの意味を取り違って、エラーが起きたり、データベースのデータに矛盾が出てきたりということはよくあることです。
必要なのは、別のモデルと接している部品の間で変換できるようにすることにより、異質なモデルの要素を消化しきれずにモデルが崩壊しないようにすることである(第四部 第十四章より)
腐敗防止層
この解決策として、隔離するためのレイヤを作成して、2つのモデル間の変換を両方向に対して行う機能を提供することです。
注意すべき点としては、この腐敗防止層は、メッセージを送受信する仕組みではなく、あるモデルを別のものに変換する仕組みということです。
腐敗防止層は、それ自体で複雑なソフトウェアになりえるので、コンテキストマップで読んだように、テストは必須です。
腐敗防止層のインタフェース
腐敗防止層の持つ公開インタフェースは、通常、サービスの集合として現れるが、まれにエンティティのかたちをとることがある。
サービスになるのはわかるのですが、エンティティになる場合ってどういうときですかね?
腐敗防止層の実装
腐敗防止層の構成例が1つ挙げられてますね。
ファサード(FACADE)・アダプタ(ADAPTER)と変換サービスを組み合わせるというものですね。ファサード・アダプタはGOFのデザインパターンです。
腐敗防止層は、モデルの変換をするサービスではありますが、統合するシステムへのインターフェイス(APIとか)が巨大で複雑であることも多いですよね。
引数が多すぎとか、条件が複雑とか・・・それだけで、十分複雑です。
ファサードはそのために用意します。
ファサード
ファサードは、サブシステムのための代替インターフェイスです。サブシステムへのアクセスを簡略化して使いやすくし、複雑な箇所は隠蔽するものです。
ファサード内では、他システムのモデルに厳密に従って実装する必要があります。
アダプタ
アダプタの役割はクライアントから来たものを変換して別システムへ送信をすること、別システムから受信したものを変換して返すこと(変換自体は変換サービス、送受信自体はファサードで行う)です。
変換サービス
単純に変換するための機能を提供します。変換自体が複雑な作業なので、独自のオブジェクトを用意します。
これらの構成は図にするとわかりやすいですね。
落ち葉拾い
他システムがこちらに通知や要求をする場合
基本はこちらから腐敗防止層にアクセルするのですが、他システムがこちら側に通知してくる場合、他システムに腐敗防止層のサービスを呼び出せるための変更が必要になることもあります。
モデルの整合性で妥協しない
変換が難しくて、ある程度他システムのモデルに合わせなければと思うことがあるかもしれませんが、やはりそれは最終手段。モデルの整合性でまずは妥協しないことです。
ファサードが必要ないことも
他システムがシンプルであるとか、APIなどのインターフェイスが整理されている場合は、ファサードが必要ないかもしれません。
この場合は、変換サービスで全部やるってことですかね。
他システムに関する特有な機能
他システムに対する監視証跡やデバックロジックなど、特有な機能を腐敗防止層に追加してもよいでしょう。
自分で作った他システム
自分で設計したサブシステムでも、別々のモデルに基づいている場合、腐敗防止層でつなぐことに意味があります。