オーケストレーターとコレオグラフィの比較

# 前提
ソフトウェアアーキテクチャハードパーツの分散ワークフローの章を読んで、
その内容を纏めておく。

Sagaパターンへ行く前に、分散ワークフローの代表的な２種類のそれぞれの特性を理解しないことにはSagaパターンのメリットデメリットを充分に考えられないからだ。

さらに、この分散ワークフローは自分が担当しているビジネスアーキテクチャの
ワークフローを定義する際にも非常に重要になってくる比較の考え方である。

というのも、ビジネスアーキテクチャで定義したフローと
アプリケーションアーキテクチャで定義するフローの様子が乖離してはいけないからだ。
その理由は以下のエンタープライズアーキテクチャモデルとコンウェイの法則を考えたら当たり前のことである。

:::note info
以下に、エンタープライズモデルの図を添付しておく。
<img width="600" alt="R.png (43.4 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/02/29/135213/b08674e8-9def-429b-ab60-9bb5a3041f2c.png">
:::

# 分割する前に考察せよ
個人的には、マイクロサービスへと分割してしまう前に、
仮に分割されていたと仮定して、連携の際のメリデメを考察すべきだと感じる。

定性的にでも事前に机上で、分散させた場合に発生するデメリットを許容できるのか？
という観点で考察していないと、
いざ分割してしまってから「そんな欠陥は許容できない」となってしまっては遅いからだ。

# オーケストレーター、コレオグラフィ
主に取り上げられていたのは、この２つであり
大体どのビジネスもこの２種類に集約されているように感じる。
それぞれの特徴の概要を見ていく。

## オーケストレーター
これはオーケストレーターという名前の通り、
オーケストレーターにあたるサービス量子が他のサービスを呼び出す制御を担う。

模式図は以下のとおりである。

:::note warn
※楕円で書いてしまっているのはポンチ絵だからである。
:::

<img width="500" alt="オーケストレーター.png (23.0 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/01/135213/8b9c287f-7e75-4963-bab3-f75978be8feb.png">

オーケストレーター自身が処理の流れを制御し、エラー対応処理をしたり、
それぞれのサービスの状態を管理している。

オーケストレーター自身が玄関口になっており、すべてのサービスへの呼び出しをする責務を担っているので、心なしかデザインパターンのFacadeパターンのような構造である。


## コレオグラフィ
これはオーケストレーターパターンのように中央調整ぽいやり方ではなく、
デザインパターンのChain of Responsibility(責任の連鎖)と同じようにメッセージを連携していく。

<img width="500" alt="コレオグラフィ.png (20.2 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/01/135213/fcd38b1e-df9b-47f4-bca5-f8683fd8934a.png">

この場合には、オーケストレーター自身がエラー対応せずに、
各サービスが別のサービスに対して補償トランザクションを送る責務を担う。

# 
それぞれの概要に触れたので、今度はそれぞれのメリットデメリットに触れていく。
正常系のフローではそれぞれの良い部分しか視えないが、
実際の業務では、異常系などのフローでどれほどデメリットを抑えるか？が重要である。
そしてこの異常系のワークフローが、どちらのパターンがより適しているかを決めるといっても過言ではない。

# オーケストレーターパターンのメリットデメリット
まずはメリットから見ていく。

## オーケストレーターパターンのメリット
<img width="500" alt="オーケストレーター.png (23.0 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/01/135213/8b9c287f-7e75-4963-bab3-f75978be8feb.png">

### 一元管理によるシンプルさ
オーケストレーター自身が各サービスの状態や、エラー処理をするため、
他のサービスABCは、自分以外のサービスの状態やらを管理する必要はなく、
さらにエラー時の補償トランザクションもオーケストレーターがやってくれるので考えなくていい。
なので、各サービスの責務も非常に分かりやすい。

ワークフローの複雑度が増すほど、オーケストレーターに責務がまとまってるので修正などがしやすい。

### エラー処理
オーケストレーターがめんどくさいことはやってくれているので、エラー処理を円滑に行えるという恩恵がある。
<img width="500" alt="オーケストレーター2.png (29.2 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/01/135213/73580e88-2b33-4976-99f7-9ccef73f690d.png">

### 回復性
仮に下図において、サービスBが停止するなどのトラブルが起きたとしても、
オーケストレーターが状態監視しているので、再試行するロジックを走らせるなり、
もしなかったとしてもオーケストレーターに再試行ロジックを追加すりゃいい。
オーケストレーターの責務がわかりやすいから、復旧にかかる時間も短くしやすいため、回復性に富んでいる。
呼び出し先のサービスの状態がおかしい場合には、しばらく呼び出さないなどの調整もしやすい。

<img width="500" alt="オーケストレータ回復.jpg (32.6 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/01/135213/15e2d478-f684-4f2a-8a69-d06f30747082.jpg">

### 状態管理
どこを見ればワークフローの状態が見られるか？が一発！

なにか全体で障害が起きた際に、原因特定のためある時刻におけるワークフローの状態を知りたい。
そんな時にあっちこっち探すのはメンドウ。
でもオーケストレータパターンなら、オーケストレータに全ての状態があるのでシンプル。

## オーケストレーターパターンのデメリット
次にデメリットを見ていく。

<img width="500" alt="オーケストレーター.png (23.0 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/01/135213/8b9c287f-7e75-4963-bab3-f75978be8feb.png">

### 応答性
サービスAからBへと何かメッセージ送りたくても、必ずオーケストレータを介さないといけないので直列的な処理になりやすく遅くなりやすい。

### 耐障害性
認知負荷って意味で考えてみれば、オーケストレータはワークフローの制御と状態管理
などなどメンドウくさいことをすべてやってくれているので、
サービスの数が増えたり、複雑なワークフローを制御していたら認知負荷が許容範囲を超えてしまい、オーケストレータ自身が落ちてしまいやすくなる。
つまり、ここが単一障害点になりやすいのである。
もしもオーケストレータが停止したら、サービスAやB、Cはそれぞれの状態を知らないので、実質全体が障害起きているようなもの。

### 認知負荷
これは組織的なコンウェイ力学による制約条件である。
上記の耐障害性でも触れたが、このオーケストレーターを担当するチームには認知負荷がどうしてもかかってしまう構造である。
もしもオーケストレーターを担当するチーム自体にかかる負荷量があまりにも大きいのであれば、オーケストレータは向いていない可能性が高まる。
よって、ワークフローの制御や補償トランザクション、各サービスの状態管理以外の責務は決して持たないようにするのが望ましいと考えられる。


### 結合度の高さ
<img width="500" alt="オーケストレーター.png (23.0 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/01/135213/8b9c287f-7e75-4963-bab3-f75978be8feb.png">

オーケストレーターから複数のドメインサービスに対して動的な結合が発生しているので、
複数の線で結合している状態。これはその本数が多ければ多いほど密な結合である。

### スケーラビリティ
一般に結合度が高くなると、スケールはしにくい傾向がある。
[詳細はこちらの記事を参照ください。スケーラビリティと結合度の関係](https://qiita.com/Kudo_panda/items/e5b4560fe9a83bf04d6d)

オーケストレーターパターンでは、コレオグラフィと比べて結合度は高く、
オーケストレーターを必ず介するために、直列的なワークフローとなりやすいため、
スケーラビリティはコレオグラフィよりも自ずと低くなる。
呼び出し先のサービスがスケールアップしたら、それに引きずられてオーケストレーター自身もスケールアップしないといけなくなる可能性がある。

そしてそれは、コンウェイの法則を考えれば、オーケストレーターを担当しているチームの認知負荷が高まることを意味している。
認知負荷が高まれば当然、【障害】も起こりやすくなる。

# コレオグラフィパターンのメリットデメリット
これらは丁度オーケストレータパターンの逆関係になる。
オーケストレータパターンにある恩恵がコチラにはなく、
オーケストレータパターンになかった高いスケーラビリティや疎結合がコチラにはある。

一見、このコレオグラフィは「どの順番でイベント発生するか」がイベント駆動型のワークフローに視えて非常に分かりやすく視えそうだが、色々なデメリットも存在する。

まずはメリットから見ていく。

## コレオグラフィパターンのメリット
### 応答性
オーケストレータを仲介しなくていいので、より多く並列処理を走らせやすい。
そのため応答性はオーケストレータパターンよりも優れている。

### 耐障害性
複数のサービスに対して認知負荷を分散できることによって耐障害性が高まる。
オーケストレータのような単一障害ポイントは起こりにくくなる。

### 認知負荷
オーケストレータのような１つだけ以上に認知負荷がかかるということは避けられる。
ただし、その分各サービス自身が呼び出す先へ補償トランザクション送ったりするので、負荷が分散される代わりに、各サービスの認知負荷がオーケストレータよりも上昇してしまう。

### 結合度が疎
<img width="500" alt="コレオグラフィ.png (20.2 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/01/135213/fcd38b1e-df9b-47f4-bca5-f8683fd8934a.png">

図を見ても分かるように、オーケストレータパターンとは違って、
サービス間の結合の本数が少なくなるので、より疎結合が実現できる。

### スケーラビリティ
疎結合が実現できることによって、個々のサービスの独立性がオーケストレータパターンよりも高まるので、スケーラビリティに優れている。

## コレオグラフィパターンのデメリット

### 分散ワークフローによる複雑さ
正常系のワークフローであればまだイベント順になっていてシンプルなのだが、途中で異常が発生した際の複雑なワークフローがこのパターンのデメリットノ１つだ。
どのサービスに対して送る補償トランザクションをどのサービスに持たせたらいいのか？など、オーケストレータパターンにはなかった複雑さが跳ね上がる。

### 状態管理の複雑さ
オーケストレータパターンとは違って状態の一元管理者がいないので、状態管理は複雑化する。

### 責務の特定の難しさ
オーケストレータパターンと違い、各サービスが自分の責務以外に、
補償トランザクション系のワークフローの責務を持つ必要性もある。

### 回復性に乏しい
このパターンは並列向きだから、障害起きてもどこに復旧すべき箇所があるのか？の特定にも時間がかかりやすい。
また補償トランザクションが失敗するリスクもあるので、その場合の復旧はさらに困難。
再試行の処理走らせるけども、そうしたら今度は別のサービスで問題発生して落ちたとかってことがあり得る。
そんな時にはオーケストレータパターンの方がずっと復旧しやすい。

# 比較した上で何が言えるか
これも状況によって変わってくる。
エラー条件でのワークフロー込みの複雑なワークフローをシンプルにしたいのか？
それともワークフローが複雑になる犠牲を払ってもスケーラビリティや耐障害性を高めたいのか？
どちらの願望が強いかによって変わってくる。

シンプルさで言えばオーケストレーターパターンの方が優れている。
自分の案件で経験したことあるワークフローはコレオグラフィ型であったが、
フローがどんどんネストしていき、何をやってんのかわからなくなりやすいってのがあった。


# まとめ振り返り
以上のことから、願望の強さとして

:::note info
複雑なワークフローへの対応をしたい＞＞スケーラビリティや耐障害性を高めたい

という関係が成立する際には、オーケストレーターパターンが。
:::

:::note info
複雑なワークフローへの対応をしたい＜＜スケーラビリティや耐障害性を高めたい

という関係が成立する時には、コレオグラフィが適している。
:::

また、どうしてもコレオグラフィパターンを適用したいけども、
ワークフローが複雑という時のために、スタンプ結合によって結合度を高めるという犠牲を払うことで、多少ワークフローの複雑さを緩和できる。