【読書メモ】実践ドメイン駆動設計 ~第7章~ 「サービス」
前回 【読書メモ】実践ドメイン駆動設計 ~第6章~ 「値オブジェクト」
サービスとは
第7章で扱う「サービス」とは「ドメインサービス」のことを指す。
- ドメインサービス
ドメインに特化したタスクを処理するステートレスな操作。集約や値オブジェクトの外に実装したほうがいいロジックなど。
- アプリケーションサービス
ドメインモデルのクライアント。トランザクションやセキュリティなどの調整的な処理など。
いつドメインサービスを使うのか?
避けるべきこと
- ドメインサービスの多用
ただし、なんでもかんでもサービスとしてモデリングしてはいけない。
サービスを使いすぎると、ドメインモデル貧血症に陥るため。
- ミニレイヤの実装
「ドメインサービス層」というミニレイヤを作ることはアンチパターン。
レイヤが肥大化する傾向にあるため。
- アプリケーションサービス層での実装
アプリケーションサービスは、ドメイン外部の関心事を実装する場所。 ドメイン内部のビジネスロジックが、利用側(アプリケーションサービス)に流出させないため。
参考
「実践ドメイン駆動設計」から学ぶDDDの実装入門 (WINGSプロジェクト 青木淳夫 著)
以上
【読書メモ】実践ドメイン駆動設計 ~第6章~ 「値オブジェクト」
前回 【読書メモ】実践ドメイン駆動設計 ~第5章~ 「エンティティ」
計測・定量化・説明を表現する。
例えば、数字・文字列・日付・時刻、氏名、電話番号など。 以下の特徴に合致する際、値オブジェクトとしてモデリングする。 例)
年齢: 誕生からどれだけ生きてきたのかを計測し、定量化した値。 状態が不変である。(不変性) 組み合わせることで、概念的な統一体を形成する。(概念的な統一体) 例)
お金:「額」と「通貨」という属性が組み合わさったもの。 例)
通貨の額を変えたい時、新しい「お金」オブジェクトを生成する。 値オブジェクトが持つ各属性全ての値が同じか、を判定できること。 どのような状態で何度呼び出しても、オブジェクトの状態が変わらない操作。 値オブジェクトを利用することで、下流のコンテキスト側に存在するモデルが管理するプロパティを最小限にすることができる。その結果、複数の境界づけられたコンテキスト間の結合を緩やかにすることができる。 例) 「実践ドメイン駆動設計」から学ぶDDDの実装入門 (WINGSプロジェクト 青木淳夫 著) 以上What is 「値オブジェクト」
値オブジェクトのモデリング
「100」と「ドル」という個別では意味を持たないものが、「100ドル」となり完結した意味を持つ。
コンテキスト間の結合をミニマムにする
コラボレーションコンテキストの中に、Moderatorが値オブジェクトとして存在。
コラボレーションコンテキストが腐敗防止層から認証・アクセスコンテキストに問い合わせる。
ユーザがモデレータロールを付与されている時、Moderatorオブジェクトを生成する。
参考
【読書メモ】実践ドメイン駆動設計 ~第5章~ 「エンティティ」
前回 【読書メモ】実践ドメイン駆動設計 ~第4章~ 「アーキテクチャ」
DDDにおいて「エンティティ」は一意なものを示す概念。長期に渡り、変化する可能性がある。 DBのプロパティをpublicなプロパティーとして保持し、そのgetter/setterのみから構成されるモデル。
オブジェクトとしての「振る舞い」がほとんどない状態で、「単なる手続き型設計」になっている点が、アンチパターンとされる。 早期生成: エンティティを永続化する前に、生成と割り当てを行う。 遅延生成: エンティティを永続化する時に、生成と割り当てを行う。 エンティティが保持する識別子とは別に、オブジェクトの識別子を別の方式で管理したい時に利用。例えば、ORMツールのHibernateは、データベースに依存した型で識別子を持つ必要がある。 レイヤスーパータイプを利用することで解決する。 ※自己カプセル化・・・ クラス内部からフィールドにアクセスする際もアクセサメソッドを利用する方法。 「実践ドメイン駆動設計」から学ぶDDDの実装入門 (WINGSプロジェクト 青木淳夫 著) 以上What is 「エンティティ」
一意ではなく、変化しないものは「値オブジェクト」と呼ばれる。ドメインモデル貧血症
エンティティ設計
一意な識別子
生成タイミング
代理識別子
エンティティの生成方法
バリデーション
参考
【読書メモ】実践ドメイン駆動設計 ~第4章~ 「アーキテクチャ」
1. What is Architecture
2. アーキテクチャの種類
Layers
特徴
クライアント -> サーバ -> DB のように、層に分けるパターン。名前空間の分割、各レイヤの依存関係、責務の明確化。
問題点
ドメイン層がインフラ層に依存するため、ドメインの実装が、インフラ層の実装に依存してしまう。
解決策
DIP(Dependency Inversion Principle)を用いる。
インフラ層の実装をドメイン層の抽象に依存させ、ドメイン層を独立させる。
Hexagonal or Ports and Adapters
特徴
システムを内部と外部の領域に分け、外部からの入力をアダプタが変換し、内部のAPIの形式に合わせる。
テスト用のアダプターが容易に作れる点が利点。
クライアント、永続化の種類が未定のうちから、暫定的なアダプターを作ればドメインの実装を進められる。
Service-Oriented
SOAの8つの原則
原則 | 説明 |
---|---|
Standardized Service Contracts | サービスは契約(インターフェース)によって説明される |
Loose Coupling of Service | 疎結合であり、外部への依存は最低限にする |
Service Abstraction | インターフェース(契約)のみ公開し、内部の詳細は見せない |
Service Re-Usability | 実装は一つで、他サービスから再利用可能である |
Service Autonomy | サービスが独立して存在し、一貫性と信頼性を保っている |
Service Statelessness | サービスを利用する側が状態を管理する |
Service Discoverability | サービスをメタデータで記述し、発見可能にする |
Service Composability | サービスはより大きなサービスの一部に組み込み可能である |
Representational State Transfer (REST)
RESTの定義
RESTとは、Fieldingが博士論文として提唱してアーキテクチャスタイル。
https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
RESTに従っていることをRESTfulと呼ぶ。
- point1 リソースはURI(Uniform Resource Identifer)により、一意に識別される。
- point2 一つのHTTPリクエストに、サーバ側での処理に必用な情報を全て含める。サーバは個別のリクエストに依存しない。
- point3 全てのオブジェクトが同じインターフェースを持ち、決められたメソッドで操作される。(特に重要なメソッドとして、GET, PUT, POST, DELETE)
- point4 レスポンスに他のリソースの情報を埋め込める。Hypermedia as the Engine of Application State(HATEOAS)
RESTとDDD
RESTとDDDをどう組み合わせるか? ドメインモデルをRESTful HTTPで直接公開するのは悪手。ドメインモデルに手を加えるたびに、システムのインターフェースにも手を加える必用が出てくる。
システムのインターフェースレイヤを、境界づけられたコンテキストとして分離する方法が一般的に使われる。
Command-Query Responsibility Segregation (CQRS)
解決したい課題
- 読み取りと書き込みのデータの形は一死するとは限らない。
- 同じデータセットに、並列で操作が実行されると競合が発生する可能性がある。
- データストアとデータアクセス層への負荷、クエリの複雑さによって、パフォーマンスに悪影響が出る可能性がある。
- 読み取りと書き込みが同じデータに行われるため、アクセス許可の管理が複雑になる。
参考: CQRSパターン - Azure Architecture Center
What is CQRS?
「更新」を行う「コマンド」と、データを「参照」する「クエリ」に、異なるモデルを使うアーキテクチャ。
アクションを実行する「コマンド」と、データを呼び出し元に戻す「クエリ」をメソッドとして分離するという、 CQS(Command Query Separation)の考えを、アーキテクチャに持ち込んだもの。
CQRSのメリット - スケーリング - 読み取り、書き込みそれぞれを個別にスケーリングできる。
パフォーマンス
- 読み取り側はクエリ用に最適化できる。
セキュリティ
- 適切なエンティティのみが、書き込みできる状態を維持しやすい。
関心の分離
- シンプルな読み取りの実装と、ビジネスロジックが含まれる書き込みの実装を分離でき、保守性・柔軟性を向上できる。
参考: CQRSパターン 解決策 - Azure Architecture Center
CQRSのデメリット - 複雑さ - イベントソーシングが含まれる場合、特に設計が複雑になりやすい。
メッセージング
- コマンド発行・イベント更新にメッセージングが使われることがある。
- その際、メッセージのエラー・重複処理が必要になる。
一貫性
- 読み取りデータが古くなる可能性がある。
- 結果整合性を採用することがある。
- サーバ側から更新のメッセージをUIに送り、リアルタイム更新する(WebSocket等)
- UIに、最終更新日時を表示する。
- UI上で擬似的に表示を更新する。
参考: CQRSパターン 実装に関する問題と注意事項 - Azure Architecture Center
Event-Driven Architecture (EDA)
- イベントを受け取り、受け取ったイベントに応じて反応するアーキテクチャ。
- システム間の結合を切り離せる。
パイプ & フィルター方式
cat phone_numbers.txt | grep 303 | wc -l
上記のLinuxコマンドのパイプ・フィルターのように、イベントを送信->イベント受信->処理実行->イベント送信という流れを、システム間のやりとりとして表現する方式。
業務プロセスにおけるアクティビティの発生をモデリングしたものになる。
サーガ(長期プロセス)方式
パイプ&フィルターを拡張したもの。複数の処理を分散して処理したい場合に利用。
長期プロセスの設計方法
実行者コンポーネントに、各タスクをトレースさせる。
パートナーアクティビティ という方法。Pat Hellandが推奨。
イベントを運メッセージに、プロセスの状態を保持させ、プロセスはステートレスとなるように設計する。メッセージを受け取るハンドラが、受け取ったイベントに情報を付与して、次のメッセージとして送出する。
イベントソーシング方式
- 履歴管理に利用可能。
- Gitのように、過去の状態を復元するような概念に類似
- 発生したすべてのイベントを、イベントストアに格納。
データファブリック / グリッドベース分散コンピューティング
参考
「実践ドメイン駆動設計」から学ぶDDDの実装入門 (WINGSプロジェクト 青木淳夫 著)
以上
【読書メモ】実践ドメイン駆動設計 ~第3章~ 「コンテキストマップ」
復習
目次
1. Why コンテキストマップ?
マップを書く主たる理由は、解決空間の全体像を見れるようにすること。
コンテキストマップは、現状を姿を捉えるためのもの。理想・期待する姿を書くわけではない。
シンプルかつアジャイルに進める。
コンテキストマップは組織の動きを示す。
2. コンテキストマップと組織パターン/結合パターン
組織パターン
パートナーシップ
成功/失敗の運命をともにする関係がある。インターフェース部分も共に検討して前に進める。
別々の道
協力体制なく、統合しない。
顧客/供給者の開発
上流・下流の関係。
順応者
上流・下流の関係だが、上流側が下流の要求に応えようとしない。
結合パターン
共有カーネル
明示的な境界を定め、共有部分を合意する。ソースコードレベルで共有。
公開ホストサービス (Open Host Service)
サブシステムへのアクセスのためのプロトコルを公開。RESTが主流。
公表された言語 (Published Language)
明確にドキュメント化された共有言語を利用。JSONやXMLを利用。
腐敗防止層 (Anti-Corruption Layer)
パートナーシップ、顧客/供給者といった関係を築けなかった際に、上流システムの機能を、独自のドメインモデルで表現するためのレイヤ。
巨大な泥団子
大規模でモデルも混在している。他のコンテキストに影響をださないように注意。
参考
【読書メモ】実践ドメイン駆動設計 ~第2章~ 「ドメイン、サブドメイン、境界づけられたコンテキスト」
1. ドメイン・サブドメイン・境界づけられたコンテキストについて
- コアドメイン ・・・サブドメインの一つで、事業・組織を成功に導くために重要不可欠なもの。
- 支援サブドメイン ・・・業務には不可欠だがコアドメインとは言えないもの。
- 汎用サブドメイン ・・・特別なことをしていなくても、業務全体として必要なもの。
2. 問題空間と解決空間
- 問題空間 ・・・解決すべきビジネス上の課題
- 解決空間 ・・・ソフトウェアをどう実装して課題を解決するか
解決空間 = 境界づけられたコンテキスト
それぞれのサブドメインに、境界づけられたコンテキストが、1対1で対応するのが望ましいゴール。
3. 境界づけられたコンテキストの意味
- 境界づけられたコンテキストとは、ドメインモデルがどこに属すのかを表すもの。
- コンテキストによって、モデルの概念・操作・プロパティは変わってくるので、明示的に境界を引く。
- 境界づけられたコンテキストにより、ユビキタス言語・ドメインモデルをカプセル化することが主目的。
境界づけられたコンテキストとは異なるもの
のような技術的な境界。
- 開発要因へのタスク割り当て
- 開発要因の管理のしやすさ
というような偽の境界。
参考
「実践ドメイン駆動設計」から学ぶDDDの実装入門 (WINGSプロジェクト 青木淳夫 著)
以上
【読書メモ】実践ドメイン駆動設計 ~第1章~「DDDへの誘い」
1. Why DDD?
- ドメインエキスパートと開発者を一つのまとまったチームにする。
- チーム全体が理解できる共通言語に基づいて開発を進められる。
- 設計がコードであり、コードが設計でもある。
- 戦略設計と戦術的設計の両面で、健全なソフトウェア開発を支える。
目指すは、事業価値をもたらすソフトウェア開発
事業価値をもたらさない、ソフトウェア開発とは?
2. どんな時にDDDを使うのか?
3. どのようにDDDを使うのか?
ユビキタス言語を作ることが第一歩。
ユビキタス言語 == ドメインエキスパート・ソフトウェア開発者を含めたチームで作り上げる共通言語
どのようにユビキタス言語を作っていくか。
- ドメインについて図示し、名前とアクションをつける。
- 定義をまとめた用語集、もしくは概念に関するスケッチなどのドキュメントを作る。
- 作成した用語・フレーズをレビューしてもらう。
point1. ユビキタス言語・コードは変化するもの。
- ドキュメントをつくって終わりではない。
- コード内のモデル・チーム内での会話が、最もユビキタス言語の現状を表す。
最初に作ったドキュメントを常に最新の状態に更新するのは非現実的。 いつでも捨てられるようにと考える。
point2. ユビキタス != ユニバーサル
ユビキタスは、業界全体・世界中で、という意味ではない。 境界づけられたコンテキストごとに、ユビキタス言語が存在する。