loose and fluffy_ddd_intro

120
Page 1/120 2016/12/18 Java女子部 イベント ゆるふわ DDD入門! 入門!

Upload: cch-robo

Post on 12-Apr-2017

273 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: Loose and fluffy_ddd_intro

Page1/120

2016/12/18Java女子部イベント

ゆるふわDDD入門!入門!

Page 2: Loose and fluffy_ddd_intro

Page2/120

自己紹介名前 robo(兼高理恵)お仕事 Java技術者 要件定義に設計から実装まで好きなもの モバイル端末

Page 3: Loose and fluffy_ddd_intro

Page3/120

はじめに

ゆるふわDDD入門入門!におこしいただいてありがとうございます。

私見ですが…ドメイン駆動設計は、オブジェクト指向プログラミングを理解し、開発経験が豊富なエンジニアが、書籍エリック・エバンスのドメイン駆動設計と実践ドメイン駆動設計を読み解き、現場で実践しないと身に付かないようです。

今回は、私の力不足から、ゆるふわなドメイン駆動設計の入門者よりの話になっています。

Page 4: Loose and fluffy_ddd_intro

Page4/120

DDDに興味を持たれたり、深堀したい方は、「ぐぐれば」既にお歴々の方々が解説してくださっていますので、そちらの資料を確認してくだいね。

併せて、エリック・エバンスのドメイン駆動設計や実践ドメイン駆動設計やオブジェクト指向プログラミング関連の書籍を読み進められると良いと思います。

ドメイン駆動設計を本格的にシステム設計に取り入れたいドメイン駆動設計を本格的にシステム設計に取り入れたい…と思っていたみなさま、ごめんなさい。

Page 5: Loose and fluffy_ddd_intro

Page5/120

参考図書

Page 6: Loose and fluffy_ddd_intro

Page6/120

エリック・エバンスのドメイン駆動設計

エリック・エバンスのドメイン駆動設計ソフトウェアの核心にある複雑さに立ち向かう

エリック・エバンスさんの視点でドメイン駆動設計を解説したバイブル本です。著者はベテランエンジニアであり、その知識と経験を前提に話が進むので、読み進むためには前提知識を学ぶ努力が必要です。

Page 7: Loose and fluffy_ddd_intro

Page7/120

「日本語版への序文」より日本語版への序文日本語版への序文(エリック・エヴァンスエリック・エヴァンスEricEvans)

根本的には、DDDを駆動している原則は次の3つだけです。コアドメインに集中すること。ドメインの実践者とソフトウェアの実践者による創造的な共同作業を通じて、モデルを探求すること。明示的な境界付けられたコンテキストの内部で、ユビキタス言語を語ること。

Page 8: Loose and fluffy_ddd_intro

Page8/120

「日本語版への序文」より

この原則はきわめて完結です。しかしもちろん、これで十分ではありません。まず、この原則はいくつかの用語の定義に依存しています。そして、この定義は本書の最も重要な内容の一部なのです。また、これらの原則を名確に理解してたとしても、成し遂げるのは容易ではありません。

偉大なソフトウェアを作り上げるためには、知性と忍耐が必要です。同様に勇気が必要であり、リスクもある程度は受け入れなければならないのです。

Page 9: Loose and fluffy_ddd_intro

Page9/120

「序文(MartinFowler)」より序文序文(マーチン・ファウラーマーチン・ファウラーMartinFowler)

ドメインモデルというものが、最初にモデル化され、その後で実装されるようなものではない、ということだ。

「まず設計し、その後に構築する」という段階を区切った考え方に対しては、多くの人々と同様に私も拒絶するようになってきている。

だが、Ericの経験から導き出される教訓は、真に強力なドメインモデルは時間と共に進化するということであり、偉大なベテランモデラであっても、最高のアイデアを得られるのはシステムが初期リリースされた後のことだ、ということである。

Page 10: Loose and fluffy_ddd_intro

Page10/120

実践ドメイン駆動設計

実践ドメイン駆動設計サンプルVaughnVernon/IDDD_Samples

ドメイン駆動設計を身につけようとしている人たちへの具体的な指針本です。エリック・エバンスのドメイン駆動設計を読んでいたほうがよいと思います、ドメインイベント、巨大な泥団子の概念、レイヤ化アーキテクチュアからヘキサゴナルアーキテクチャへの発展…などの新たな知見も追加されています。

Page 11: Loose and fluffy_ddd_intro

Page11/120

プリンシプルオブプログラミング

プリンシプルオブプログラミング良いコードを書くための「Principles/原則」の紹介と解説をまとめた本です。「単一責務の原則」や「凝集度」などエリック・エバンスのドメイン駆動設計や実践ドメイン駆動設計でも利用している概念や用語も含んでいます。実装経験をもつ人を対象としているため、具体的なコード説明がなく抽象的な解説になっていることに留意ください。

Page 12: Loose and fluffy_ddd_intro

Page12/120

参考サイト/スライドDDD難民に捧げるDomain-DrivenDesignのエッセンスhttps://www.ogis-ri.co.jp/otc/hiroba/technical/DDDEssence/index.htmlざっくりDDD入門!!http://www.slideshare.net/digitalsoul0124/ddd-17678116リッチなドメインモデル名前探しの旅http://www.slideshare.net/masuda220/ddd-fornameドメインオブジェクトの見つけ方・作り方・育て方http://www.slideshare.net/masuda220/ss-62386442「実践ドメイン駆動設計」社内読書会まとめ〜IDDD本難民に捧げる1章から7章〜http://www.slideshare.net/AtsuoAoki/iddd17

Page 13: Loose and fluffy_ddd_intro

Page13/120

参考PDFDomainDrivenDesign(ドメイン駆動設計)Quickly日本語版https://www.infoq.com/jp/minibooks/domain-driven-design-quicklyダウンロードするには、infoQへのユーザ登録(メールアドレスとPWの登録)が必要です。

Page 14: Loose and fluffy_ddd_intro

Page14/120

DDD入門!

Page 15: Loose and fluffy_ddd_intro

Page15/120

DDD難民に捧げるDomain-DrivenDesignのエッセンス第1回 ドメイン駆動設計とは

Page 16: Loose and fluffy_ddd_intro

Page16/120

ドメインモデルとはドメインモデルとはある業務に特化した、業務的に正確な意味合の取扱データや振る舞いを一般化して保持するもの。図や文書および、Javaオブジェクト実装で表現される、DDDを実践する上で欠かせないもの。

DDDにおけるドメインモデルは、依存関係が絡んだ複雑なモデルをシンプルにして扱いやすくするために、OOPの単一責任の原則に従い、各業務概念をより中核的な独立した概念に細かく分離(モデリング)していきます。ですので、たいていコアドメインと複数のサブドメインから成ります。

ドメインモデルは、抽象概念です。このため単純に利用すると、コアとなる一部分を指すか、事業ドメイン全体をカバーするのか判然としないことに注意してください。

Page 17: Loose and fluffy_ddd_intro

Page17/120

手続型設計の限界(モデリングしないと…)モデリングを使わない(あるいは不十分でも)、機能を満たすコードによる手続型設計のアプローチでも、ドメインの機能は実装できます。

ですが複雑さが爆発していくので、やがてだれも実態を理解できなくなりメンテナンスも不能になるでしょう。

Page 18: Loose and fluffy_ddd_intro

Page18/120

オブジェクト指向で、モデリングする。オブジェクト指向のアプローチを使えば、対象概念の振るまいとデータ構造(と状態)が外に漏れ出さないよう隠蔽化してくれます。隠蔽化とカブセル化で責務を分離すれば、互いの影響範囲が小さくなり、全体も見通し易くなります。新任者であってもメンテナンスし易くなるのです。一方、機能を満たすコードのみの手続き型の実装は、振るまいと状態がどこからでも操作できるので、全ての操作の整合性を管理しない限り、対象概念の振るまいと状態の一貫性が保証できません。

対象概念を表す重要な業務ロジックでさえ、どこにでも実装できるために、どこにあるのか、どこまで探せばよいのかすら判りづらくなってしまいます。

Page 19: Loose and fluffy_ddd_intro

Page19/120

ドメイン駆動設計の視点DDDの中心となる原則は、議論や傾聴、理解、発見、そして事業価値だそうです。事業価値を生み出すためには、設計(開発)対象を深く知らなければなりません。例えば銀行システムなら、事業価値は、銀行業務領域(ドメイン)が元ですから、ドメインの反映としてのソフトウエアを作成することが最優先となります。

そのためには、ドメインの核となる概念や要素を取り入れて、関係を正確に再現できるよう、ドメインをモデル化しなければなりません。

ドメインをモデル化できるようにするには、専門家や設計者/開発者が、お互いにドメイン知識を共有し磨き上げられなければなりません。

銀行システムには、ドメインだけでなくDBなどのミドルウェアも必要です。ドメインを中心にするには、それらが影響しないよう設計しなければなりません。

…忍耐強くこれらを繰り返します、技術至上主義の考え方ではありません。

Page 20: Loose and fluffy_ddd_intro

Page20/120

DDD入門!視点のドメイン駆動設計概略前ページをドメイン駆動設計のパターン用語で表現しました。

事業価値を生み出すため、業務ドメイン(ドメインモデル)を反映したソフトウェアの設計/開発を最優先する。業務ドメイン知識の共有と育成のために、業務の専門家と設計者/開発者でユビキタス言語を育てあう。ドメインをモデリングして各々の中核の責務により(コア/支援サブ/汎用サブ)ドメインに分離していくことで、境界づけられたコンテキストを見つける。境界付けられたコンテキストどうしは世界が異なるので、ユビキタス言語も異なっている。分離した(コア/支援サブ/汎用サブ)ドメインの間でオブジェクトを操作するにはユビキタス言語の変換が必要なので、変換対応のコンテキストマップを作る。

Page 21: Loose and fluffy_ddd_intro

Page21/120

DDD入門!視点のドメイン駆動設計概略アプリケーションは業務ロジック(ドメイン)だけではなりたたない。ユーザインターフェース、アプリケーション、ドメイン、インフラストラクチャのレイヤから成り立っている。ドメインと別レイヤとの橋渡しでの責務の流出/流入を防ぐため(ポートとアダプター/ヘキサゴナル)アーキテクチャやドメインイベントを使う。ドメイン内の状態や値を持つ概念をモデル化するため、同一性の有無からエンティティと値オブジェクトを作り、それらのライフサイクルと構造体関係をあらわす集約を作る。ドメイン内の集約の永続化と問い合わせ専用のリポジトリを設ける。集約や複雑なオブジェクトの生成を委譲するファクトリを導入する。ドメイン内の中核の責務から外れるロジックの配置場所としてサービスを設ける。

Page 22: Loose and fluffy_ddd_intro

Page22/120

DDD入門!視点のドメイン駆動設計概略事前に完璧な設計をすることはできない。ドメインエキスパートが気づかず、設計者や開発者とのユビキタス言語育成の中で発見される知見もある。ドメインのモデリングやリファクタリングも日々行なわなくてはならない。より良いソフトウェアは、忍耐強くこれらを繰り返して作る。

ドメインモデルは、エンティティや値オブジェクトやサービス…で形作られる概念なので、XXXドメインモデルというようなクラスはない。

Page 23: Loose and fluffy_ddd_intro

Page23/120

DDDパターン用語+詳細+α

Page 24: Loose and fluffy_ddd_intro

Page24/120

単一責務の原則

(SRP:theSingleResponsibilityPrinciple)クラスやモジュールは、ただ1つの原因(要因)により変更されなければならないことを表します。

複数の異る役割の状態や振る舞いを持つような神クラスは、責任(役割)が分割されていないことを表し、理解が困難かつバグを招くことは経験済みでしょう。責務(変更の原因となるもの)を探すことは、コードの抽象化に役立ちます。オブジェクト指向設計の概念として、最も重要なものの1つです。

Page 25: Loose and fluffy_ddd_intro

Page25/120

凝集性

(Cohesion)クラスやモジュールの機能の純粋性を表します。クラス内のメソッドとインスタンス変数においては相互依存性のこと。機能が全てのメソッドと全てのインスタンス変数を使う場合に最大となります。

インスタンス変数やメソッドの総数自体は少ないことを前提にすると、一般的に、凝集性が高ければメソッドとインスタンス変数が無駄なく相互に依存し合っていることなので、全体として1つのロジックになるように設計されている(特定の目的に特化している)といえます。

Page 26: Loose and fluffy_ddd_intro

Page26/120

依存関係逆転の原則

上位のモジュールは、下位のモジュールに依存してはならない。どちらのモジュールも、抽象に依存すべきである。抽象は、実装の詳細に依存すべきではない。実装の詳細が、抽象に依存すべきである。

実践ドメイン駆動設計第4章アーキテクチュアより

…という原則。上位レベルのコンポーネントが、下位レベルへの要求のインターフェース(抽象)を提供し、下位レベルは、それを実装することで、上位レベルは、下位レベルの実装を知らなくてもインターフェース(抽象)を知っていれば使えるようになる。こうすることで実装と抽象の依存関係を逆転させている。

Page 27: Loose and fluffy_ddd_intro

Page27/120

デメテルの法則オブジェクトを使用する場合、直接知っているオブジェクトしか使うべきではないという法則

オブジェクトのメソッド内から実行できるメソッドは、次のいずれかのみ。

そのオブジェクト自身のメソッド自身にパラメータとして渡されたオブジェクトのメソッドメソッド引数のオブジェクトから取得した別オブジェクトは使わないこと。自身の内部でインスタンス化されたオブジェクトのメソッド自身が保持しており、直接アクセスできるオブジェクトのメソッド

Page 28: Loose and fluffy_ddd_intro

Page28/120

「命じろ、たずねるな」オブジェクトを使う場合は、オブジェクトにクエリをかけて得た情報からコマンドをなげるのでなく、公開されたインターフェースで定義されたコマンドのみ使うようにすること。やることが決まっているなら問い合わせによる不必要な負荷を減らすこと。

Page 29: Loose and fluffy_ddd_intro

Page29/120

ドメインエキスパート

事業価値の元となるドメインの「細部」「ルール」「落とし穴」「潜在的な問題点」を知っている専門家のこと。銀行システムを設計/開発するのなら、いちばん銀行業業務(ドメイン)を知っている、銀行の中で働く人々やその専門家が「ドメインエキスパート」です。

Page 30: Loose and fluffy_ddd_intro

Page30/120

ユビキタス言語ユビキタス言語(模範的説明)とは、適切なドメインモデルを作りあげられるよう、ドメインの業務知識の共有と各ドメインモデルの中核概念を抽出できるようにするために作り上げる、ドメインエキスパートやソフトウェア設計者/開発者を含めたチーム全体で意思疎通を可能にして、概念名や操作名だけでなく用法も含めて育て上げる、中核とするドメインの業務知識用の共有言語(共有用語を含む)のこと。

ユビキタス言語は、特定ドメインを扱うチーム内で育て上げるため、業界全体や他チームでは意味をなさない。ユビキタス言語は、境界づけられたコンテキストごとに育て上げるので、境界づけられたコンテキストごとに異なる。よってユビキタス言語で定義した用語は、別の境界づけられたコンテキストでは、同じ文言でも別の意味になる。

Page 31: Loose and fluffy_ddd_intro

Page31/120

ユビキタス言語のアンチパターン

組織全体で流通させるユビキタス言語を目指すな組織全体の意思疎通ができたら良いと、あらゆる名称が唯一の意味しかもたないようにしようとしてはならない。

全ての業務概念についてステークスホルダー全員が納得するような共通の意味付けをすることは事実上不可能だからである。

ユビキタス言語は、合意が取れる単位で育成し流通させること。

Page 32: Loose and fluffy_ddd_intro

Page32/120

ドメインモデル

事業価値の元となるドメインの概念を抽象化(モデル化)したもの。ドメインモデルとは、EricEvansによれば、特定の図で表されるものではなく、伝えようとする概念だそうです。対象のドメインをユビキタス言語に従って表現したものであり、これがなければ、何をモデルに取り込み、何を捨てるのかが曖昧になり、ソフトウェアの全体的な展望の設計ができません。したがってソフトウェアの詳細部であるコードの設計も始められません。

ドメインは、モデリングしていくと中核的な独立した概念に細かく分離されていくので、たいていコアドメインと複数のサブドメインに分かれます。

Page 33: Loose and fluffy_ddd_intro

Page33/120

ドメインモデル貧血症ドメインモデル貧血症とは、あるドメイン固有の責務(取扱データや振る舞い)が、他のドメインに漏れだしているため、ドメインモデルが機能不全になっていること。

上記の問題によりドメインがうまく働かない(不調である)ことを、貧血症になぞらえた表現です。ドメインモデルに、DBなどの外部都合の実装が入り込んでしまっていることも含まれます。

Page 34: Loose and fluffy_ddd_intro

Page34/120

ドメインモデルとユビキタス言語ドメインモデルのコンポーネントの属性(プロパティ)の名称や、振る舞い(メソッド)の名称と引数や返値は、ユビキタス言語に従って定義します。ドメインモデルのコンポーネント(パターン)、エンティティ、値オブジェクト、サービス、リポジトリ、ファクトリ、ドメインイベント…など。

Page 35: Loose and fluffy_ddd_intro

Page35/120

コア/支援サブ/汎用サブドメイン

サブドメインや境界づけられたコンテキストを含む、抽象的な業務ドメインコアドメイン(境界づけられたコンテキスト)業務に不可欠で、ドメインの中核となるモデル支援サブドメイン(A)(境界づけられたコンテキスト)業務に不可欠だが、コアドメインとは言えないモデル支援サブドメイン(B)(境界コン+外部の境界コン)業務に不可欠だが、コアドメインとは言えないモデル汎用サブドメイン(境界づけられたコンテキスト)業務に不可欠でないが、プロジェクト全体で不可欠なモデル

Page 36: Loose and fluffy_ddd_intro

Page36/120

コアドメイン

業務に不可欠で、ドメインの中核となるモデルコアドメイン(模範的説明)とは、コアドメインとは、重要な事業価値があり、見返りが一番大きな最優先投資領域(ドメイン)のこと。プロジェクトの目的である事業の中核となるモデルである。

Page 37: Loose and fluffy_ddd_intro

Page37/120

汎用サブドメイン

業務に不可欠でないが、プロジェクト全体で不可欠なモデル汎用サブドメイン(模範的説明)とは、プロジェクト(ソリューション)全体として必要であるが、対象のドメイン内では特に何もしていない領域のこと。

Page 38: Loose and fluffy_ddd_intro

Page38/120

支援サブドメイン

業務に不可欠だが、コアドメインとは言えないモデル支援サブドメインとは、その内容が特別なもので、業務に不可欠な領域を表しているが、まだコアドメインとは言えないようなモデルのこと。

Page 39: Loose and fluffy_ddd_intro

Page39/120

境界づけられたコンテキスト境界づけられたコンテキスト(模範的説明)とは、ドメインモデルを適用する際の概念的な境界(適用範囲⇒コンテキスト)のこと。ドメイン内のモデルがどこに属すのか(コアドメイン/支援サブドメイン/汎用サブドメイン)を表す。

Page 40: Loose and fluffy_ddd_intro

Page40/120

境界づけられたコンテキストとユビキタス言語ユビキタス言語は、ドメインモデルをつくり上げるために、ドメインエキスパートや開発者の間で、あるドメイン(業務知識)中の各概念をチーム内で共有できるよう、特定の考え方や判明した知見の切り口で言語化していく(育て上げる)ものです。このためユビキタス言語中には、いくつかの「切り口として働く「切り口として働く(既存の既存の/創造の)抽象概念」創造の)抽象概念」が発生します。

ドメインモデル内では、この「切り口として働く抽象概念」「切り口として働く抽象概念」を共有しているモデルのグループとそうでないモデル達との間に(共有物がないので直接取り扱えないという)境界が発生します。この「切り口として働く抽象概念」「切り口として働く抽象概念」が「境界づけられたコンテキスト」です。共有物がないので「境界づけられたコンテキスト」ごとに、ユビキタス言語も異ることになります。

Page 41: Loose and fluffy_ddd_intro

Page41/120

境界づけられたコンテキストとコア/サブドメイン「境界づけられたコンテキスト」(「切り口として働く抽象概念」「切り口として働く抽象概念」)により、ドメインのモデルが、コアドメイン、支援サブドメイン、汎用サブドメインのいずれになるかが決まります。

ドメインの中核となる「境界づけられたコンテキスト」を持っているモデルがコアドメインです。

ドメインの中核となる「境界づけられたコンテキスト」を持っていなかったモデルは、サブドメイン(支援サブドメイン/汎用サブドメイン)になります。サブドメインは、ドメインとは異るとなるがプロジェクト全体で必要になる「境界づけられたコンテキスト」を持っているか否かで、汎用サブドメインか支援サブドメインになります。

Page 42: Loose and fluffy_ddd_intro

Page42/120

境界づけられたコンテキストとコンテキストマップ「境界づけられたコンテキスト」が異る(「切り口として働く抽象概念」「切り口として働く抽象概念」を共有していない)モデルとモデルの間のやりとりには、お互いのユビキタス言語のすり合わせのための変換対応が必要になります。

この異る「境界づけられたコンテキスト」間でのユビキタス言語の変換対応関係(概略やコード)についてのドキュメントが「コンテキストマップ」です。

Page 43: Loose and fluffy_ddd_intro

Page43/120

コンテキストマップコンテキストマップ(模範的説明)とは、プロジェクトに関わる境界づけられたコンテキストと、それらがどのように統合(変換対応)されているのかを示すドキュメントのこと。

Page 44: Loose and fluffy_ddd_intro

Page44/120

コンテキストマップの重要性

抽象化したドメインのコンテキストマップコンテキストマップは、プロジェクト全体を構成する複数の境界づけられたコンテキスト間の関係を上流/下流で表し、コンテキストの統合(変換対応)を明確にします。通常、境界づけられたコンテキストごとに、担当チームも分かれています。上流/下流の違いとコミュニケーションが必要なチームが判明するので、作業の担当範囲などのチーム間の合意形成を円滑にします。

Page 45: Loose and fluffy_ddd_intro

Page45/120

コンテキストマップとチーム間の合意形成コンテキストマップには、境界づけられたコンテキストの関係を上流/下流で表わして、作業分担の合意形成(対応)を求めていました。

上流/下流になるのは、共同作業チームだけでなく、上層部やレガシーシステムなど交渉不能である可能性もあるので、下記の対応戦略のパターンが挙げられています。

共有カーネル、顧客/供給者の開発、順応者、腐敗防止層、公開ホストサービス、公表された言語、別々の道、巨大な泥団子。

Page 46: Loose and fluffy_ddd_intro

Page46/120

共有カーネル共有カーネル(模範的説明)とは、コンテキスト間での共有に合わせて、チーム間での役割が合意できる場合の戦略。

コンテキストを共有するチーム間で、コミュニケーション(ユビキタス言語作成)を図り、相互でモデルおよび関連物(コードやDBなど)を共有します。両チームは、共有モデル⇔自分たちのモデルへのマッピング変換を行います。

Page 47: Loose and fluffy_ddd_intro

Page47/120

顧客/供給者の開発顧客/供給者の開発(模範的説明)とは、コンテキスト間の上流/下流に合わせて、チーム間での役割が合意できる場合の戦略。

上流チームは、下流チームとのコミュニケーション(ユビキタス言語作成)を図り、下流チームのニーズを考慮して開発を行います。下流チームは、上流モデル⇒下流モデルへのマッピング変換を行います。

Page 48: Loose and fluffy_ddd_intro

Page48/120

順応者順応者(模範的説明)とは、コンテキスト間の上流/下流に合わせて、チーム間での役割が合意できない場合の戦略。

下流チームは、上流チームに隷属するメリットを優先し、自分たちのドメインモデル作成を諦め、上流チームのユビキタス言語に合わせたモデルを開発します。上流モデル⇒下流モデルへのマッピング変換は発生しません。

Page 49: Loose and fluffy_ddd_intro

Page49/120

腐敗防止層腐敗防止層(模範的説明)とは、コンテキスト間の共有/上流/下流に合わせて、チーム間での役割が合意できない場合の戦略。あるいはユビキタス言語が共有できないレガシーシステムと接合する場合の戦略

該当するチームは、両者の間でのモデルの変換を行う隔離レイヤを作成して、自分たちのモデルを開発します。該当チームは、隔離レイヤのモデル⇔自分たちのモデルへのマッピング変換を行います。

Page 50: Loose and fluffy_ddd_intro

Page50/120

公開ホストサービス公開ホストサービス(模範的説明)とは、(サブシステムの利用など)コンテキスト間を1対多で共有する場合の戦略。共有サービスを設けることで、車輪の再発明抑止やメンテナンス性を向上させる戦略

集中先(サブシステム)にアクセスするプロトコルを定義し、各チーム個別のマッピング変換を担当する共有サービスを公開します。各チームは、共有サービスを介して共通プロトコル⇔自分たちのモデルのマッピング変換を行います。

Page 51: Loose and fluffy_ddd_intro

Page51/120

公表された言語公表された言語(模範的説明)とは、一般化されているユビキタス言語を使うことで、車輪の再発明を抑止する戦略コンテキスト間の共有/上流/下流に即した、一般化されたユビキタス言語がある場合の戦略。

該当するチームは、コミュニティなどで一般公開されているユビキタス言語(およびモデルやライブラリ)を間に挟んで、自分たちのモデルを開発します。該当チームは、一般公開モデル⇔自分たちのモデルへのマッピング変換を行います。

Page 52: Loose and fluffy_ddd_intro

Page52/120

別々の道別々の道(模範的説明)とは、コンテキスト間での共有が不可欠でなく、チーム間での役割が合意できない場合の戦略。

コンテキスト間での共有が不可欠でない場合、該当チームは、両者が一切つながりを持たないように設計し、その狭いスコープ内でのモデルを開発します。マッピング変換は発生しません。

Page 53: Loose and fluffy_ddd_intro

Page53/120

巨大な泥団子巨大な泥団子とは、コンテキストマップの作成が不能なことを表す概念です。打つ手がありません。

コンテキスト間での共有/上流/下流どころか、境界づけられたコンテキストへのモデリング(分離/再設計)すら困難な、様々なモデルが混在し、境界も辻褄があわなくなっていているもの全体を表す概念あるいは、そのような問題のある現行業務や既存システムの例え。

Page 54: Loose and fluffy_ddd_intro

Page54/120

巨大な泥団子と境界づけられたコンテキストドメインモデルの新規作成であっても、ドメインの中核概念に基づいたモデリング(分離/再設計)をおろそかにして、境界づけられたコンテキストの調査より先に様々なモデルを作り続けないでください。

そのような状況を放置していると、中核概念に分割していないことが、当然化、常識化してしまい、境界づけられたコンテキストに気づく機会も失ってしまいます。そして、巨大な泥団子になってしまいます。そして、巨大な泥団子になってしまいます。

Page 55: Loose and fluffy_ddd_intro

Page55/120

コンテキストマップの統合(変換対応)例

抽象化したドメインのコンテキストマップの統合(変換対応)例コンテキストマップの統合では、複数の戦略を組み合わせることもできます。

ACL腐敗防止層(AntiCorruptionLayer)OHS公開ホストサービス(OpenHostService)PL公表された言語(PublishedLanguage)

Page 56: Loose and fluffy_ddd_intro

Page56/120

アーキテクチャの役割開発するソフトウェアは、現実のドメインではなく、ドメインを扱うアプリケーションです。

このため、業務知識のロジック(ドメイン層)だけでなく、プログラム全体の取り扱いを行うもの(アプリケーション層)や、ユーザーとの対話を行うもの(ユーザインターフェース層)や、DBなどのミドルウェアのAPI(インフラストラクチャ層)のレイヤが必要になります。これらの責務は異るため、お互いにドメイン貧血症に陥らないようにするアーキテクチャが必要なのです。

Page 57: Loose and fluffy_ddd_intro

Page57/120

(アンチパターン)利口なUIUIモデルは、ユーザインターフェース層に属しますが、UIモデルからドメインを操作するなどのビジネスロジックが入り込んでしまい、ドメインモデル貧血症を起こしているもの。

Page 58: Loose and fluffy_ddd_intro

Page58/120

レイヤ化アーキテクチャレイヤ化アーキテクチャ(模範的説明)とは、ドメインを扱うアプリケーションを上位から、ユーザインターフェース層、アプリケーション層、ドメイン層、インフラストラクチャ層に分けるアーキテクチャ。ドメインが中心になっておらず従属する形となるので、近年はポートとアダプターアーキテクチャに置き換えられています。

Page 59: Loose and fluffy_ddd_intro

Page59/120

ポートとアダプターアーキテクチャポートとアダプターアーキテクチャポートとアダプターアーキテクチャ(ヘキサゴナルアーキテクチャヘキサゴナルアーキテクチャ)ポートとアダプターアーキテクチャは、対称性を生み出すためのアーキテクチャスタイル。

中心核と内部(中心核を含む)と外部(外周)の3つの領域に分ける設計手法。中心核にドメインモデル、内部にアプリケーション(ユースケース境界/ポート層)、外部にアダプター(個別クライアントとの接点)を配し、各アダプターは、対象とする特定のクライアント(ユーザインターフェースorインフラストラクチャー)との入出力を受けもつ。

Page 60: Loose and fluffy_ddd_intro

Page60/120

ポートとアダプターアーキテクチャポートとアダプターアーキテクチャポートとアダプターアーキテクチャ(ヘキサゴナルアーキテクチャヘキサゴナルアーキテクチャ)アダプター⇒個別クライアント(外向き)へはクライアント側の個別APIを使うが、個別クライアント⇒アダプター(内向き)へはアプリケーション側の共通APIを使用する。アダプター⇒アプリケーション側へは共通インターフェースを介すが、アプリケーション側のインスタンスはアダプターごとに異なる。ヘキサゴナルアーキテクチャを使うときには、ユースケースを念頭に置いてアプリケーションを設計すること。

Page 61: Loose and fluffy_ddd_intro

Page61/120

ポートとアダプターアーキテクチャの例

抽象化したポートとアダプターアーキテクチャの例

個々の外部のクライアントに合わせたアダプターが存在します。外部から内部へのアクセスには、アプリケーションのAPIを使います。クライアントは、ユーザインターフェースやインフラストラクチャにあたります。

Page 62: Loose and fluffy_ddd_intro

Page62/120

(参考参考)ポートとアダプターアーキテクチャ資料ポートとアダプターアーキテクチャ資料ドメインモデル中心のアーキテクチャhttps://devtab.jp/entry/internal/42ヘキサゴナルアーキテクチャ(Hexagonalarchitecture翻訳)http://blog.tai2.net/hexagonal_architexture.html

Page 63: Loose and fluffy_ddd_intro

Page63/120

コマンドクエリ責務分離(CQRS)コマンドクエリ責務分離(CQRS)とは、

あらゆるメソッドは、何らかのアクションを実行する「コマンド」あるいは呼び出し元にデータを戻す「クエリ」のいずれか一方でなければならず、その両方の機能を兼ね備えてはいけない。つまり、何かの質問をすることで、その質問への応えが変わってしまってはいけない。もうち少しきちんと言うと、メソッドが値を戻すのは、そのメソッドが参照透過性を持ち、何も副作用をおよぼさない場合だけでなければいけない。

実践ドメイン駆動設計第4章アーキテクチュアより

…という原則です。

Page 64: Loose and fluffy_ddd_intro

Page64/120

コマンドクエリ責務分離(CQRS)オブジェクトのレベルから見るとCQRSは、以下のような意味になります。実践ドメイン駆動設計第4章アーキテクチュアより

あるメソッドがオブジェクトの状態を変更するのなら、そのメソッドは「コマンド」であり、値を戻してはいけない。メソッドの戻り値は、Javaならvoidになる。

あるメソッドが何らかの値を戻すのなら、そのメソッドは「クエリ」であり、直接・関節を問わず、オブジェクトの状態を変更してはいけない。このメソッドの戻り値の型をきちんと指定して宣言する必要がある。

Page 65: Loose and fluffy_ddd_intro

Page65/120

コマンドクエリ責務分離(CQRS)ここでのコマンドクエリ責務分離(CQRS)とは、サーバの機能を「コマンド」(副作用あり)と「クエリ」(副作用なし)に分ける考え方です。

例えば集約は、通常だとコマンドとクエリを両方持っていますし、その集約のリポジトリにもコマンドとクエリのメソッドが存在しますが少々非効率でもあります。

CQRSを使って、クエリの処理を最適化するために、集約のコマンドとクエリをコマンドモデルとクエリモデルに分離します。

コマンド発行によるコマンド状態変更時に、コマンドモデルがコマンド・リポジトリへの保管と、クエリモデルの更新ならびにクエリ・リポジトリへの保管を行わせます。コマンド発行の処理が増えてしまいましたが。クエリ発行では、クエリ・リポジトリからクエリモデルを取得するだけでことが済むようになります。

Page 66: Loose and fluffy_ddd_intro

Page66/120

コマンドクエリ責務分離(CQRS)の例

抽象化したコマンドクエリ責務分離(CQRS)の例QuPrc:クエリプロセッサCmPrc:コマンドプロセッサ(アプリケーションサービス)EvSBS:(全ての)イベントのサブスクライバCmM:コマンドモデルQumSta:クエリモデルの保存場所CmMSta:コマンドモデルの保存場所

Page 67: Loose and fluffy_ddd_intro

Page67/120

コマンドクエリ責務分離(CQRS)の例ユーザからの入力:クライアント{ユーザ入力からコマンド発行}⇒コマンドプロセッサ{コマンド受信からコマンド更新}⇒コマンドモデル{状態更新のためコマンド集約を生成}⇒コマンドモデル・リポジトリ{コマンド集約を保管}⇒コマンドモデル{状態更新のドメインイベント発行}⇒イベントサブスクライバ{状態更新のドメインイベント受信からクエリ更新}⇒クエリモデル{最新状態反映のためクエリ集約生成}⇒クエリモデル・リポジトリ{クエリ集約を保管}クエリモデルは、ここでは表示していません。

Page 68: Loose and fluffy_ddd_intro

Page68/120

コマンドクエリ責務分離(CQRS)の例ユーザからの出力要求:クライアント{ユーザ出力要求からクエリ発行}⇒クエリプロセッサ{クエリ受信からクエリ集約を要求}⇒クエリモデル・リポジトリ{クエリ集約を返却}⇒クエリプロセッサ{取得したクエリ集約から出力データ生成}⇒クライアント{画面出力}クエリモデルは、出力用の非正規化データです。

Page 69: Loose and fluffy_ddd_intro

Page69/120

コマンドクエリ責務分離(CQRS)の例イベントのサブスクライバによるクエリモデルの更新コマンドモデルは、クエリモデルが同期するようドメインイベントを発行する必要があります。

コマンドモデルは、状態変更時に状態更新のドメインイベントを発行します。ドメインイベントを受信するサブスクライバは、受け取ったドメインイベントに従ってクエリモデルを更新します。このようにして、クエリモデルに、コマンドによる最新状態が反映されるようにします。

Page 70: Loose and fluffy_ddd_intro

Page70/120

イベント駆動アーキテクチャ(EDA)イベント駆動アーキテクチャ(EDA)は、イベントの作成や検出、消費そしてイベントへの反応を促すアーキテクチャです。

実践ドメイン駆動設計では、オブジェクトとオブジェクト操作元との結合を切り離す設計手法として利用しています。

クライアントなどのオブジェクト操作元は、操作するイベントタイプのイベントを発行し、ドメインオブジェクトは、サブスクライバから購読したイベントタイプを介した間接的な操作を行うことで、操作元との結合を切り離します。こうすることでドメインオブジェクトの依存は、メッセージングシステムと購読するイベントタイプのみとなります。

Page 71: Loose and fluffy_ddd_intro

Page71/120

イベント駆動アーキテクチャの例

抽象化したイベント駆動アーキテクチャの例

イベント駆動アーキテクチャにより、3つのシステム(ポートとアダプターアーキテクチャ)の結合が切り離なされ、メッセージングシステム自身と購読するメッセージのイベントタイプだけに依存するようになっています。

Page 72: Loose and fluffy_ddd_intro

Page72/120

イベントソーシングイベントソーシングは、オブジェクトへの変更追跡ができるようにするパターンです。

実装ドメイン駆動設計の例でのイベントソーシングでは、ドメインモデル内の集約のインスタンスへの全ての操作コマンドに対し、操作コマンドの実行ごとにドメインイベントを発行して、イベントストアに発生順に記録させています。

これにより、任意時点での集約の状態が再現(追跡)できるようになります。任意時点までのイベント(操作コマンド)を発生順に適用させて再現します

Page 73: Loose and fluffy_ddd_intro

Page73/120

ドメインモデルと同一性を持つオブジェクトドメイン駆動設計のドメインモデルには、現実のドメインの反映が求められます。ですが社員情報など、同一性をもったオブジェクトは、ドメインロジックで対応できません。オブジェクトには、ライフサイクルがあり、生成から破棄までを繰り返しますが、ロジックだけでは再生成時の最新状態への反映ができないからです。

同一性をもったオブジェクトには、以下の対応が必要です。

状態が更新された時には、破棄されるまでに、状態をどこかに保管すること。再生成された時には、保管していた状態を読みだして再現すること。ひとつの概念を表す集団に含まれる場合は、集団を単位として対応すること。

ドメイン駆動設計では、これらに対応するため、エンティティ、値オブジェクト、集約、リポジトリのパターンが用意されています。

Page 74: Loose and fluffy_ddd_intro

Page74/120

エンティティエンティティ(模範的説明)とは、同一性をもつオブジェクトを扱う設計パターンドメイン内で特定の、変化していくが同一性を持ち唯一な物を表します。

同一性の保証が必要なオブジェクトです。一意な識別子と属性や振る舞いを持っていて、状態が変化しても同一物であることが識別でき、同じ状態のものがあっても他と区別できます。

同一性をもっている(唯一物である)ため、同型の別インスタンスと交換することは無意味です。

Page 75: Loose and fluffy_ddd_intro

Page75/120

エンティティの設計エンティティの設計は、子エンティティのコンテナではなく、値のコンテナとして組み立てること。

エンティティ設計の初期段階では、エンティティを一意に特定するポイントとなる属性や振る舞いにだけ注目する。

エンティティには、同期対応が必要。エンティティは、変化できます。このため変更があれば全ての参照先に伝えて、同期してもらう必要があります。この問題には、イベント駆動アーキテクチャとドメインイベントの組み合わせで対応できます。

Page 76: Loose and fluffy_ddd_intro

Page76/120

エンティティ(補足)UUID生成器Java標準APIには、かなりの確率で完全に一意な識別子を作成するUniversallyUniqueIdentifier(UUID)UUID生成器が用意されている。

StringrawId=java.util.UUID.randomUUID().toString();

擬似乱数生成器と暗号化

SecureRandomrandomGenerator=newSecureRandom();intrandomNumer=randomGenerator.nextInt();StringrandomDigits=newInteger(randomNumber).toString();MessageDigestencryptor=MessageDigeet.getInstance("SHA-1");byte[]rawIdBytes=encryptor.digest(randomDigits.getBytes());

Page 77: Loose and fluffy_ddd_intro

Page77/120

エンティティ属性のバリデーション属性/プロパティへの操作は、自己カプセル化(アクセッサメソッド仲介)で行ない、不適切な値の設定がされないようにします。

自己カプセル化とは、クラス内のデータへのアクセスは、たとえ同一クラスの中からでも、アクセッサメソッド経由で行うよう設計することだ。MarfinFowler

メリットとして、インスタンス変数を抽象化でき、他のオブジェクトの属性やプロパティを容易に使えるようになり、バリデーションあるいはアサーションでの事前チェックもできるようになります。…が、実践ドメイン駆動設計の著者はこう思ってます。

バリデーションは、単体で個別の関心事であり、バリデーション専任のクラスが受け持つ責務である。ドメインオブジェクトに実装するものではない。

Page 78: Loose and fluffy_ddd_intro

Page78/120

オブジェクト統合失調症オブジェクト統合失調症とは、処理を移譲されたオブジェクトが、委譲元のエンティティ・オブジェクトの識別子を知らない状況を表します。

エンティティは、同じ状態であっても他と区別できますが、識別子が判らないため、処理を委譲されたオブジェクトは、委譲元のエンティティを区別できなくなることをパラノイアになぞらえた表現です。

Page 79: Loose and fluffy_ddd_intro

Page79/120

値オブジェクト値オブジェクト(模範的説明)とは、ドメイン内で特定の、計算や定量化や交換可能な性質の概念を表します。

同一性の保証が必要ない効率化のためのオブジェクトです。変更不可能(不変)な値の属性と副作用のない振る舞い(関数)を持ち、値の透過性から同じ状態のものは区別できず同じものとして扱います。交換可能性があるため、同型の新インスタンスとの交換で状態更新とすることもできます。

振る舞いは副作用を持たず、新しい値を返すことはできますが、自分自身の状態を変更することはできません。補足)色コード(#ffffff)をString型でなく、ColorCode型の値オブジェクトにすると、単なる文字列でなく、ドメイン内での色コードという概念を表せるようになります。

Page 80: Loose and fluffy_ddd_intro

Page80/120

値オブジェクトのモデリングディスカッションで、以下のような特徴の概念があれば、値オブジェクトとして定義します。

そのドメイン内の何かを計測したり定量化したり、あるいは説明したりする。状態を不変に保つことができる。関連する属性を不可欠な単位として組み合わせることで、概念的な統一体を形成する。計測値や説明が変わったときには、全体を完全に置き換えられる。値が等しいかどうかを、他と比較できる。協力関係にあるその他の概念に、副作用のない振る舞い(関数)を提供する。

Page 81: Loose and fluffy_ddd_intro

Page81/120

値オブジェクト:概念的な統一体概念的な統一体は、関係する全ての属性の値がないと成り立たないもの。例)トッピングしたアイスの代金(アイスとトッピングは全種同額)代金は、トッピングの個数が決まらないと決定しない。

値オブジェクトはひとつ以上の属性を持っています。それらがお互いに関連していて、全体をもってこの値の説明ができ、それらのいずれかを切り離しても、この値の説明ができなくなる。これらの条件をみたす値オブジェクトは、概念的な統一体です。

Page 82: Loose and fluffy_ddd_intro

Page82/120

値オブジェクト:状態更新も扱えるエンティティでなくても、値オブジェクトで状態更新を扱えます。設計中のオブジェクトが状態を更新するので「これはエンティティ!」と単純に考えないでください。

オブジェクトが同一性をもたないのでしたら、値オブジェクトを使うことを検討してください。値オブジェクトは交換可能性があるので、新インスタンスに置換することで状態更新が扱えます。

Page 83: Loose and fluffy_ddd_intro

Page83/120

値オブジェクト:副作用のない振る舞い値オブジェトは、エンティティを変更しないでください。変更するとテストが難しくなってしまいます。

自分自身の状態変更でないからといって、パラメータとして渡されたエンティティの変更はしないでください。

Page 84: Loose and fluffy_ddd_intro

Page84/120

値オブジェクト:できるだけ値で受け取るメソッドのパラメータは、できるだけ値でもらい、値オブジェクトをそのまま受け取らない。値オブジェクトをそのまま受け取ることは、他人の内部構造を知っている(依存する)ことになります。メソッドのパラメータは、実際に使う属性のみを受け取るようにすること。メソッドのパラメータは、できるだけエンティティを受け取らないようにすること。  エンティティの状態変更がないことを保証しにくいため。

//修正前floatpriority=businessPriority.priorityOf(product);

//修正後floatpriority=businesssPriority.priority(product.businessPriorityTotals());

Page 85: Loose and fluffy_ddd_intro

Page85/120

値オブジェクト:ミニマリズムを考慮メソッドのパラメータには、実施に使う値オブジェクトや属性を渡すようにすること。下流のモデル内の管理負担が最小限になるようにします。

Page 86: Loose and fluffy_ddd_intro

Page86/120

値オブジェクト:標準型を利用する値オブジェクトが複数派生する場合は、標準型を追加して区別できるようにする。

標準型とは、あるものの種類を説明する型のこと。例えばユビキタス言語にPhonNumber(電話番号)が定義されていているなら、標準型のPhoneTypeを定義すれば、電話番号がさらに家電話(Home)か携帯電話(Mobile)かを説明できます。

//電話種別の標準型を定義enumPhonType{Home,Mobile,Other};

Page 87: Loose and fluffy_ddd_intro

Page87/120

値オブジェクト:永続化判断永続化するからといって、必ずエンティティが必要になるわけではありません。

あるオブジェクトを永続化する場合は、そのオブジェクト型専用のテーブルに格納されることもあります。そのテーブルには、主キーも含まれる…だからといって、オブジェクトがエンティティであると決めつけないでください。

DDDは、ドメインモデルを中心に設計するパターンです。永続化するオブジェクトが、エンティティか、値オブジェクトで良いのかは、ドメインモデルが決めることです。

そのためのチェック項目も提案されています。

Page 88: Loose and fluffy_ddd_intro

Page88/120

値オブジェクト:永続化判断チェック項目

1. 今モデリングしているのは、そのドメインにおける何かのものなのだろうか?それとも、測定値や量など、物の性質についての説明なのだろうか?

2. 正しくモデリングしてドメインの要素を表したときに、このモデルの概念は、さきほどまとめた値の特徴をすべて(あるいは、ほぼ)満たしているだろうか?

3. エンティティを使おうとしている理由は、ベースにあるデータモデルが、ドメインオブジェクトをエンティティとして扱うことを求めているからというだけのことなのだろうか?

4. エンティティを使おうとしている理由は、ドメインモデルが一意な識別子を必要としていて個別のインスタンスを気に掛ける必要があり、オブジェクトの状態の変更を追跡する必要があるからなのだろうか?

Page 89: Loose and fluffy_ddd_intro

Page89/120

値オブジェクト:永続化判断実践ドメイン駆動設計では、前ページのチェック項目が1:性質についての説明、2:Yes、3:Yes、4:Noであるなら、値オブジェクトを使うべきとしています。

そして、オブジェクトを格納する場所としての永続化ストアは用意するが、それがドメインモデル内の値の概念化に影響を及ぼさないようにすることが重要としています。

ドメインモデルに、インフラストラクチャのデータモデルが漏れ出している。ドメインモデルが、データモデルの単なる写像になっている。

Page 90: Loose and fluffy_ddd_intro

Page90/120

集約集約(模範的説明)とは、同一性をもつオブジェクトを含む集合を扱う設計パターン

関連が深くてライフサイクル(生成から破棄までの生存期間)が同じオブジェクトの集合(Aggregates)から、代表とするエンティティ(ルート)を選んでひと括りとし、内部の操作はルートを経由しなければできないようにすることで、ライフサイクルの境界での一括したアクションを扱い易くします。集約のインスタンスの永続化には、リポジトリを使います。

Page 91: Loose and fluffy_ddd_intro

Page91/120

集約の不変条件集約は、集約内にあるオブジェクトと集約全体に対して、不変条件を強制します。不変条件が満たされることで、トランザクション制御ができるようになります。不変条件とは、内容が意図した通りであり変更されていないことの保証です。

Page 92: Loose and fluffy_ddd_intro

Page92/120

集約の不変条件集約全体の不変条件強制ロジック

集約は、集約内部のメンバ(エンティティと値オブジェクト)を集約の境界に定義し、外部から参照できないように隠蔽化します。集約の境界内のメンバは、お互いと他の集約ルートのみ参照できます。集約は、代表とするエンティティを一つ選び、ルートエンティティとします。集約は、ルートエンティティのみが、集約外部のオブジェクトからアクセス可能とし、かつルートエンティティを経由しなければ、集約の境界内のメンバの操作もできなくします。集約は、ルートエンティティに集約の境界会内の不変条件をチェックする責務を負わせます。

集約は、このようにして集約の境界内のメンバの意図しない変更を防ぎ、不変条件(データの一貫性)が満たされるようにしています。

Page 93: Loose and fluffy_ddd_intro

Page93/120

リポジトリリポジトリ(模範的説明)とは、ドメインモデルに同一性をもつオブジェクトの永続化の概念を導入する設計パターン

集約を使い、モデルのロックを可能にして、トランザクションを管理できるようにします。リポジトリにより、ドメインにインフラストラクチャの都合が漏れださないようにして、ドメインロジックをコアドメインに集中できるようにします。

Page 94: Loose and fluffy_ddd_intro

Page94/120

リポジトリと永続化リポジトリは、集約を概念上の集合のように表現して、コレクションのように操作でき、かつ背後でのDBへの永続化までできるようにしてくれます。集約のオブジェクトの追加や削除が実行されると、リポジトリの背後にある仕組みが、データベースに対して挿入や削除を行います。こうして、ライフサイクルの始まりから終わりまでを通じて、集約のルートに対するアクセスとデータベースとの透過的同期を提供します。

Page 95: Loose and fluffy_ddd_intro

Page95/120

リポジトリのフロー例

抽象化したリポジトリのフロー例

クライアントから受けた選択条件をDBインターフェースに渡します。DBインターフェースから受け取ったデータを集約に変換します。(集約の生成にファクトリが介在する場合もある)クライアントに集約のオブジェクトを返します。

Page 96: Loose and fluffy_ddd_intro

Page96/120

ファクトリファクトリ(模範的説明)とは、複雑なオブジェクトや集約のインスタンス生成責務を別のオブジェクトに移すパターンです。

集約の各メンバが、自分の中核ロジックに集中できるようにするため、集約全体をひとまとまりとして生成して、インスタンス生成の複雑さを隠蔽します。

Page 97: Loose and fluffy_ddd_intro

Page97/120

ドメインイベントドメインイベントは、ドメイン内で発生した/する、何らかの出来事を捉えるためのものです。メッセージングシステムを使い、何らかの操作を表すコマンドやクエリを、境界づけられたコンテキストを超えてドメインモデル内の対応する専任者に通知して、対処してもらえるようにするパターンです。

Page 98: Loose and fluffy_ddd_intro

Page98/120

ドメインイベントの例

ドメインイベントのフロー例実践ドメイン駆動設計第8章ドメインイベント図8-1より

集約がイベントを作って出版し、サブスクライバは、そのイベントを格納して、リモートのサブスクライバに転送するか、格納せずに転送しています。

Page 99: Loose and fluffy_ddd_intro

Page99/120

ドメインイベントの導入検討条件組織の文化によって注意すべきフレーズは代わりますが、ディスカッションで、以下のようなフレーズが出たきた場合ドメインイベントの導入を検討します。

何かのきっかけで、何かをしなければいけないことがキーポイント

「…するときに、」「もしそうなったら、…」「…の場合は、私に知らせて欲しい」「…の場合は、通知して欲しい」「…が発生したときに」

あるいは、

(社内の別システムの)あるドメインで発生したイベントを別(システム)の境界づけられたコンテキストに通知しなければいけないとき。

Page 100: Loose and fluffy_ddd_intro

Page100/120

ドメインイベントの実現手法ドメインイベントでは、集約の変更成功のイベント通知により、関係する他の集約のインスタンスの同期(別トランザクション)が行えるよう、結果整合性(次の更新までに同期が保証できる)が図れる手法を利用します。これは、イベントの他のコンテキストへの配送に時間がかかるためです。

結果整合性には、スケーラブルかつシステム間を疎結合に保つメリットもあります。

結果整合性(EventualConsistency)は、データが更新された際には、即座にデータが反映されなくても、参照時に更新結果が得られば良い…結果的に一貫性が保たれればよいという考え方です。

Page 101: Loose and fluffy_ddd_intro

Page101/120

ドメインイベントのモデリングイベントのモデリングの基本

イベントやプロパティの名前には、イベント発生元の境界付けられたコンテキストのユビキタス言語に沿います。イベントの名前には、実行されたコマンドを用いるのが適切です。(コマンドがイベントの発生要因のため)イベントの発生元や関連するプロパティを追加します。イベントが発生した集約や、関係する他の集約(およびその識別子)イベントを発生するために必要なパラメータイベントの発生による集約の状態の推移

イベントが提供するメソッド(挙動の操作)を追加します。イベントの発生要因を表すプロパティを伝える目的操作

Page 102: Loose and fluffy_ddd_intro

Page102/120

ドメインイベントのモデリングイベントのモデリングについての補足

イベントに追加する振る舞いは、副作用のないものにします。イベントは基本的に不変クラスなのでシンプルになります。

Page 103: Loose and fluffy_ddd_intro

Page103/120

ドメインイベントのユースケースドメインイベントの一般的な使用例では、パブリッシャー(出版)とサブスクライバー(購読)というパターンを使います。集約が特定のイベントを作成し、それをパブリッシャーが発行(出版)して、(システムやコンテキスト境界をまたいだドメインモデルの)それを対象としたサブスクライバーが捕捉(購読)することで、特定のイベントに必要な対応を行ないます。

Page 104: Loose and fluffy_ddd_intro

Page104/120

ドメインイベントのコンポーネントドメインモデル内のイベントを扱うコンポーネント

パブリッシャーパブリッシャーは、集約に対してシンプルなサービスを提供し、集約がイベントのサブスクライバに通知を送れるようにするための軽量なオブザーバです。ドメインモデルと同じモジュールに属します。サブスクライバーサブスクライバーは、対応するイベントが指定され、イベントハンドリング(捕捉)時の処理が実装された軽量なオブザーバです。一般的に、アプリケーションサービス(あるいはドメインサービス)からパブリッシャーに登録され、イベントを発行する集約と同一のスレッドで実行されます。

Page 105: Loose and fluffy_ddd_intro

Page105/120

ドメインイベントのコンポーネントドメインモデル内のコンポーネントについての補足

ドメインモデルの情報をメッセージング基盤に漏らさないこと。ドメインモデルからインフラストラクチャを間接的に利用することがあっても明示的に結合させてはいけません。サブスクライバでは、指定されたものとは別の集約のインスタンスを取得して状態変更をしてはいけません。

Page 106: Loose and fluffy_ddd_intro

Page106/120

ドメインイベント:メッセージング基盤の利用リモートにイベントを届けるためにはミドルウェアを使います。リモートの境界づけられたコンテキストに、手元のコンテキストで発生したイベントを届けるには、一般的にミドルウェアに分類される、ActivieMQやRabbitMQやAkka…などのメッセージング・コンポーネントを使います。あるいは、RESTリソースを使った、独自のメッセージング・システムでも対応可能でしょう。

Page 107: Loose and fluffy_ddd_intro

Page107/120

ドメインイベント:メッセージング基盤の整合性モデルとイベントの整合性を保つ永続化の3パターン

1. ドメインモデルとメッセージ基盤の永続化共有モデルへの変更と新しいメッセージの追加を、同一のローカルトランザクション内で行えるよう、ドメインモデルとメッセージング基盤が、永続化ストア(データソースなど)を共有します。欠点:メッセージングシステムのストレージ領域をドメインモデルと同じデータベースに配置しないといけない。

2. ドメインモデルとメッセージ基盤の永続化のグローバル制御モデルとメッセージングのストレージを別々にできるよう、ドメインモデルの永続化ストアとメッセージングの永続化ストアを、グローバルなXAトランザクション(二相コミット)で制御します。欠点:グローバルなトランザクションを考慮しないといけない。

Page 108: Loose and fluffy_ddd_intro

Page108/120

ドメインイベント:メッセージング基盤の整合性モデルとイベントの整合性を保つ永続化の3パターン

3. イベントストアの利用イベントストアは、モデルとイベントとの整合性が、単一のローカルトランザクション内で保証されるよう、イベント用の特別なストレージ領域(データベースのテーブルなど)を、ドメインモデルが使っているのと同じデータストア内に用意する手法です。ストレージ領域は、境界づけられたコンテキストが所有して管理します。外部のコンポーネントは、このイベントストアを使って、格納済みのイベントのうちまだ発行していないものを、メッセージングメカニズムを利用して発行します。欠点:メッセージングメカニズムを経由して送信するために、イベントをそのメカニズムに転送する仕組みを自作しないといけません。補足:イベントストアの基本役割は、シリアライズしたイベントをその発生順に保持することです。

Page 109: Loose and fluffy_ddd_intro

Page109/120

ドメインイベント:イベントストアの主目的イベントストアが提供できるもの

リモートのサブスクライバがイベントに反応できる。イベントストアをメッセージング基盤を通してすべてのイベントを発行する際のキューとすることで、リモートのサブスクライバが自分のコンテキストの必要に応じてイベントに反応できるようになります。RESTベースの通知をクライアントに提供できる。集約のコマンドの結果を完全に記録できる。ドメインモデル上で実行された全てのコマンドの結果を履歴として記録できます。データを使って、傾向の分析や今後の予測などを行なえる。

Page 110: Loose and fluffy_ddd_intro

Page110/120

ドメインイベント:イベントストアの主目的イベントストアが提供できるもの

集約のインスタンスの再構築ができる。リポジトリから取得した時系列のイベントを適用することで、集約のインスタンスが再構築できます。集約に対するある時点の変更を取り消せる。取り消したい過去のある時点を指定して、マークされたイベントを無視して、集約のインスタンスの再構築を行います。

Page 111: Loose and fluffy_ddd_intro

Page111/120

サービスサービス(模範的説明)とは、ドメインの中核から外れるが、そのドメインに必要なタスクをこなす、ステートレスな操作のこと。

どのオブジェクトにも属さいない操作のため、オブジェクトとしてモデル化すると不自然ですが、エンティティや値オブジェクトの責務としても不自然なので、それ用の独立した操作インターフェース(メソッド)のみ提供します。

システムレベルのリモートプロシージャ呼び出し(RPC)やメッセージ指向ミドルウェアを使うような「サービス」のことではありません。

Page 112: Loose and fluffy_ddd_intro

Page112/120

サービスの種類ドメインサービスは、ドメインの中核から外れるが、そのドメインに必要なタスクをこなす、ステートレスな操作であり、ビジネスロジックを持ち、アプリケーションサービスを使い、多少複雑になることもある粒度が細かいタスクをこなします。

アプリケーションサービスは、ビジネスロジックを持たないアプリケーション全体のロジックを提供し、ドメインモデルのクライアントであり、ドメインサービスのクライアントにもなります。

Page 113: Loose and fluffy_ddd_intro

Page113/120

ドメインサービスの導入検討条件ドメインサービスを使う(導入する)のを検討する条件は、操作が、既存のエンティティや値オブジェクトに属さないとみなせる場合です。

以下のような条件が、考えられるそうです。

重要なビジネスロジックを実行する。ドメインオブジェクトを、ひとつの構成から別の構成に変換する。複数のドメインオブジェクトからの入力にもとづいて、値を算出する。モデルの中核ではないが、そのモデルに不可欠な要件がある。例:アカウント情報のパスワードは暗号化する。アカウント情報に情報保管以外の暗号化という責務があることは、単一責務の原則に違反しているためサービスに移します。

Page 114: Loose and fluffy_ddd_intro

Page114/120

ドメインサービスのモデリングドメインサービスのモデリングは、以下のようにシンプルです。

ドメインサービスのインターフェース宣言は、ドメインのモジュール内で行う。ドメインサービスの実装は、(アプリケーションのモジュールなど)ドメインモデルの外部に配置する。ドメインサービスのセパレートインターフェースは、複数実装が必要でなければ必須ではない。操作名は、必ずユビキタス言語の一部(動詞)で命名すること。状態を持たせないこと。

Page 115: Loose and fluffy_ddd_intro

Page115/120

モジュールモジュール(模範的説明)とは、Javaではパッケージと呼ばれている概念のこと。DDDの文脈におけるモジュールに相当する。DDDの文脈におけるモデル内のモジュールは、ドメインオブジェクト内のひとまとまりのクラス群をまとめる、名前付きのコンテナ。同じドメインオブジェクト内の他のモジュールのクラス群との結合を少なくするよう設けます。

Page 116: Loose and fluffy_ddd_intro

Page116/120

モジュールの例//トップレベルのモジュール名(一般的に所属先の逆インターネットドメイン名)som.saasovation

//境界付けられたコンテキストを表すモジュール名//実際のコンテキスト名と一字一句同じにする必要はないcom.saasoation.identiyaccesscom.saasovation.collaborationcom.saasovation.agilpm

//ドメインのモジュール名com.saasoation.identiyaccess.domaincom.saasovation.collaboration.domaincom.saasovation.agilpm.domain

//ドメインモデルのモジュール名com.saasoation.identiyaccess.domain.modelcom.saasovation.collaboration.domain.modelcom.saasovation.agilpm.domain.model

//ドメインモデルのサービス名com.saasoation.identiyaccess.domain.serviscom.saasovation.collaboration.domain.serviscom.saasovation.agilpm.domain.servis

Page 117: Loose and fluffy_ddd_intro

Page117/120

モジュールの例//ドメインモデル内のモジュール名//ドメインモデルのコンポーネントを配置するcom.saasovation.agilpm.domain.model.tenant   <<valueobject>>TenantIdcom.saasovation.agilpm.domain.model.team   <<servis>>MemberService   <<aggregateroot>>ProductOwner   <<aggregateroot>>Team   <<aggregateroot>>TeamMembercom.saasovation.agilpm.domain.model.product   <<aggregateroot>>Productcom.saasovation.agilpm.domain.model.product.backlogitem   <<aggregateroot>>BacklogItemcom.saasovation.agilpm.domain.model.product.release   <<aggregateroot>>Release//backlogitemやreleaseは、モデル内のモジュール内のモジュールを示す

Page 118: Loose and fluffy_ddd_intro

Page118/120

みなさん、お疲れ様でした。

この発表は、エリックエバンスのドメイン駆動設計と、実践ドメイン駆動設計の

特徴的な一部のパターンの表層をなでただけです。

そして「意図の明白なインターフェース」のような、細かいことですが重要な基本も抜けてしまっています。

ドメイン駆動設計は、もっともっと深いものです。この発表が、何かのきっかけになりましたら幸いです。

Page 119: Loose and fluffy_ddd_intro

Page119/120

ご清聴、ありがとうございました。

Page 120: Loose and fluffy_ddd_intro

Page120/120