腐敗防止層を意識して綺麗なドメインを保ちたい

本記事は ドメイン駆動設計#1 Advent Calendar 2019 20日目の記事です。

こんにちは、会社でエリックエヴァンスのDDDの輪読会が開催されていて、半年経ってようやく飲み込めてきた程度のレベルのきり丸です。

## 注意
私のメインで使用している言語がJavaなので、Javaを基準に考えています。
他の言語では必ずしも一致しないとは思うので、その点はご了承ください。
また、エリックエヴァンスのドメイン駆動設計はまだ完全に読めていないので、本で定義されている内容を再度書いている可能性もあります。

### 腐敗防止層とは
> 腐敗防止層とは他システムへメッセージを送信する仕組みではない。むしろ、あるモデルやプロトコルの持つ概念オブジェクトやアクションを別のものに変換する仕組みなのだ。
>
>エリック・エヴァンスのドメイン駆動設計 P 375

プログラム間やサーバ間の変換にかかるコストが高い時に、変換を隔離したい時に使用する変換層です。

相手のドメインモデルと自分のドメインモデルの中間に存在するので、独自のユビキタス言語やドメインモデルを保つことができるようになります。
また、腐敗防止層そのものを双方向のインターフェイスとして利用することができます。

### なぜ大事だと思っているのか
モノリシックなシステムでは、フロントエンドとバックエンド間をつなぐアプリケーション層、DB、別サービスと連携するインフラストラクチャ層はフレームワークの性質上、オブジェクトにGetter / Setterを付ける必要があり、エンティティでも値オブジェクトでもないDTOが生成されます。

Microservice化した場合、さらに連携するサービスごとにDTOが生成されます。

長年色んなシステムが開発された結果、単独のシステムだけで価値を得るというのは難しくなっているので、Microservice化をせずともDTOが大量発生しているのが現状です。

DTOは一時的なものであり、特別な意味を持たないモデルであることを意識しているのであれば良いのですが、大抵はめんどくささに流されてしまって、そのままDTOをいろんな場所で使いまわそうとしてしまいます。
(※私の経験したプロジェクトでは必ず一度はDTOを使いまわそうとしましたし、DDDを勉強しなければエンティティや値オブジェクトを作ることを面倒くさがってたと思います。)

DTOからエンティティや値オブジェクトを生成しましょう。
値オブジェクトの大事さは他の色んな記事で紹介されています。

---

個人的な感覚ではありますが、メインがJavaエンジニアだということもあり、サーバサイドについてはDTOを使いまわさないように意識することはできるものの、クライアントサイドに関してはまったく意識しておりませんでした。

RESTを一切使わないのであればクライアントの腐敗防止層は意識しないでよいと思いますが、
REST連携を画面側で行うのであれば腐敗防止層を意識する価値はあると思います。
openAPI等で連携機能もDTOも自動生成できるようになったことを考えると、昔より腐敗防止層を用意する価値が上がっていると思っています。


相手のドメインに完全に依存するというのも選択肢としてはありです。
ただ、腐敗防止層も用意してよいということを頭の片隅に入れておくと別のアクションも取れるようになります。

---

最悪、DTOを使いまわすこと自体は問題ないのですが、色んな箇所で使われてしまうと、そのDTOがどういう値を持ちうるかが分からなくなるのが問題です。

例えば、クレジットカードの審査をするAシステムに対して、画像を保存しているBシステムを元に画像の種別を取得してからAシステムに連携するとします。

![alt](http://www.plantuml.com/plantuml/png/SoWkIImgAStDuN8iA53GjLDmKh1II4yjUR5YpxCPVSzcx-1o0ea29O7YJrjxNwpO29JIC30mr0Jfm2Ntk6cIu-F6rKydT3nkwd_SEFjnuxBd-tU_MB5P0raZKDlpAPjVhEu6YpgavgK07G80)

実は、同じように画像を保存しているCシステムがあり、Bシステムにデータが無かった場合にCシステムに問い合わせてからAシステムに問い合わせるようなフローになっていたとします。

![alt](http://www.plantuml.com/plantuml/png/SoWkIImgAStDuN8iA53GjLDmKh1II4yjUR5YpxCPVSzcx-1Ap2bHS7hSjFrnqyx7pMsFcnSyRbpzkBdzSVEUnqtx7pVsF6viUjpKpUK4qWmq0wZzQMllYnKRWIPe61WOQe8CnYNtk6cI8z2ufnCw7ZVrFswS_RXnsVFzkr-isAm1qfYQKvoAr-hdBGiVDxOWM-sNN-AMNvgN0hFK6TqtpjYSOcbfYN0cfXmXP-QbA0032Mu0KFlpAPjVhEu6ope0fO712m00)

問題なのは、BシステムもCシステムも免許証という画像種別は同じなのに、Bシステムでは001、Cシステムでは999で管理しています。
現時点ではそれに合わせた変換ロジックを持てばいい話ですが、このケースが少しでも複雑になると途端にどちらの値が入ってくるかが分からなくなりがちです。

そこで、腐敗防止層の出番です。
今はBシステムからAシステム、CシステムからAシステムに画像種別を直接変換していますが、一旦アプリ側で別の画像種別(A)を持たせてBシステムもCシステムもAppに合わせて変換するようにし、Aシステムに連携するようにしてはどうでしょうか。

![alt](http://www.plantuml.com/plantuml/png/SoWkIImgAStDuN8iA53GjLDuqJhXsTJfBsTiUhPsaPE2bK9wQicB5NkUpUXxDdi75ueaI3M6YiIS4WMdnqtR7pVjVDpSzhXvmUF6rO-RsnytxtdSjFznOy_ZngR7JTrSJjYiUjhQ-sB5Hg1P6WO6XfgebX5M_xXf4j0BGEkUJkXutDJ_k77suyPbp_VlVh5YiuOZ5jE0YgtW9e1KfEOKf-9r-_EMXOyRMx2xtI-_n2s_D2y5gpr8yjY2sHbVC3k3L6EeSCPc1i8tbfQMg3uch9wKy7F67dvvAGh0w8Vv44WXM-48jW2xyS3OW-i2kklvbCqlLdU3HHs0XW8J9m00)

腐敗防止層という登場人物が増えたことにより、パッと見たところの処理は複雑になっていますし、本来行わなくてもよいAppの持つ画像処理の変換等、無駄な処理が増えているように思えます。
しかし、各コンポーネントの責務は減っていますし、Appから見てBシステムの画像種別、Cシステムの画像種別を意識しなくてよくなったので、使い心地としてはかなり改善されていると思います。


今回はAppが新たに画像種別を持つようにしましたが、Bシステムの画像種別を正とするとしてもよいと思います。
その判断は政治的な観点が絡むと思ってます。
例えば、LINEとヤフーの合併のように、PayPayとLinePayといった似た性質のアプリを持つけど、どちらを正とするか、完全に別とするかとかは関係者の判断ですし。

### まとめ
腐敗防止層を意識して作成すると、コンポーネントの責務がより明確になってモデルを守りやすくなるので、意識してみませんか。