🐙

【実践ドメイン駆動設計】第3章 コンテキストマップ 読書メモ

2023/06/25に公開

実践ドメイン駆動設計の読書メモ

ロードマップ

  • コンテキストマップを描くことがなぜプロジェクトの成功に股可決なのか
  • 意味のあるコンテキストマップを描くのがいかに簡単なことであるか
  • 組織的な関係やシステム的な関係を考慮し、それがプロジェクトにどのように影響するかを検討
  • SaasOvationチームが、コンテキストマップを活用して、プロジェクトを掌握していく様子を見る

3.1なぜそんなにもコンテキストマップは重要なのか

  • 自分達のプロジェクトのマップを描く主な目的は、解決空間の全貌を俯瞰できるようにすること
  • 巨大な泥団子・・・中身の仕様がごちゃごちゃでほぼブラックボックス。APIもわかるけどそれもごちゃごちゃであんまり取り扱いたくない、どうやって動いてるのかわからないみたいな感じのもの
  • 巨大な泥団子との結合を求められる際も、コンテキストマップにその関連をきちんと反映させておく必要がある
    • 自分たちのチームにはそこから得られる知見が必要だし、どこでチーム間のコミュニケーションが必要になるかを判断できるから
  • 早いうちにコンテキストマップを描いておけば、依存する他のプロジェクトとの関係を、注意深く考えられるようになる

Evans本より

  • プロジェクト機能しているモデルをそれぞれ識別して、その境界づけられたコンテキストを定義する
  • 境界づけられたコンテキストそれぞれに名前をつけ、その名前をユビキタス言語の一部にする
  • モデル同士の接点を記述して、あらゆるコミュニケーションで必要となる明示的な変換について概略を述べ、共有するものがあれば強調する。

コンテキストマップを描く

  • コンテキストマップは、現存する地形を捉えるもの
  • 現状に注目すれば、今自分達がどこにいるのかや、次に向かうべき場所がどこなのかを把握できる
  • 儀式的な作業が増えるとコンテキストマップ作成がめんどくさくなってしまうので、シンプルかつアジャイルにすすめる
  • オープンな議論をし、会話によって戦略的な知見が見つかったら、それをコンテキストマップに追加する
  • コンテキストマップは組織の動きを示すものなので、進捗の妨げになるようなガバナンスの問題や、チームやマネジメントに関する課題を浮き彫りにすることもある。(?)
  • コンテキストマップはチームメンバーが常にそれを見て議論できるようにしておく必要がある
  • DDDには組織的なパターンや結合のパターンがいくつかあり、二つの境界づけられたコンテキストの間には、いずれかが当てはまることが多い。例は下記

組織的なパターンや結合のパターンの定義

  • パートナーシップ: 二つのコンテキストを担当するチームが成功/失敗の運命を共にする場合、チーム間で協力的な関係を築く必要がある。両チームは、開発のプランニングや統合時の結合管理を共同で行うことにする。両チームが協力して、インターフェイスを果tんさせ、お互いのシステムのニーズを満たすようにする必要がある。相互依存するフィーチャーは、お互いのリリースに間に合うように開発しなければならない。
  • 共有カーネル: 一部のモデルやそれに関連するコードを共有すれば、相互依存性が高まる。これは設計作業の助けになることもあれば、逆に邪魔になってしまうこともある。明示的な境界を定め、二つのチームが共有することに合意したドメインモデルのサブセットを指定すること。このカーネルは、できるだけ小さくまとめること。この明示的に共有されたものには特別な地位が与えられているので、もう一方のチームに相談せずに変更してはならない。継続的な統合プロセスを定め、チームのユビキタス言語に合わせてカーネルのモデルを維持すること
  • 顧客/共有者の開発: 二つの開発チームに上流/下流関係があり、上流のチームが成功するかどうかが下流の結果に左右されうるということがある。そんな場合、上流チームは下流チームのニーズにさまざまな方法で対応する必要がある、下流の優先順位を考慮して、上流のプランニングを行う。下流の要件に必要となる作業について交渉し、予算を立てることで、提供の約束とスケジュールを全員が理解できるようにすること.
  • 順応者: 二つの開発チームに上流/下流関係があるにもかかわらず、上流に下流チームの要求に応える動機がない場合、下流チームはどうすることもできない。人の役に立ちたいという思いから上流開発者は約束するかもしれないが、それが守られるとは思えない。下流チームは境界づけられたコンテキスト間の変換の手間を省くために、上流に当てられたモデルで我慢することになる。
  • 腐敗防止層(ACL): 変換層はシンプルで、エレガントなことさえあるが、それはうまく設計された境界づけられたコンテキスト同士を協力的なチームで橋渡しする場合である。しかし、コントロールやコミュニケーションが不十分なために、共有カーネルやパートナーシップそして顧客/供給といった関係を取り除けなかった場合は、変換が複雑になってしまう。そんな場合の変換層は、より防御的な色合いを帯びるようになるだろう。下流のクライアントは、隔離するためのレイヤを作成することによって、上流のシステムの機能を独自のドメインモデルの用語で表現する機能を提供する。この層は、既存のインターフェイスを通して他のシステムと通信するので、他のシステムを修正する必要はほとんどないか、全くないこともある。 内部的には、このレイヤが必要に応じて、二つのモデル間での変換を両方向に対して行う。
  • 公開ホストサービス(OHS): サブシステムにアクセスできるようにするプロトコルを、サービスの集合として定義すること、そのプロトコルを公開し、サブシステムと統合する必要のある人が全員使用できるようにすること。新しい統合の要件に対応する際には、プロトコルに機能を追加し、拡張すること、ただし、あるチームだけに特有の要求は別だ。そのような特殊なケースには、一回限りの変換サービスを使用してプロトコルを拡張し、共有プロトコルは単純で一貫性のある状態に保つこと。(APIみたいな認識)
  • 公開された言語(PL): 二つの共愛づけられたコンテキスト内にあるモデル同士で変換するんには、共通の言語が必要である。必要なドメインの情報をコミュニケーションにおける共通の媒体として表現できる、明確にどキュ、円溶かされた共通言語を使用し、必要に応じてその用語への変換と、その言語からの変換を行うこと。公表された言語は、公開ホストサービスと組み合わせて使われることが多い。(スキーマ)(apiと一緒に使われることが多い)
  • 別々の道: 要件定義は容赦なく行わなければならない。二つの機能の集合が互いにとって不可欠でないのなら、切り離すことができる。結合は常に高くつくが、それによる利益は小さいこともある、境界づけられたコンテキストを他とは一切繋がりを持たないものと宣言し、開発者あその小さいスコープ内で、シンプルで特化した解決策を見つけられるようにすること。
  • 巨大な泥団子: 既存のシステムを精査した結果、システムを構成する各部分がどれも大規模であることがわかった。しかも、さまざまなモデルが混在しており、境界も辻褄が合わない、そんな場合は、そのひどい状態の全体を大きく囲む境界を定め、巨大な泥団子として扱う。このコンテキスト内では、綺麗にモデリングしてやろうなどとは考えないこと、そんなシステムの影響が他のコンテキストに及ばないように、注意すること。

3つのコンテキストマッピング

  • サブドメイン(問題空間)と境界づけられたコンテキスト(解決空間)が1対1になっていることが理想(?)

  • 隔離されたコア(Evans)を使って、リファクタした

  • 今このようなコンテキストの状態になっている

  • U→Dに影響を及ぼす

  • 認証アクセスコンテキストは、他の二つのコンテキストに影響を及ぼす。

  • 境界づけられたコンテキストで説明した通り、ProjectOvationは可能な限りそれ単体で自立して動くようにするべきだが、上流のモデルに一切依存せずにサービスを稼働させるということではない

統合パターンと特徴

公開ホストサービス

このパターンはRESTベースのリソースとして実装できる。クライアント側の境界づけられたコンテキストから、それを利用することになる。一般的に公開ホストサービスはリモートプロシージャコール(RPC)のAPIだと考えられてる。メッセージングを使った実装にすることもできる。

公表された言語

いくつかの方法で実装できるが、よく使われるのはXMLスキーマ。RESTベースのサービスとして表現する際には、公表された言語を、ドメインの概念の表現として扱う。表現方法には、XMLやJSONなどがある。あるいはGoogle Protocol Buffersを使って表現することもできる。RESTを使うメリットの一つは公表された言語をどの形式で表現するかを、クライアント側で指定できる。

腐敗防止層

ドメインサービスを下流のコンテキストで定義して、それぞれの方に対する腐敗防止そうとすることができる。また、腐敗防止層は、リポジトリインターフェイスの中に入れることもできる。RESTを使う場合は、クライアント側のドメインサービスの実装が、リモートの公開ホストサービスにアクセスすることになる。サーバー側は、それに対する応答を、公表された言語として表現する。下流の腐敗防止層は、その表現を、ローカルのコンテキストのドメインオブジェクトに変換する。例えば、コラボレーションコンテキスト認証・アクセスコンテキストに対して、モデレータ権限を持つユーザーのリソースを問い合わせたるという操作がその一例で、リクエストしたリソースを、XMLやJSONなどで受け取るかもしれない。それを、値オブジェクトであるModeratorに変換する。Moderatorのインスタンスは下流のモデルの用語を反映するものであり、上流のモデルとは関係がない。

実践タイム

  1. プロジェクトの現状を表すシンプルな図を描く(図に描いた内容をソフトウェアとして実装することを覚えておく)
    下記のようなものも示す
    1. 境界がどこに位置するのか
    2. それらとチームとの関係
    3. どのような種類の結合になるか
    4. 必要となる変換

  2. 1. 自分達の境界づけられたコンテキストについて、本来そこに属さない概念を見つけたら、新しいコンテキストマップを描いて、必要なコンテキストとそれらの関係を示してみる
    2. DDDの9種類の関係から選ぶとしたらどれか?またそれを選ぶ理由は?

  3. 自分たいslのプロジェクトの境界づけられたコンテキストの中にある統合の中から、どれか一つを選んで、変換マップを作ってみよう。変換が過剰に複雑になったり、大量のデータのコピーや同期を要したり、変換後のオブジェクトがもう一方のモデルとよく似たものになったりといったことはないだろうか・おそらくそれは、他の境界づけられたコンテキストから受け取る内容が多すぎて、あまりにもそのモデルに合わせすぎており、自分達のモデルとの間に衝突を起こしてしまっているのだろう。

Discussion