DDD
CONTEXT MAP - コンテキストの地図 (p.344) †
要約 †
CONTEXT MAP - コンテキストの地図
個々のBOUNDED CONTEXTだけでは、全体的な視点は得られない。他のコンテキストは、いまだ曖昧だったり流動的だったりするかもしれない。
***
問題サマリ
- 他のチームのメンバは、コンテキストの境界にあまり注意を払わず、境界を曖昧にしたり、相互の結びつきを複雑にするような変更を加えてしまうものだ。
- 異なったコンテキスト同士で連結が必要になる場合、このようなことをしていると、双方に悪い結果をもたらす。
- BOUNDED CONTEXT間でのコードの再利用は、基本的に避けるべきだ。機能やデータを統合する際には、translation(翻訳/中継)を通して行うべき。
- 異なるコンテキスト同士の関連を定義し、プロジェクトのすべてのコンテキストについての俯瞰的なビューを作ることで、プロジェクトが混乱しづらくなる。
- CONTEXT MAPは、プロジェクトマネジメントとソフトウェア設計の重なる部分に位置するものだ。物事の自然な成り行きにまかせれば、コンテキスト境界はチームの境界に従うことになるだろう。
- 近くで働く人たち同士では自然にモデルのコンテキストを共有することになるし、異なるチームの人たち(や同じチームにいても会話しないような人たち)は異なるコンテキストを持つことになるだろう。
- 物理的な場所の影響力も大きい。特別な努力を払わない限り、ビルの反対側にいるだけで(別の都市にまでわかれずとも)、異なるコンテキストを持つようになってしまう。
- プロマネはこのことを知っていて、サブシステムに従ってチームを組織する
- が、組織・モデル・設計の関係は必ずしも十分明らかになっているとは言えない
- マネジャとチームメンバーは双方とも、ソフトウェアモデルや設計が、概念的にどのように分割されているかに関するクリアな視点が必要だ。それも最新のやつ。
Therefore:
- 個々のモデルがプロジェクトにおいてどのような役割を果たしているかを特定し、BOUNDED CONTEXTを定義せよ。ここには、オブジェクト指向ではないようなサブシステムのモデルも含まれる。
- 個々のBOUNDED CONTEXTに名前をつけ、その名前がユビキタス言語の一部になるようにせよ。
- モデル同士が接する部分を明らかにせよ。あらゆる相互作用についてtranslationの概要を明示し、あらゆる共有部分を目立つようにせよ。
- 現在の状況を描け。変更は後でやれ。
解決方法サマリ
- 個々のBOUNDED CONTEXTの中では、首尾一貫したユビキタス言語の方言を持つことになる。CONTEXTの定義を明確にし、どんなモデルも曖昧さを残さず使えるように、BOUNDED CONTEXTの名前はその方言の一部となる。
- 地図は、必ずしも特定の形式で文書化される必要はない。Evansは、この章の冒頭に描いたようなものが良いと感じているが、違う形が好みの人もいるだろう。どの程度詳細に描くかというのも、状況による。
- いずれにせよ、地図はプロジェクトのすべてのメンバが共有し、理解しなくてはならない。また、地図はBOUNDED CONTEXTにわかりやすい名前を与え、CONTEXT同士が接する場所やCONTEXT自身の性質を明らかにしなくてはならない。
***
- BOUNDED CONTEXT間の関係は、設計上の問題やプロジェクト編成上の問題に応じてさまざまな形を取る。
- CONTEXT MAPは常に、現在の状態を描くようにすることを忘れないように。
- 現在の関係が後で述べるパターンに近い場合、パターン名を使いたくなるかもしれないが、強制してはいけない。純粋に、現在見られる関係を記述すること。より標準的な関係に移行するのは後でできる。
- じゃあ、こんがらがっていたり矛盾を含んでいるようなモデルを見つけたらどうする?それでも全部地図に書き出して、おかしなところを見つけるんだ。
- ささいなものは修正
- プロセスは補強
- 関係があいまいなら、近いパターンを見つけて移行
- 一気に全体的な再編成にすすんではいけない。曖昧さのない地図を手に入れ、すべての仕事をBOUNDED CONTEXTに置き、モデル間が明確な関連で結ばれるようになるまで、明らかな矛盾についてだけ変更するようにすること。
- 一貫した地図が手に入ったら、変更したい場所が見つかるだろう。設計やチーム編成に対して、よく考えた上で変更を加えることができる。
- 現実に変更がなされるまで、地図を変更しないように。
例:Shipping Applicationの2つのContext
- いつもの出荷システムに戻る。
- 予約時の、積荷の自動ルーティングについて考える。モデルは図14.2を参照。
- Routing Serviceは、受け取ったRouting Specificationを満たすようなItineraryを返す。
- Routing Serviceは、既存(Booking Application)のドメインモデルを拡張するような(LegsとかItineraryを使う)形にしたいと思っていたが、うまくやるには洗練されたアルゴリズムが必要だとわかった。これは、最適化されたネットワークとして実装する必要がある。そうした場合、vesselは行列の1つの要素として表される。
- つまり、違ったモデルが必要。よって、異なる概念構造を持つ2つのBOUNDED CONTEXTを作り、Network Traversal Serviceが要求を受ける形にした。
- Routing Serviceへの要求を、Network Traversal Serviceがわかる形に翻訳してやらないといけない。さらに、Network Traversal Serviceの戻り値をRouting Serviceが返すはずの値に翻訳してやらないといけない。
- ただし、モデルのすべてをマッピングする必要はない。
- RouteSpecification?からlocation codeのListへの変換
- Node IdのListからItineraryへの変換
- ちなみに、戻りは本当はもうちょっと考えないといけない。仕様を満たすルートは1つじゃないから。
- このあたりの仕事をこなすため、Translationオブジェクトを作ろう
- これは、双方のチームが維持しなくてはいけない
- テストが簡単にかけるようになっていた方が良い。また、テストスイートを共有する形で仕事をするめるのが良いだろう。
- Translationを作ることで、Routing Serviceはすっきりする。
- 2つのCONTEXTの境界が接する部分は、かなり小さくなっている。Routing Serviceが、Route-FindingのCONTEXTからBooking CONTEXTの残りの部分を分離してくれている。
- インタフェースは、副作用のない関数として設計されているのでテストもしやすい。Route SpecificationをRouting Serviceに渡し、返されたInineraryをチェックするような自動テストは簡単に作れるようになっているべきだろう。
モデルのCONTEXTは常に存在するが、明確に意識しなければ、オーバーラップしたり変動したりする。明確にBOUNDED CONTEXTを定義し、CONTEXT MAPを作ることでモデルの統合や接続をコントロールできるようになる。
CONTEXT境界のテスト
- CONTEXT同士の境界はかなり重要なため、テストするべき。テストによって、翻訳の繊細な部分や、あまりうまくやりとりできていない部分を補うことができる。
CONTEXT MAPの整理とドキュメント化
- BOUNDED CONTEXTは、チームのユビキタス言語の一部になっているべき。
- 全員が境界の場所を知っていなければならず、どんなコード片や状況に関しても、どのCONTEXTに属するかがわからなければならない。
- 2つ目の要求を満たすためには、状況によっていろんな方法がある。一度BOUNDED CONTEXTが定義されたなら、異なるCONTEXTのコードは自然に異なるMODULEに分離される。どのMODULEがどのCONTEXTに属するかを追跡することも必要になるが、そのためには命名規約が役に立つかもしれない。
- 同様に重要なのは、全員が同じような方法で概念的な境界についてコミュニケートすること。
- このためには、例に示したようなインフォーマルな図を使うのが好きだ。
- どんな場合でも、地図が議論の役に立つようにするのは非常に重要。名前をユビキタス言語に入れること。
***
担当者のつぶやき †
みんなの突っ込み †