（IDDDを読んで気になったことシリーズ）「13.3 メッセージングを使った統合」は複雑

書籍「実践ドメイン駆動設計」の「13.3 メッセージングを使った統合」の図解を試みる。
13章以前の各章の集大成的な部分もあり、構造が複雑だったので理解を整理する目的と備忘としての目的の為に作成した。
合わせて、お気に入り設計手法の「三要素分析法」と「ドメイン駆動設計」を段階的につなぎ合わせる構成も模索してみた（模索中）。

# 1 基本設計
三要素分析法を使用して整理する。
[データモデリング手法とレファレンスモデル](http://dbc.in.coocan.jp/)

## 1-1 業務フロー
#### **１）メインフロー**
**2-1**
1. Productを作成する。
2. ProductCreatedイベントがEventStoreに格納される。
3. CreateExclusiveDiscussionコマンドがExchangeへ向けて配送される。
4. Disucussion作成のトラッカーをTCPTrackerへ格納しカウントダウンを開始する。

**2-2**
1. CreateExclusiveDiscussionを受信してForumとDiscussionを作成する。
2. ForumCreated、およびDiscussionCreatedイベントがEventStoreに格納される。
3. DiscussionCreated通知がExchangeへ配送される。

**2-3**
1. DiscussionCreated通知を受信してProdustにDiscussionを紐付ける。
2. ProductDiscussionInitiatedイベントがEventStoreに格納される。
3. TCPTrackerにプロセス完了の更新を行う。
```mermaid
flowchart TD
  subgraph AgilePM
    AP1(2-1 ProdProductを作成する)
	AP2(2-3 ProductにDiscussionを紐付ける)
	AA1[(Product)]
	AA2[(EventStore)]
	AA3[(TCPTracker)]
  end
  
  subgraph Collaboration
    CP1(2-2 ForumとDiscussionを作成する)
	CA1[(Forum)]
	CA2[(Discussion)]
	CA3[(EventStore)]
  end

  XE1@{ shape: das, label: "COLLABORATION_EXCHANGE_NAME" }
  
  AP1 -.-> AA1
  AP1 -.->|"ProductCreated<br>(Event)"| AA2
  AP1 -.-> AA3[(TCPTracker)]
  AP1 -.->|"CreateExclusiveDiscussion<br>(Command)"| XE1
  XE1 -.->|"CreateExclusiveDiscussion<br>(Command)"| CP1
  CP1 -.-> CA1
  CP1 -.-> CA2
  CP1 -.->|"ForumCreated,DiscussionCreated<br>(Event)"| CA3
  CP1 -.->|"DiscussionCreated<br>(Notification)"| XE1
  XE1 -.->|"DiscussionCreated<br>(Notification)"| AP2
  AP2 -.-> AA1
  AP2 -.->|"ProductDiscussionInitiated<br>(Event)"| AA2
  AP2 -.-> AA3
 ```

#### **２）タイムアウト検知フロー**
**2-4**
1. TCPTrackerを参照して、インターバル超過プロセスを抽出する。
2. リトライ可能ならばProductDiscussionRequestedイベントが、リトライ上限ならばProcessTimedOutイベントがEventStoreに格納される。
3. リトライ可能な場合は、コマンドがExchangeへ向けて配送される。
4. TCPTrackerのステータスを更新する。
```mermaid
flowchart TD
  subgraph AgilePM
    AP1(2-4 インターバル超過プロセスを抽出してリトライかタイムアウトする)
    AA1[(TCPTracker)]
	AA2[(EventStore)]
  end

  XE1@{ shape: das, label: "COLLABORATION_EXCHANGE_NAME" }

  AA1 <-.-> AP1
  AP1 -.->|"PrcesssTimedOut<br>ProductDiscussionRequested<br>(Event)"| AA2
  AP1 -.->|"CreateExclusiveDiscussion<br>(Command)"| XE1
 ```

## 1-2 データモデル
理想は渡辺式ER図をMarmaidで作図すること。以下は現状できる範囲で図示したイメージ。
```mermaid
erDiagram
  Discussion |o--o| Product : "ProductはDiscussionIdをProductDiscussionに持つ"
  Product ||--o| TCPTracker : "ProductとTCPTrackerは1対1または0（サーガを開始しない場合もある）"

  Product {
    TenantId tenantId PK
    ProductId productId PK
	SetOfProductBacklogItem backlogItems
    String description
    ProductDiscussion discussion FK "DiscussionIdを値オブジェクトに変換して格納"
    String discussionInitiationId UK "ProcessIdをStringに変換して格納"
    String name
    ProductOwnerId productOwnerId
  }

  Discussion {
    TenantId tenantId PK
	DiscussionId discussionId PK
    Author author
    boolean closed
    String exclusiveOwner
    ForumId forumId
    String subject
	String discussionInitiationId UK "ProcessIdをStringに変換して格納"
  }

  TCPTracker {
    ProcessId processId PK
    TenantId tenantId
	long timeConstrainedProcessTrackerId
    long allowableDuration
    boolean completed
    int concurrencyVersion
    String description
    boolean processInformedOfTimeout
    String processTimedOutEventType
    int retryCount
    long timeoutOccursOn
    int totalRetriesPermitted
  }
```

## 1-3 機能モデル
to be created

## 1-4 業務モデル
to be created

# 2 詳細設計
まずフレームワークを定義し、次にフレームワークを活用したプロセスの詳細を設計する（プロセスは基本設計の業務フローにあるプロセスのこと）。

## 2-1 フレームワーク
to be created

### 2-1-1 イベント発行をサブスクライブしてイベントストアへ格納（EventStoringAspect）
**１）データフロー**
```mermaid
flowchart LR
  A((Entity)) -.->|DomeinEvent| B[EventStoringAspect]
  B -.->|DomeinEvent| C[(EventStore)]
```

**２）EventStoringAspectのオブジェクトモデル**
　実践ドメイン駆動設計　p.296　図8-3
　※IdentityAccessEventProcessorはAspect（p.297　上の網掛）

### 2-1-2 イベントストアから収集したイベントをエクスチェンジへ配送（StoredEventForwarder）
**１）データフロー**
```mermaid
flowchart LR
  A[(EventStore)] -.->|DomainEvent| B[StoredEventForwarder]
  B -.->|Notification| C@{ shape: das, label: "ExchangeA" }
  B -.->|Notification| D@{ shape: das, label: "ExchangeB" }
```

**２）StoredEventForwarderのオブジェクトモデル**
- NotificationServiceはEventStoreからDomainEventを取得しNotificationを発行する
実践ドメイン駆動設計　P.311　上の網掛
※GitHubではNotificationApplicationServiceとRabbitMQNotificationPublisherの組み合わせで実装されている 
```mermaid
classDiagram
  EventStore <-- NotificationService:observe
  NotificationService --> Notification:new
  NotificationService --> MessageProducer:send
  MessageProducer --> Exchange:deliver
```

- NotificationServiceは定期実行する
実践ドメイン駆動設計　p.315　「発行時の待ち時間に関して言うと」の段落以降  
```mermaid
sequenceDiagram
  TimerMBean ->> MBeanService:notify
  MBeanService ->> NotificationListener:handleNotification
  NotificationListener ->> NotificationService:publishNotifications
```

### 2-1-3 エクスチェンジからメッセージを取得して処理を委譲する（ExchangeMessageDispatcher）
**１）データフロー**
```mermaid
flowchart LR
  A@{ shape: das, label: "Exchange" } -.->|notification| B[ExchangeMessageDispatcher]
  B -.-> C[something]
```

**２）ExchangeMessageDispatcherのオブジェクトモデル**
```mermaid
classDiagram
  direction LR
  class ExchangeListener {
    <<abstract>>
  }
  
  Exchange <-- Queue:routing
  Queue <-- MessageConsumer
  ExchangeListener --> Queue
  ExchangeListener --> MessageConsumer
  ConcreateExchageListener --|> ExchangeListener
```
実践ドメイン駆動設計　P.455　網掛
1. MessageProducerがExchageへメッセージを発行する
2. QueueはExchageからへメッセージを取得する
3. MessageConsumerはQueueからメッセージを取得し具体的な処理を実行する
4. ExchageListenerはクライアントから見た抽象Consumerとなり、Queueのメッセージを処理する
5. 実際はConcreateExchageListenerを実装して使用する

### 2-1-4 プロセスとプロセストラッカー
**１）データフロー**
```mermaid
flowchart TD
  subgraph AgilePM
    A[Process]
    B[(TCPTracker)]
    C[(EventStore)]
    D[StoredEventForwarder]
    E@{ shape: das, label: "AGILEPM_EXCHANGE_NAME" }
	F[ExchangeMessageDispatcher]
  end

  B -.->|TimeConstrainedProcessTracker| A
  A -.->|"Event<br>(ProcessTimedOut)"| C
  C -.-> D
  D -.->|"Notification<br>(ProcessTimedOut)"| E
  E -.-> F
```

**２）Process、TimeConstrainedProcessTracker、およびProcessTimedOutのオブジェクトモデル**
```mermaid
classDiagram
  class ProcessTimedOut {
    TenantId
	ProcessId
	TotalRetriesPermitted
	RetryCount
	allowsRetries()
	retryCount()
	totalRetriesPermitted()
	totalRetriesReached()
  }
  
  class Process
  <<interface>> Process

  Process <|.. AbstractProcess
  Entity <|-- AbstractProcess
  AbstractProcess <|-- Product
  AbstractProcess --> TimeConstrainedProcessTracker:new

  ConcreteProcessTimedOut --|> ProcessTimedOut
  TimeConstrainedProcessTracker --> ConcreteProcessTimedOut:new
```

## 2-2 プロセス設計
プロセスを詳細化してアプリケーション・サービスを設計する。
- 点線矢印　　　直接の依存関係なし。データフローのみ。
- 実線矢印　　　メソッド呼び出しの関係。基本的には。

### 2-2-1 Productを作成する
```mermaid
flowchart TD
  subgraph AgilePM
    A[ProductService]
    B[EventStoringAspect]
    C[(EventStore)]
	I[(Product)]
    D[StoredEventForwarder]
    E@{ shape: das, label: "AGILEPM_EXCHANGE_NAME" }
	F["ExchangeMessageDispatcher<br>(ProductDiscussionRequestedListener)"]
  end
  
  H@{ shape: das, label: "COLLABORATION_EXCHANGE_NAME" }

  A -.-> I
  A -.->|"Event<br>(ProductCreated)"| B
  B -.-> C
  C -.-> D
  D -.->|"Notification<br>(ProductCreated)"| E
  E -.-> F
  F -.->|"Command<br>(CreateExclusiveDiscussion)"| H
  F -->|"startDiscussionInitiation(..)"| A
```

### 2-2-2 ForumとDiscussionを作成する
```mermaid
flowchart TD
  H@{ shape: das, label: "COLLABORATION_EXCHANGE_NAME" }
  
  subgraph Collaboration
	I["ExchangeMessageDispatcher<br>(ExclusiveDiscussionCreationListener)"]
	J[ForunService]
	K[EventStoringAspect]
	L[(EventStore)]
	N[(Forum)]
	O[(Discussion)]
	M[StoredEventForwarder]
  end

  H -.->|"Command<br>(CreateExclusiveDiscussion)"| I
  I -.-> J
  J -.-> N
  J -.-> O
  J -.->|"Event<br>(DiscussionStarted)"| K
  K -.-> L
  L -.-> M
  M -.->|"Notification<br>(DiscussionStarted)"| H
```

### 2-2-3 ProductにDiscussionを紐付ける
```mermaid
flowchart TD
  subgraph AgilePM
    A[ProductService]
	B[EventStoringAspect]
    C[(EventStore)]
	D[(Product)]
	G["ExchangeMessageDispatcher<br>(DiscussionStartedListener)"]
  end

  H@{ shape: das, label: "COLLABORATION_EXCHANGE_NAME" }
  
  H -.->|"Notification<br>(DiscussionStarted)"| G
  G -->|"initiateDiscussion(..)"| A
  A -.-> D
  A -.->|"Event<br>(ProductDiscussionInitiated)"| B
  B -.-> C
```

### 2-2-4 インターバル超過プロセスを抽出してリトライかタイムアウトする
```mermaid
flowchart TD
  subgraph AgilePM
    A[ProcessService]
    B[(TCPTracker)]
    C[(EventStore)]
    D[StoredEventForwarder]
    E@{ shape: das, label: "AGILEPM_EXCHANGE_NAME" }
	F["ExchangeMessageDispatcher<br>(ProductDiscussionRetryListener)"]
	G[ProductService]
  end

  B -.->|TimeConstrainedProcessTracker| A
  A -.->|"Event<br>(ProductDiscussionRequestTimedOut)"| C
  C -.-> D
  D -.->|"Notification<br>(ProductDiscussionRequestTimedOut)"| E
  E -.-> F
  F -->|"timeOutProductDiscussionRequest(..)<br>or<br>retryProductDiscussionRequest(..)"| G
```

## 2-3 ドメインモデル設計
ドメインモデルの各要素を詳細化する。
- エンティティ
- 値オブジェクト
- イベント
- etc