purucat’s blog

寿司よ止まれっ!

"「実践ドメイン駆動設計」から学ぶDDDの実装入門" 10 章感想 (全14章)

"「実践ドメイン駆動設計」から学ぶDDDの実装入門"

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

のレビューをこまめに記載していく


「集約」〜トランザクション整合性を保つ境界〜

memo

  • 集約(Aggregates)とはオブジェクトのまとまりであり、即時に整合性を保ちながらデータを更新する単位。オブジェクトの集まりの「境界線」の意味で使われる。
    • 外部からは集約ルートとなるエンティティを介してのみ操作可能。(操作をしない外部からの参照だけなら、他の集約からの参照は許可。)
    • 5つルールと4つの例外がある
  • 楽観的並行性制御(optimistic concurrency control)データ取得時時点で一意に識別できる値と更新時点での値の差の有無で更新を制御 <-> pessimistic concurrency controlロックを取って並列更新を制御
  • 大きすぎる集約はトランザクションの衝突が多くなるため、小さな集約として切り出す。他の集約を参照するにはその集約ルートの一意な識別子のみを参照する。
  • Global Transaction (::= Distributed Transaction)の実現手法として2 phase commitがある。
  • デメテルの法則 (Law of Demeter, LoD) または最小知識の原則 (Principle of Least Knowledge)で保守性の向上。 ref. https://ameblo.jp/principia-ca/entry-11876117369.html
  • Tell-Don't-Ask (ref. https://martinfowler.com/bliki/TellDontAsk.html) Askしないことで、振る舞いが対象オブジェクトに移動するのを推奨する。
  • Disconnected Domain Model::= AggregatesからRepositoryを用いて他のAggregatesを読み出す。これよりは Domain Serviceで実現のほうが良い。

分からないこと

  • 次の2つのルールは、変更管理を容易にするための方針なのだろうか?

"「実践ドメイン駆動設計」から学ぶDDDの実装入門" 9 章感想 (全14章)

"「実践ドメイン駆動設計」から学ぶDDDの実装入門"

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

のレビューをこまめに記載していく


「モジュール」〜高凝集で疎結合にまとめる〜

つまり 閉鎖性共通の原則(Common Closure Principle).

memo

  • IDDDの「モジュール」はJavaではパッケージに相当。依存関係や概念が同じものを一つのモジュールとしてまとめることで、モジュール間は疎結合となる
    • モジュールは別のモジュールに依存しないようにするべき。
      • 意味的にモジュールあいだに双方向の依存がある場合でも、実装は単一方向の依存とするべき
  • プロダクト名でパッケージをつけるよりは、ユビキタス言語である「境界づけられたコンテキスト」でパッケージを命名するほうが、プロダクト名の変更の影響を受けなくてすむ。

分からないこと

  • domainportというDDDの大きな枠組み配下にクラスは存在させないようだ。これはIDDDのルールなのか?
例:
jp.company.<context-A>.domain       // <- domain配下にクラスは存在させない。これはIDDDのルールなのか?
jp.company.<context-A>.domain.model
jp.company.<context-B>.domain
jp.company.<context-B>.domain.model.{value-obj,entity,domain-service,domain-event,repository,aggregates}

"「実践ドメイン駆動設計」から学ぶDDDの実装入門" 8 章感想 (全14章)

"「実践ドメイン駆動設計」から学ぶDDDの実装入門"

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

のレビューをこまめに記載していく


ドメインイベント」〜出来事を記録して活用〜

気になった所

  • イベントpublishの前に集約というキーワードが出てきているが説明が後の章(10章)なのでわかりにくい。
  • p.102 分散トランザクションの導入は製品固有の知識が必要ないため<=むしろ必要では。多分書き間違え。

学んだ事

  • ドメインイベント::= ドメインモデルの一部であり、ドメイン内で発生する何かの出来事
    • モデリングには、イベント発生元のコンテキストのユビキタス言語に従う。
    • IDDDでは Pub/Sub型でドメインイベントを処理する例をあげている。 Subscriberでは次の3つの処理パターンがある。
      • 同期処理::=イベントに応じた処理をイベント発行と同一トランザクションで行う。(おそらくこれが、「軽量なオブザーバー(<ーpublisher/subscriberが同じプロセススレッドで動作し、イベント発行と同じトランザクションで処理される特徴を持つ)」。)
      • イベント格納処理::=イベントと同一トランザクションではイベントの記録だけ。
      • 分散処理::=イベントをリアルタイムで別のシステム(境界付けられたコンテキスト)に転送し、処理を行う。
    • Domain Eventに「一意な識別子」はないが、必要になる場合は導入する。(この場合、Event classはValue Objectで設計するということ?)

分からないこと

  • Domain Eventを用いると、集約の制約(単一のトランザクションでは単一の集約の塊だけを変更するという推奨ルール)から開放して結果整合性を保てる。

"「実践ドメイン駆動設計」から学ぶDDDの実装入門" 7 章感想 (全14章)

"「実践ドメイン駆動設計」から学ぶDDDの実装入門"

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

のレビューをこまめに記載していく


ドメインサービス」〜複数のものを扱うビジネスルール〜

メモ

  • DDDにおけるサービスには「アプリケーションサービス」と「ドメインサービス」の2つがある。
    • ドメインサービス::=個々のドメインオブジェクト(エンティティ、値オブジェクト、集約)の責務だけでは表現できないビジネスロジックを実装。(ドメイン層)
      • SRP(Single Responsibility Principle単一責任の原則)::=クラスを変更する理由は一つ以上存在してなならないこと。
    • アプリケーションサービス::=ドメイン以外の関心の実装をする。(ドメイン層へのクライアント側?)
  • セパレートインターフェイス::=実装クラスとは別のパッケージ(クラスではない!!)でインタフェースを定義すること。これはDIPの依存関係を表現していると思う。
    • 書籍には複数実装がなく今後実装を差し替える可能性がないなら不要とあるが DIPの実現はできない気がする、、、

Correct Diagram.

<domain package> AuthenticationService -> IEncryptionService
------------------------------------------------↑--------
                                                |
<infra package>                           MD5EncryptionService

Incorrect Diagram.(よくやりがち?)

<domain package> AuthenticationService
                     |
----------------------↓---------------------------------
<infra package>  IEncryptionService   <-   MD5EncryptionService

"「実践ドメイン駆動設計」から学ぶDDDの実装入門" 6 章感想 (全14章)

"「実践ドメイン駆動設計」から学ぶDDDの実装入門"

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

のレビューをこまめに記載していく


6章:値オブジェクト〜振る舞いを持つ不変オブジェクト〜

学んだ事

  • 値オブジェクトは6つの特徴がある

    1. 「domain内の知識を計測・定量化・説明している」
    2. 「immutable」(変更を管理する必要がない)
    3. 「概念的な統一体」である。(例:100円通貨は2つのパティ「100」と「円」で意味を持つ)
    4. 「交換可能性」:値を変更したいときは新オブジェクトで交換可(これが不便でエンティティを採用するのはだめ。エンティティは長期に渡って識別する必要があるときのみ使用!)
    5. 「等価性」:各属性すべてが同じなら等価
    6. 「副作用のない関数」:呼び出しは如何なるオブジェクトの状態も変えない
  • 他コンテクストエンティティは、粗結合にするために、値オブジェクトとして新たに用意する。

  • JPY,USD等、通貨はenumとして良く扱うが、これはValue Objectではなく、Standard TypeとVernon氏は呼んでいる。

分からないこと

  • テストを書くとき、値オブジェクトで、自分自身を引数とするコピーコンストラクタを用意する。 <=不変性のテストだろうか。イマイチ具体的例を思いつかない。

"「実践ドメイン駆動設計」から学ぶDDDの実装入門" 5章感想 (全14章)

"「実践ドメイン駆動設計」から学ぶDDDの実装入門"

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

のレビューをこまめに記載していく


5章 「エンティティ」〜 一意な識別子で同一性を識別

良い所

  • みんな何となくやっている実装を言語化してsummarizeするのに役立つかも? (例:ユースケースのシナリオでの「変更」というワードを使用する主語がエンティティ候補になる)
  • Software Designの歴史を知れる

悪い所

  • 代理識別子(システム上のキー)はGoogleのexact matchで調べる限りでは一般的ではなさそう。hibernateのドキュメントを眺めた感じだとidentifier propertiesがソースかな?まだ識別子プロパティの方が良いかも。

気になった所

  • Nothing

学んだ事

  • モデルの発展に合わせてユビキタス言語を用語集に反映。
  • DDD (Domain Driven Development) はオブジェクトモデリングを中心にシステム構築を考える。

    • DOA (Data Oriented Approach / Data Driven Approach) はデータ間の関係性(DB設計)を中心にシステム構築を考える。オブジェクトの振る舞いが欠乏してドメインモデル貧血症になりがち。だが、データ構造とプログラムは切り離されている。又、一度モデリングしたデータ構造は長期にわたって変化しにくい。
      • POA (Process Oriented Approach) は業務プロセスの流れを元にシステム構築を考える。データがプログラムに依存してしまう。(1960代 ~ 1970代の主流)
  • 自己カプセル化」::= コンストラクタで、引数のvalidation 機能を持つsetterを介して値を設定する。

Entity

EntityのPropertyのバリデーション

  • Design By Contract(契約による設計) / Programming By Contract(契約プログラミング) ::= (Bertrand Meyer氏によるオブジェクト指向入門という書籍で紹介されている考え方。原著は1990年頃発売?)
    • https://developer.hatenastaff.com/entry/2016/09/01/163542 にあるのがわかりやすい。

      関数の仕様を決める時に、関数を実行するのに何が必要か(事前条件)、そしてどういった結果を返してくれるのか(事後条件) をはっきりさせて分析することで、関数の責任や他の部分との 境界を明確にして整理することができます。さらに、契約に基づいて関数の事前条件や事後条件をコード上に表明(assertion)として表現することで、コードのまちがいに気付きやすくなり、信頼性の高いソフトウェア開発につながります。

Entityオブジェクト全体のバリデーション

  • 対応するバリデータをクラスで適切なタイミングで行う。 対応するバリデータクラスに対象Entityとinvalid時のhandlerをコンストラクタで渡してvalidateするやり方は考えたことがなかった!

複数個のEntityオブジェクト組み合わせ時のバリデーション

  • Domain serviceで制御するらしい。具体例が思いつかないが7章の解説を待とう。

分からないこと

  • Nothing

"「実践ドメイン駆動設計」から学ぶDDDの実装入門" 4章感想 (全14章)

"「実践ドメイン駆動設計」から学ぶDDDの実装入門"

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

「実践ドメイン駆動設計」から学ぶDDDの実装入門 (CodeZine Digital First)

のレビューをこまめに記載していく


良い所

(。・_・。) アーキテクチャの概要がいっぱい。スンナリ頭に入ってくれば君はアーキテクト!? 共通概念の言語化による共有という観点でココらへんの用語を適切に使えればコミュニケーションが簡便になると思われる。

悪い所

  • ESB (Enterprise Service Bus) が何なのか皆目見当がつかなかった (自分の事前知識不足)。 次のリンクをググって理解した。 https://arch.simplicable.com/arch/new/10-soa-design-patterns-every-architect-should-know の4や https://www.ibm.com/developerworks/jp/webservices/library/ws-universalports-esb/index.html 言語化すると次のようになる。
    • 2つのサービス間の接続の本数はサービス数が Nある場合は N(N-1)/2 つまりO(N2)のオーダーとなる(毛球問題)のに対応するのに導入されるサービスのことらしい。それぞれの接続が独自プロトコルを使用しているサービスならメンテナをやめようと思えてくるのは想像に固くない、、、 ESBを利用することで接続の本数をNにできる。
    • 2つのサービスを繋ぐためにプロトコル(http, iiop, etc...)変換機能を持つ。
    • 2つのサービスを繋ぐためにdata format(JSON, XML, etc..)変換機能を持つ。
  • 4.11 DDDにおけるCQRSでの流れに具体例がほぼないので一読ではよくわからない。例を上げるなら;
    • (1) GitHubにPull Requestを送るというコマンドで、はGitHub側で仮のmerge branchを作成したり自動でreviewerをアサインする仕組みがあればそれを実行する。
    • (2) Webhookが登録されていればPull Requestという「ドメインイベント」を発行してJenkinsなどに通知
    • ... と行った流れのことだろう。
    • Long-Running processesの説明が不正確?

気になった所

  • 専門用語が一気に出てくるため、よくわからなければ理解を深めるためにググる方が良い。

学んだ事

  • SOA (Service Oriented Architecture) は8つの設計原則をもつサービスのアーキテクチャ
  • 昔ながら3層(UI -> Web-Server -> DB-Server) もレイヤ化アーキテクチャの一種。
  • DIP (Dipendency Inversion Principle) によりドメイン層が依存されるだけの状態にする。これによりドメインの管理がしやすくなる。
  • 「ヘキサゴナルアーキテクチャ」はドメインを中心にとらえ、外部接続インタフェースである「ポート」の部分を差し替え可能である「アダプタ」とする。
  • CQRS (Command Query Responsibility Segregation) とは Command実行とQuery実行は別々の処理として分離しなければならないということ。
    • Command ::= *void* modify(...)
    • Query ::= *ImmutableType* get(...)
  • DDDの観点では「結果整合性」が許容される場合は使用することで複雑性を排除する。
  • システムが複数ある場合、イベントを扱うことで複数のシステム間の結合を疎にできる。
  • IDDDではイベント駆動のアーキテクチャとして次の3つを紹介している;
    • 「パイプ&フィルター」: UNIX コマンドに当てはめるとよい。パイプで分離することにより、再利用性やチューニングをしやすくできる。
    • 「長期プロセス(Long-Running processes)」:「並列でパイプラインを実行できる。」 とあるが主目的は、ユーザーからのレスポンスを待つ幾つかのストーリーが逐次実行されて初めて目的が達成されるという意味での正に「長期プロセス」のことである。 ref. https://www.slideshare.net/BerndRuecker/long-running-processes-in-ddd https://github.com/berndruecker/flowing-retail
    • 「イベントソーシング」: パターンの一つ。発生したすべてのイベントを「イベントストア」に記録する。「イベントストア」としてはKafka辺りで実現できそう。

分からないこと

  • DIPの実装として「DIコンテナ」、「サービスファクトリ」、「プラグイン」がある。

知らない概念が多かったので時間がかかった。この後は暫く簡易な概念が続くはず、、、