<< Conformist パターン : めをつぶってアリモノを使う | main | Anticorruption Layer を開発する >>

Anticorruption Layer パターン : 己を知り、敵を知れば...

システム開発の相談が飛び込んできた。

20 の Bounded Context があって、いろいろからみあっていて、さらに外部システムとも接続する。
いきなり「アプリケーション連携」のヘビーな実践テーマが飛び出しきちゃったなあ。

開発済みの範囲は、半分以下。既存システムは、3つ(?)。
10くらいの Bounded Context を無理矢理、3つのシステムに割り振って、開発した感じ。

そもそも、10の Bounded Context ではなく、3つの Bounded Context に見えているらしい。
ここらへんの認識あわせが、骨かもしれないなあ。

いつものことだけど、「時間も予算もない」、だけど、「なんとかして」コール。

大きな絵としては、それぞれの Bounded Context に分けてアプリケーションを開発し、それを連携する基盤の整備をすれば、なんとかなりそう、という方向で話しをするつもり。

UI 層、ドメイン層、インフラ層の切り分けを明確にするアーキテクチャの改良活動も必要だな。

いちおう絵は描いたけど...

システム間接続


エンタープライズアプリケーション開発やっていれば、アプリケーション連携やシステム間接続は、必然的な開発テーマ。

新規開発の基本要件には、だいたい「既存システムとの連携」が入ってくる。

既存システム相手では、 Shared Kernel パターンや Customer/Supplier Development Teams パターンは使えない。

かといって、 Conformist パターンで、既存のシステムにあわせると、モデルが違いすぎて、新システムの本来の目的を、とても達成できそうもない。

こういう時の選択肢が「Anticorruption Layer パターン」。

ある Bounded Context と 別の Bounded Context の間に、「汚染」を防止する「変換レイヤ」を用意するわけだ。

よくある開発テーマ。

多くの場合、

・通信方式
・データ型
・文字コード

などのレベルで仕様を決めて、接続とデータ変換やれば、いっちょうあがり、というやり方が多い。

これだけでも「接続」の効果は大きい。

モデルの変換


Domain-Driven Design (DDD) では、そういう下位の通信レイヤの変換だけでなく、「ドメインモデル」の違いとその変換に注目する。
他の層から分離した「ドメイン層」が、いちばんの関心事。
"Isolationg the Domain" 。なんどもでてくる DDD の基本中の基本ですね。

別のアプリケーションになっているのは、目的も背景もこだわりポイントが違うから。
それぞれが別の Bounded Context であり、ドメインのモデルもまるで別のもの。
似ているように見えても「きっと違っているはず」という姿勢が基本。

「モデル」の異なる Bounded Context 間で、連携するには、「モデル」と「モデル」の「変換」こそ、もっとも重要な関心事だし、ソフトウェアの価値を大きく左右するポイント。

「モデルの変換」をうまくモデリングして設計・実装すれば、役に立つソフトウェアになり、コードが扱いやすくなる。将来のそれぞれのアプリケーションの変更にも柔軟に、簡単に対応しやすくなる。

「モデルの変換」の設計が怪しいと、開発中のソフトウエアは、既存システムのモデルに「汚染」され、本来の目的に、あんまり役に立たず、ぎこちなく、扱いにくいコードになっていく。

なぜ "Anticorruption" ?


もし、それぞれのドメイン(問題領域)を深く理解し、うまく設計された Bounded Context 同士の連携であれば、2つのモデルの変換も、意図が明確で、わかりやすい設計・実装になる。

現実には、既存アプリケーションのモデルと設計・実装は、いろいろ理由で歪んでいたり、不完全なことがあたりまえ。

理想的な、よくできたモデル間の連携なら "Translation" という素直な名前で良い。

エバンスが、「Anticorrution(汚染防止)」という、ネガティブな名前をつけたのは、現実のアプリケーション間連携は、「きれいごと」ではすまないことが身にしみているからでしょう。
多かれ少なかれ、連携相手からの「汚染」を防ぐという姿勢にならざるをえない。

まったく、その通り。

新しく開発するドメインで、よいモデルを発見できそうでも、既存システムの連携がでてくると、いろりろ歪み始める。

相手システムやその開発者たちに呪いの言葉を吐いても、なにも解決しない。
それよりも、自分たちでよい仕事をして解決しようね、というのが Anticorruption Layer パターンの考え方かなあ。

そのほうが、確かに健全ではある。

やり方


他の連携パターンに比べ、このパターンは、Building Block や、やり方が、具体的に書いてある。

現場で出くわす機会の多い課題だし、実践経験も豊富だから、パターン化できてきているんでしょうね。

都合の良いインタフェースを考えちゃう


手のつけどころは、簡単。

自分たちが取り組んでいる Bounded Context のためのドメインモデルに、いちばん都合の良いインタフェースをまず、設計しちゃう。

おそらく Service クラスを設計して、都合の良いタイミングで、都合の良いオブジェクトを入手したり、送り出したりできるようにする。

この段階では、相手の都合は一切無視。

自分たちのモデルをシンプルに、純粋に、意図を明確に保つことに、徹底的にこだわって設計すればよい。

相手のインタフェースの整理


次のステップは、相手側のインタフェース。

相手が提供する既存のインタフェース仕様、それからその背後にある「相手のモデル」を、調べて、検討してみる。

既存システムは、いろいろな機能やデータ項目が、からみあって、外部インタフェースも、かなり複雑になっていることも多い。

そこを整理して、相手のインタフェースの中で、自分たちの関心事だけに簡略化した、Facade クラスを設計しちゃう。

Facade は、こっちのモデルの一部ではなく、連携相手のモデルの一部。
既存のインタフェースは、いろいろな事情で複雑に膨れ上がっていても、

・必要な情報
・必要なタイミング

など、こうなっているとわかりやすいな、という視点で「相手側のインタフェース」に Facade パターンを適用しちゃう。

内部の複雑さを隠蔽して、こっちにわかりやすく単純化したインタフェースを用意する。

Service と Facade ができたら、中を作る


こちら側の出入り口に、便利な Service クラスを用意。
あちら側の出入り口に、わかりやすい、Facade クラスを用意。

ここまでくれば、Anticorruption Layer の設計・実装は、わりと素直にできる。
「イン」と「アウト」が明確に定義されていれば、話は簡単でしょう。

ただし、「関心事」の分離が鉄則。

・モデル層以外の「低レベル」の変換は、インフラ層に実装して「隠蔽」すること
・複数の変換テーマがある時は、変換テーマごとに別々のクラスを用意すること
 (GenericTranslator とか、Universal Adapter とか、ConvertUtil とか、設計しないこと)

使うパターンは、基本は二つ。

・Adapter パターン
・Translator パターン

Adapter パターンは、文字通りに「アダプタ」です。変換するわけではなく、形状の違い等の吸収。

論理的に変換するニーズは、別途 Translator クラスを設計する。
「変換」のニーズごとに、別々の 小型で、意図が明確な Translator クラスを作っていく。

小さく分けておくことで、要求の変化への対応が単純になり、それぞれのクラスを再利用できる可能性も広がる。

登場人物のまとめ


Anticorruption Layer の登場人物(オブジェクト)をまとめておくと、こちらの Bounded Context 側に近い順に、

・連携サービスのインタフェース ( Service クラス )
・Adapter ( こちらの Service と あっちの Facade をつなぐ )
・Translater ( Adapter から呼ばれる変換機能 )
・Facade ( 相手のインタフェースの理想(?)形)

双方向に連携する場合、同じ Adapter/Translator ではうまくいかないことが多い。
方向が違えば、モデルの変換ロジックは別ものになることが多い。

一般に、通信を扱うときに「上り」と「下り」は、別のクラスの責任にしておくのが良い。

オブジェクトの「配置」


Anticorruption Layer を、ひとかたまりのモジュールとして、一箇所に配置するとは限らない。
こちらと、連携相手のシステムとの間で、配置パターンには選択肢がある。

A. Facade まで含めて、こちらの環境に配置。( Facade クラスが相手と「通信」する )
B. Facade は、連携先に配置。(通信は、Adapter と Facade 間 )
C. Service まで、連携先に配置。(通信は、Service のリモート呼び出し)

どれを選択するかは、性能、コスト、システム管理ポリシー、....など、さざまなな要素を考える必要がある。

あるいは、開発時とか、移行期間中とかもかかわってくる。

いずれにしても重要なのは、

・モデル層とインフラ層の分離
・モデルとモデルの変換

をきちんと、モデリングし、設計・実装すること。

たいせつなのは、良い変換は、自分たちの Bounded Context の理解だけではダメ。

英語と日本語を翻訳するときに、両方の言葉(その背景の概念)に精通しているほど、良い翻訳ができる。

Bounded Context 間の連携も、こちらの「ユビキタス言語」と相手の「ユビキタス言語」の両方を理解して、バイリンガルになることで、仕事が簡単になるし、よい結果をだせる。

こちらの「ユビキタス言語」の理解がしっかりしていれば、相手の「ユビキタス言語」の理解も楽になる。
まずは、自分たちの「ユビキタス言語」を確立することからはじめる。

コメント
コメントする









この記事のトラックバックURL
トラックバック
calendar
     12
3456789
10111213141516
17181920212223
24252627282930
31      
<< March 2024 >>
システム設計日記を検索
プロフィール
リンク
システム開発日記(実装編)
有限会社 システム設計
twitter @masuda220
selected entries
recent comment
recent trackback
categories
archives
others
mobile
qrcode
powered
無料ブログ作成サービス JUGEM