c#実装から見るddd(ドメイン駆動設計)
DESCRIPTION
わんくま同盟勉強会@大阪#60でお話しさせて頂きました。 『C#実装から見るDDD(ドメイン駆動設計)』を多少手直しをして、再掲載しました。TRANSCRIPT
![Page 1: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/1.jpg)
わんくま同盟 大阪勉強会 #60
C#実装から見る
DDD(ドメイン駆動設計)Ver2.0 (ちょっと追記版)
By @kawakawa
![Page 2: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/2.jpg)
わんくま同盟 大阪勉強会 #60
はじめに
みなさん、
DDDをご存じでしょうか?
![Page 3: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/3.jpg)
わんくま同盟 大阪勉強会 #60
はじめに
DDDとは、2011年に日本で出版された「ドメイン駆動設計」の事です。
![Page 4: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/4.jpg)
わんくま同盟 大阪勉強会 #60
はじめに
DDDは書籍以外にも、ネット上に多数の資料があり、目にされた方も多いかと思います。
![Page 5: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/5.jpg)
わんくま同盟 大阪勉強会 #60
はじめに
しかし、DDDは理屈の理解はできても、
実践するのは、難しいと思います。
まず、
顧客(ドメインエキスパート)が要ります。
仲間(開発チーム)が要ります。
プログラム知識が要ります。
・・・・
![Page 6: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/6.jpg)
わんくま同盟 大阪勉強会 #60
はじめに
本日は、DDDをプログラム実装という
観点から見てみることで、
DDDを知らない人には、興味のキッカケを、
DDDの実装をしらない人には、一例を提示できればと思いました。
それではみなさん、よろしくお願いします。
![Page 7: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/7.jpg)
わんくま同盟 大阪勉強会 #60
自己紹介
• かわべ たくや
• Twitter:@kawakawa
• 大阪で働いています
• I Love C#!
• DDD勉強中!
![Page 8: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/8.jpg)
わんくま同盟 大阪勉強会 #60
はじめに
DDDを知らなくても、困らないような資料にしたつもりですが、やっぱり知らないより、知っていたほうが楽しいので、簡単にDDD
を説明させて頂きます。
![Page 9: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/9.jpg)
わんくま同盟 大阪勉強会 #60
DDD知らない方向け
「DDDとは?」 (独断と偏見で説明)
![Page 10: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/10.jpg)
わんくま同盟 大阪勉強会 #60
DDDとは?
• DDDとは、「Domain-Driven-Design」
• 訳すと、「ドメイン駆動設計」
• よく目にする、●DD「●-Driven-
Development」は、「●駆動“開発”」 であり、「●駆動“設計”」と異なります。
![Page 11: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/11.jpg)
わんくま同盟 大阪勉強会 #60
DDDとは?
• ドメインとは、「領域」の意味。
(顧客のお仕事=「業務領域」であり、これも 1つのドメインです)
• ドメインから問題・関心ごとを抜き出したのが「(ドメイン)モデル」。
• プログラマのお仕事は、この「モデル」をプログラムで実装することです。
![Page 12: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/12.jpg)
わんくま同盟 大阪勉強会 #60
DDDとは?
• 開発は、モデルを「分析」「設計」「実装」のサイクルをグルグル回します。
(モデル駆動開発と呼ばれてます)
• ドメイン駆動“設計”とは、そのグルグル回すことを如何に継続させるか設計することです。
![Page 13: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/13.jpg)
わんくま同盟 大阪勉強会 #60
DDDとは?
• よくある勘違いとしては、DDD本自体にモデルの答えは書いていません。(モデリングの本ではないです)
• モデリングを継続させる方法を考える本です。
(魚をくれるのではなく、釣り方を教えてくれる本)
![Page 14: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/14.jpg)
わんくま同盟 大阪勉強会 #60
DDDを行う意義とは?
![Page 15: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/15.jpg)
わんくま同盟 大阪勉強会 #60
DDDの意義
私が思うDDDの意義は、
・DDD本を読むまで
「動くアプリが正義!」
・DDD本を読んだ後
「動き続けるアプリが正義!」
アプリへの認識が変わりました。 (※動く=顧客の問題を解決すると読み替えてもOK)
(※動く≒顧客の問題を解決する)
![Page 16: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/16.jpg)
わんくま同盟 大阪勉強会 #60
DDDの意義
動き続けるとは?
• 業務システムで考えると、納品は、開発の終わりではありません。納品してからも開発は続きます。
(有償・無償は問わず)
• 顧客から要望は色々出てきます。
「より見やすい画面が欲しい」
「より操作しやすくして欲しい」
• 顧客の業務形態に変化が生ずれば、仕様変更です。
![Page 17: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/17.jpg)
わんくま同盟 大阪勉強会 #60
DDDの意義
つまり、動き続けるとは、
変化し続けるという事。
どこまで、仕様変更に追随できますか?
![Page 18: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/18.jpg)
わんくま同盟 大阪勉強会 #60
DDDの意義
つまり、動き続けるとは、
変化し続けるという事。
どこまで、仕様変更に追随できますか?
※勿論、業務形態が根本的に変化したのなら、追随は無理です。 (不動産屋が八百屋にジョブチェンジなど)
![Page 19: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/19.jpg)
わんくま同盟 大阪勉強会 #60
DDDの意義
また、DDDに向かない場合もあります。
• ドメインが薄い
(DDD行うほうが労力かかります)
• アプリの使用期間が短い
(一度きりで再利用しない場合。デモアプリなど)
![Page 20: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/20.jpg)
わんくま同盟 大阪勉強会 #60
DDDの面白い所
![Page 21: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/21.jpg)
わんくま同盟 大阪勉強会 #60
DDDの面白い所
DDDでは、モデルは実装されて初めて意味を成すと考えられています。
つまり、図やUMLがモデルではなく、動くソフトウェアまで含めて、モデルと考えられています。
![Page 22: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/22.jpg)
わんくま同盟 大阪勉強会 #60
DDDの面白い所
プログラミングにおいて大抵は、実装上の制約(性能や品質等々)により、設計図通りに実装出来ないものですが、そう言った点も含めて、絵にかいた餅ではなく、動くモデルに注力しているのが、非常に現実的で、DDDは面白い思想だと思いました。
![Page 23: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/23.jpg)
わんくま同盟 大阪勉強会 #60
それでは、DDDの実装を見てみましょう
![Page 24: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/24.jpg)
わんくま同盟 大阪勉強会 #60
とその前に・・・
いきなりですが、DDDは実装も大事ですが、実装以外の項目も大事です。
• 顧客(ドメインエキスパート)とのコミュニケーション
• コンテンツマップ作成
• ユビキタス言語の発見
• 開発チームづくり ・・・などなど。
残念ながら、実装だけ見ても“DDD”はできません…。
![Page 25: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/25.jpg)
わんくま同盟 大阪勉強会 #60
DDD実装のサンプル元
• 実装サンプルは、DDD本:著者エヴァンスも関わった「DDD
Sample」使います。
• http://dddsample.sourceforge.net/
• DDD本にはそこまで詳しく触れられていなかった、DDDの実装方法が詰まっていて大変参考になります。
![Page 26: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/26.jpg)
わんくま同盟 大阪勉強会 #60
DDD実装のサンプル元
• 注意点としては、DDDSampleはDDD本を読んでいる事を前提されています。
• 内容は、DDD本に何度も出てくる、貨物輸送プログラムです。
• HPにクラス設計図等の説明が無いので、本を読まないと、「これは何クラス?」という状況に陥ります。
![Page 27: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/27.jpg)
わんくま同盟 大阪勉強会 #60
実装例一覧
本日提示させて頂く、実装例は、
• レイヤ化アーキテクチャ (少しだけ責務のレイヤも)
• 値オブジェクト
• エンティティ
• リポジトリ
![Page 28: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/28.jpg)
わんくま同盟 大阪勉強会 #60
レイヤ化アーキテクチャ
![Page 29: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/29.jpg)
わんくま同盟 大阪勉強会 #60
レイヤ化アーキテクチャ
ソフトウェアの世界には、レイヤという便利な考え方があります。
有名なレイヤーといえば、MVC(Model View
Controller)ですよね。
一番不安定なView層から、Model層を直接参照・編集できないように切り離すことで、Model
層が安定します。 (MVCが指すModelとDDDのモデルは微妙に異なります)
![Page 30: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/30.jpg)
わんくま同盟 大阪勉強会 #60
レイヤ化アーキテクチャ
DDDのレイヤ化アーキテクチャも考え方は、同じです。
(ドメイン)モデルを様々な事象から可能な限り切り離すことで、モデルの安定化を目指します。
![Page 31: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/31.jpg)
わんくま同盟 大阪勉強会 #60
レイヤ化アーキテクチャ
DDD本「第4章ドメインを隔離する」から抜粋
基本的に、上のレイヤは下位レイヤーを参照できるが、
逆に下から上へは参照できない構造。
![Page 32: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/32.jpg)
わんくま同盟 大阪勉強会 #60
レイヤ化アーキテクチャ
ユーザインタフェース(またはプレゼンテーション層) • ユーザに情報を表示して、ユーザのコマンドを解釈する責務を負う。
• 外部アクタは人間のユーザではなく、別のコンピュータシステムのこともある。
![Page 33: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/33.jpg)
わんくま同盟 大阪勉強会 #60
レイヤ化アーキテクチャ
アプリケーション層 • ソフトウェアが行うことになっている仕事を定義し、表現力豊かなドメインオブジェクトが問題を解決するように導く。
• このレイヤが責務を負う作業は、ビジネスにとって意味があるものか、あるいは他システムのアプリケーション層と相互作用するのに必要なものである。このレイヤは薄く保たれる。
![Page 34: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/34.jpg)
わんくま同盟 大阪勉強会 #60
レイヤ化アーキテクチャ
ドメイン層(またはモデル層) • ビジネスの概念と、ビジネスが置かれた状況に関する情報、およびビジネスルールを表す責務を負う。
• ビジネスの状況を反映する状態はここで制御され使用されるが、それを格納するという技術的な詳細は、インフラストラクチャに委譲される。この層がビジネスソフトウェアの核心である。
![Page 35: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/35.jpg)
わんくま同盟 大阪勉強会 #60
レイヤ化アーキテクチャ
インフラストラクチャ層 • 上位のレイヤを支える一般的な技術的機能を提供する。これには、アプリケーションのためのメッセージ送信、ドメインのための永続化、ユーザインタフェースのためのウィジェット描画などがある。
• インフラストラクチャ層は、ここで示す4 層間における相互作用のパターンも、アーキテクチャフレームワークを通じてサポートすることがある。
• 個人的感想としては、ここは「ごった煮」層。
![Page 36: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/36.jpg)
わんくま同盟 大阪勉強会 #60
レイヤ化アーキテクチャ
それでは、早速実装をみてみましょう。
![Page 37: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/37.jpg)
わんくま同盟 大阪勉強会 #60
レイヤ化アーキテクチャ
名前空間(フォルダ分け)などを使って、レイヤ分類を実装していました。
MVCもフォルダで分けたりするので、同じですね。
DDDSampleでは他にもフォ
ルダがありますが、ここでは解りやすくする為、省いています。
![Page 38: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/38.jpg)
わんくま同盟 大阪勉強会 #60
レイヤ化アーキテクチャ
レイヤ化自体は、フォルダ(名前空間)分けという単純な方法でした。
しかし、MVC同様にどのオブジェクトはどのフォルダに格納すべきか、よく考える必要があります。
![Page 39: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/39.jpg)
わんくま同盟 大阪勉強会 #60
少しだけ、
責務のレイヤ
![Page 40: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/40.jpg)
わんくま同盟 大阪勉強会 #60
責務のレイヤ
• DDDSampleには直接記されていないのですが、DDDには、「責務のレイヤ」というレイヤ概念があります。
• モデル層内部をより細かく分類して、不安定箇所(仕様変更が多発する箇所)を切り離します。
![Page 41: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/41.jpg)
わんくま同盟 大阪勉強会 #60
責務のレイヤ
第16章 大規模な構造「責務のレイヤ」より
![Page 42: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/42.jpg)
わんくま同盟 大阪勉強会 #60
責務のレイヤ
• 責務のレイヤは、開発に非常に有効な手段と思います。
• しかし、責務のレイヤを実装するには、顧客(ドメインエキスパート)の知識が必要となり、上流設計で行う作業やスキルが必要となります。
・業務知識の習得
・業務の見える化 ・・・色々
やはり、一筋縄ではいかなそうです。
![Page 43: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/43.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
![Page 44: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/44.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
• DDDでは、如何にモデルをシンプルに保つかが、大切な考えになります。
• オブジェクトに、責務以上の機能、余計なデータを持たせない事に、注意を払います。
![Page 45: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/45.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
• 値オブジェクトは、“属性情報”だけを持ちます。
• 属性情報とは、「色」や「大きさ」など、
対象の性質を表したものです。
![Page 46: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/46.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
そして、値オブジェクトは次のルールが適応されます。
• 同一性(アイデンティティ)を持たない。
• 不変(immutable)である。 (属性に変更が必要になった場合、属性を変更するのではなく、
新しい属性を持った値オブジェクトを作成する)
![Page 47: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/47.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
DDDSampleのLeg(行程)をサンプルにして、実装をみてます。
Legは船の貨物の「積み込む地点」と、「荷下ろし地点」を保持します。
※ 単純化の為、DDDSampleから改変(省略)しています
![Page 48: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/48.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
//値オブジェクト用インターフェース
public interface IValueObject<T>
{
//属性が同じかチェック
bool SameValueAs(T other);
}
最初に、値オブジェクト用のインターフェースを用意。
![Page 49: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/49.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
//Leg(行程)の値オブジェクト実装
public class Leg : IValueObject<Leg>
{
public Location LoadLocation { get; private set; } //荷積み地点
private Location UnloadLocation { get; private set; } //荷下ろし地点
public Leg(Location loadLocation, Location unloadLocation)
{
this.LoadLocation = loadLocation;
this.UnloadLocation = unloadLocation;
}
public bool SameValueAs(Leg other)
{
if (this.LoadLocation != other.LoadLocation) return false;
if (this.UnloadLocation != other.UnloadLocation) return false;
return true;
}
} ※ 解りやすくする為に、DDDSampleから改変しています。
![Page 50: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/50.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
• Leg(行程)サンプルの特徴は、属性として、
・ LoadLocation(荷積み地点)
・ UnloadLocation(荷下ろし地点)
を持ち、コンストラクタ以外に、属性を変更する
手段を持ちません。
• このLeg(行程)だけみると、値オブジェクトと言っても、特別なことは無いように見えますね。
![Page 51: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/51.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
その2
![Page 52: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/52.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
• 次は、Leg(行程)をリストとして保持する、Itinerary
(運送スケジュール)オブジェクトを考えてみます。
• Itineraryは、Cargo(貨物)(後述するエンティティ)のLegをまとめたもので、Legリスト最初が出発点、最後が到着点(目的地)となります。
![Page 53: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/53.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
このItinerary(運送スケジュール)を値オブジェクトと考えた場合、不変性をどう考えればよいでしょうか?
リストとして保持しているLeg(行程)に、1つでも変更が生じた場合、Cargo(貨物)は、Itinerary
(運送スケジュール)を破棄して、都度、新しいインスタンスを用意しないといけないのでしょうか?
![Page 54: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/54.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
DDD本の第16章『大規模な構造』の「責務のレイヤ」に、次のように書かれています。
ソフトウェアにおけるこのレイヤは、計画作成と意思決定に用いるツールをユーザに提供し、潜在的には一部の意思決定を自動化できる
(運送スケジュールが変更になった時、自動的に貨物の経路を選択し直すなど)
つまり、意思決定支援レイヤの責務として、変更対応すればよいそうです。(うーん難しい!)
![Page 55: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/55.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
個人的解釈としては、
• 運送スケジュール変更というのは、Cargo(貨物)自体の責務ではない。
• スケジュール変更は、より上位の意思に寄るものである。(例:貨物運送担当者など)
• その為、 RoutingService(経路選択サービス)を用
意し、スケジュール変更に伴う実装的負担を引き受けることで、各オブジェクト構造をシンプルに保てる(余計な仕事をさせなくて済む)
![Page 56: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/56.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
• まずは、Itinerary(運送スケジュール)の実装をみてみましょう。
![Page 57: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/57.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
// Itinerary(運送スケジュール)オブジェクト
public class Itinerary : IValueObject<Itinerary>
{
private List<Leg> legs = null;
public Itinerary(List<Leg> legs)
{
this.legs = legs;
}
}
※ 解りやすくする為に、DDDSampleから改変しています。
![Page 58: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/58.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
Itinerary(運送スケジュール)は、単純にLeg(行程)をリストで保持しているだけですね。
次は、Cargo(貨物)とRoutingService(経路選択サービス)です。
![Page 59: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/59.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
// Cargo(貨物) (後ページのエンティティ時にも記載)
public class Cargo:IEntity
{
~省略~
//運送スケジュール
private Itinerary itinerary;
//運送スケジュール変更
public void AssignToRoute(Itinerary itinerary)
{
this.itinerary = itinerary;
}
}
※ 解りやすくする為に、DDDSampleから改変しています。
![Page 60: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/60.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
// Itinerary(運送スケジュール)を新しく作るサービスを用意
public class RoutingService
{
public List<Itinerary> fetchRoutesForSpecification(Cargo cargo)
{
//新しいltinerary(運送スケジュール)割り当て
cargo.assignToRoute(toItinerary());
}
//条件に従い、新しい運送スケジュール作成
private Itinerary toItinerary() {
~省略~
return new Itinerary(legs);
}
}
※ 解りやすくする為に、DDDSampleから改変しています。
![Page 61: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/61.jpg)
わんくま同盟 大阪勉強会 #60
値オブジェクト
DDDSampleにおける実際のRoutingService
(経路選択サービス)はもっと複雑です。
ただ、DDD的意図を読み取ると、経路変更の仕事を、経路情報を持つCargo(貨物)に行わせるのではなく、Serviceとして外部に出したことにより、Carg(貨物)がシンプルに保たれている事に、意義があるのと考えています。
![Page 62: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/62.jpg)
わんくま同盟 大阪勉強会 #60
エンティティ
![Page 63: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/63.jpg)
わんくま同盟 大阪勉強会 #60
エンティティ
• エンティティは値オブジェクトと異なり、同一性(アイデンティティ)を持ちます。
• 同一性は、モデルのライフサイクル期間中保たれます。
• 同一性は、エンティティをDB格納して、取り出した後でも、保たれます。
エンティティ
モデルのライフライン
DB エンティティ
同じアイデンティティ
![Page 64: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/64.jpg)
わんくま同盟 大阪勉強会 #60
エンティティ
• cargo(貨物)をサンプルに、エンティティの実装を見てみます。
• cargo(貨物)は、TrackingId(追跡ID)をアイデンティティとして、同一性を持ちます。
• TrackingId(追跡ID)は、作成時に割り当てられた後、変更されることはありません。
![Page 65: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/65.jpg)
わんくま同盟 大阪勉強会 #60
エンティティ
// エンティティ用インターフェース
interface IEntity<T>
{
//同一エンティティかチェック
bool sameIdentityAs(T other);
}
• まずはエンティティ用のインターフェース
![Page 66: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/66.jpg)
わんくま同盟 大阪勉強会 #60
エンティティ
//cargo(貨物)
public class Cargo:IEntity<Cargo>
{
private readonly TrackingId trackingId;
public Cargo(TrackingId trackingId) {
this.trackingId = trackingId;
}
public bool SameIdentityAs(Cargo other)
{
return other != null && trackingId.sameValueAs(other.trackingId);
}
} ※ 解りやすくする為に、DDDSampleから改変しています。
![Page 67: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/67.jpg)
わんくま同盟 大阪勉強会 #60
エンティティ
• アイデンティティであるtrackingId(追跡ID)をreadonlyにすることで、設定後の不意な変更を防止しています。
• それ以外は特段特徴のない、普通のクラスですね。
![Page 68: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/68.jpg)
わんくま同盟 大阪勉強会 #60
エンティティ
• 次に、そのアイデンティティとして使用されている TrackingId(追跡ID)の実装を見てみます。
![Page 69: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/69.jpg)
わんくま同盟 大阪勉強会 #60
エンティティ
// TrackingId(追跡ID)
public sealed class TrackingId : IValueObject<TrackingId>
{
private readonly String id;
public TrackingId(String id) {
this.id = id;
}
public override bool Equals(object o) {
if (this == o) return true;
if (o == null) return false;
TrackingId other = (TrackingId)o;
return SameValueAs(other);
}
public bool SameValueAs(TrackingId other) {
return other != null && this.id.Equals(other.id);
}
} ※ 解りやすくする為に、DDDSampleから改変しています。
![Page 70: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/70.jpg)
わんくま同盟 大阪勉強会 #60
エンティティ
• 驚いた事に、 TrackingId(追跡ID)は値オブジェクトです。
• Cargo(貨物)は、エンティティですが、そのアイデンティティとして、値オブジェクトであるTrackingId(追跡ID)を使用しています。
![Page 71: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/71.jpg)
わんくま同盟 大阪勉強会 #60
エンティティ
これらの事から、何が値オブジェクトで、エンティティなのか、深く考える必要があることが伺えます。 (エンティティのアイデンティティも、普通ならエンティティになると普通思うと思います)
個人的には、容易にオブジェクトをエンティティとしないという、強い意志を感じました。
![Page 72: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/72.jpg)
わんくま同盟 大阪勉強会 #60
Factories と Repositories
![Page 73: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/73.jpg)
わんくま同盟 大阪勉強会 #60
Factories と Repositories
• エンティティの実装例で見た通り、同一性の確保は、プログラムの実装に依存します。 (例では、追跡IDのユニーク性確保など)
• このように、新しくオブジェクトをnew(インスタンス化)したいときに、特定条件(今回は追跡ID採番)を実行したい事は多々あります。
![Page 74: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/74.jpg)
わんくま同盟 大阪勉強会 #60
Factories と Repositories
• そこで、オブジェクトの生成、並びにDBへの格納・取り出しなど、オブジェクト化するのに必要な処理をまとめたのが、「Factories(ファクトリ)」と「Repositories(リポジトリ)」です。
![Page 75: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/75.jpg)
わんくま同盟 大阪勉強会 #60
Factories と Repositories
• 「Factories」がオブジェクト生成時に使用。
• 「Repositories」は、DB格納や取り出しなど、オブジェクトを使いまわす時に使用します。
![Page 76: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/76.jpg)
わんくま同盟 大阪勉強会 #60
Factories と Repositories
• cargo(貨物)を格納するCargoRepositoryの実装例は次のようになります。
![Page 77: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/77.jpg)
わんくま同盟 大阪勉強会 #60
Factories と Repositories
//貨物リポジトリ
interface ICargoRepository
{
//指定、追跡IDに該当するcargo取得
Cargo find(TrackingId trackingId);
//全cargoを取得
List<Cargo> findAll();
//DBに格納します
void store(Cargo cargo);
//DBなどのシーケンスを使い、ユニークなIDを発番させます。
TrackingId nextTrackingId();
}
![Page 78: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/78.jpg)
わんくま同盟 大阪勉強会 #60
Factories と Repositories
• ICargoRepositoryインターフェースを実装することで、O/Rマッパで実装するとDBに結びつけたり、ファイル操作で実装すると、Textファイルとして保存させたり、することができます。
• 次ページはDBで実装した時の例です。
![Page 79: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/79.jpg)
わんくま同盟 大阪勉強会 #60
Factories と Repositories
//貨物リポジトリ(DB)
public class CargoRepositoryDb
{
private DAO dao=null;
//指定、追跡IDに該当するcargo取得
public Cargo find(TrackingId tid) {
dao.createQuery("from Cargo where trackingId = :tid"); //SQL
dao.setParameter("tid", tid);
return dao.result();
}
//全cargoを取得
public List<Cargo> findAll() {
dao.createQuery("from Cargo "); //SQL
return dao.result();
}
(続く) ※ 解りやすくする為に、DDDSampleから改変しています。
![Page 80: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/80.jpg)
わんくま同盟 大阪勉強会 #60
Factories と Repositories
(続き)
// DBに格納します
public void store(Cargo cargo){
dao.saveOrUpdate(cargo);
dao.createSQLQuery("delete from Leg where cargoId =null").executeUpdate();
}
// ユニークなIDを発番
public TrackingId nextTrackingId() {
var randomId= dao.GetRoundomUID();
return new TrackingId(randomId);
}
}
※ 解りやすくする為に、DDDSampleから改変しています。
![Page 81: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/81.jpg)
わんくま同盟 大阪勉強会 #60
Factories と Repositories
Factoriesの実装例は載せておりませんが、Repositoriesとほぼ同じような実装内容になります。
そうなってくると、FactoriesとRepositoriesをまとめても良さそうに思いますよね?
![Page 82: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/82.jpg)
わんくま同盟 大阪勉強会 #60
Factories と Repositories
しかし、DDD本では、次の理由でFactoriesとRepositoriesの役割を分離させてます。
• Factoriesは、新しいオブジェクトを生成する責務。
• Repositoriesは、既存オブジェクトを再構成する責務。
• 分離させることで、FactoriesをDB(永続)化する処理から分離できる。
![Page 83: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/83.jpg)
わんくま同盟 大阪勉強会 #60
まとめ
![Page 84: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/84.jpg)
わんくま同盟 大阪勉強会 #60
まとめ
簡単な実装例だけでしたが、
• レイヤ化アーキテクチャ
• 値オブジェクト
• エンティティ
• Repositories
DDDの中核をなす、実装例を見て頂きました。
![Page 85: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/85.jpg)
わんくま同盟 大阪勉強会 #60
まとめ
他にもDDDSampleでは、
• 集約(Aggregate)
• ドメインイベント
• Service
• 仕様(SPECIFICATION)
などの実装例が紹介をされています。
(しかし、これらはDDDを知らないと、判りづらいかもしれません)
![Page 86: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/86.jpg)
わんくま同盟 大阪勉強会 #60
書籍紹介
次に、DDD実装で参考になる書籍を簡単に紹介させていただきたいと思います。
![Page 87: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/87.jpg)
わんくま同盟 大阪勉強会 #60
書籍紹介
ドメイン駆動 ■amazon
http://www.amazon.co.jp/dp/4798116173
■書籍紹介
C#を使った、ドメイン駆動設計をパターンを使って実装していく実践本です。
まさに、C#er向けの一冊。
C#2.0と若干古いのですが、サンプルソースは参考になります。
SQLServerと如何に連携させるか、
テスト駆動開発でいかに進めるかなど、
てんこ盛りな内容です。(少々詰め込み過ぎ?)
![Page 88: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/88.jpg)
わんくま同盟 大阪勉強会 #60
書籍紹介
Implementing Domain-Driven Design ■amazon
http://amzn.com/0321834577
■書籍紹介
英語本ですが、IDDDというキーワードでよく見かける、DDD実践本です。
DDD本の後に出版された、如何にDDDを実践していくかを主眼に書かれている本で、DDD本には収録さ
れていなかったドメインイベントも記載されているようです。
DDD本に劣らない分厚さを誇ります(汗。
私は当然、英語苦手なので未読です(汗汗
IDDDのワークショップを世界的に行うコミュニティがあるようです。(http://idddworkshop.com/)
![Page 89: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/89.jpg)
わんくま同盟 大阪勉強会 #60
まとめ
最初にも書かさせて頂きましたが、DDDにおける実装が占める役割は、ほんの一部です。
実装に至るまでの過程がもの凄く重要だと思います。
また、実装例として挙げたものより、状況によって、より適切な実装方法は、数多くあると思います。
![Page 90: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/90.jpg)
わんくま同盟 大阪勉強会 #60
まとめ
今回は、実装という方面からDDDを眺めてみましたが、DDDを知らなかった方に、少しでも興味を持って頂けたのなら幸です。
DDDの実装については、私も勉強中です。
もし気になる点などありましたら、是非お声かけ下さい。<(_ _)>ペコリ
![Page 91: C#実装から見るDDD(ドメイン駆動設計)](https://reader035.vdocuments.net/reader035/viewer/2022081401/556607a4d8b42a06318b45a3/html5/thumbnails/91.jpg)
わんくま同盟 大阪勉強会 #60
まとめ
以上、ご清聴ありがとうございました。