マイクロサービスにおけるデータの所有権の割当

# 背景
分散アーキテクチャにてデータをデータの側面での境界付けられたコンテキストである
データドメインごとに分割した後には、どのサービスがそのデータドメインを所有するか？
を考えないといけない。

これは分散アジャイル組織において、情報をどこに持たせるのがもっともベターか？
を考える際にも超重要になってくるので、組織設計を行う方とかは是非とも一度通っておくことをオススメします。

いきなり分散アジャイル組織をデザインするのではなく、
まずはどのチームにどのデータを所有させるとよりQCDを満たせる解として良いのか？を
考えられるので。

# 前提知識
## データドメイン
端的に言うと、データの側面でのコンテキスト境界のこと。
トランザクション単位といったプロセスの側面から考えたうえで、
強い整合性の求められるような箇所(注文と注文明細とか)は、同じデータドメインにまとめるといったことを考えます。

このデータドメインは、データという側面からの考察だけでは十分に明らかになりません。
必ずトランザクションなどといったプロセスの側面とを行き来し、
データのコンテキスト境界を明らかにします。

## 概念スキーマで論理分割
データベースに詳しい方ならここはすっ飛ばしていただいて構いません。
今回扱うソリューションは、ソフトウェアアーキテクチャハードパーツにある代表的な解について、自分なりの見解を交えながら記載しますが、
いきなりサービスとして分割する前に、まずは物理的に１つのDBサーバーを基本として、
その中でデータのコンテキスト境界ごとに論理分割した上で、
各モジュールに所有権を割り振ったのちに、
「この境界の位置で物理的に切り分けて問題ない。切り分けた方がビジネス上の恩恵がデメリットより上回る」と判断した上で1つのサービス境界内に、サービスとデータをカプセル化してください。

## 情報エキスパート
この時、考え方の基本になるのは、GRASPの情報エキスパートパターンである。
テーブルに対して書き込みを行うサービスにその所有権を担わせる。

https://qiita.com/Kudo_panda/items/6d4cff3dff0f7d060405

## アナリシスパターン
また以下で出てくる共同所有におけるテーブル分割パターンでは、
アナリシスパターンで出てくる【知識レベルと操作レベルの分離】の思想が反映されている。

マスターデータである知識レベルが1つに対して、実体として手に取って扱える操作レベルの方が複数あるようなビジネス。
たとえば某ファストファッションビジネスなどで、各物理的な商品の方が、
どの顧客の手にわかっているのか？までシステムで管理したいスコープとする場合には、
操作レベルの方の商品を【在庫】と名前を表現して、
【商品】はマスターデータの方の知識レベルの方として表現することで、
マスターデータである商品の概念１つに対して、在庫は0以上であり、
在庫と顧客が注文などを通して関連づき、商品と顧客は紐づかないという概念モデルとして表現する。(以下の図を参照)

<img width="500" alt="注文ドメイン.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781175/f7c60f43-38f0-36fc-c087-18a52350f57d.png">

:::note warn
ただし、マスターデータである知識レベルが1つに対して、実体として手に取って扱える操作レベルの方が必ず0または1になるようなビジネスモデル。
たとえばオーダーメイドのようなビジネスなどでは、わざわざ知識と操作レベルの概念を分けるメリットはない。
:::

# 諸注意
サービスを分割してからデータの所有権を考察するなんてことは絶対にしないでいただきたいです。
分散アーキテクチャにおける他のコンテキストへのデータアクセスやトランザクションの問題は相当やっかいです。
あらかじめ「もしも仮にサービスを物理的にも分割したら～」という仮定で、
嬉しいことと、それによって発生するデータの整合性リスクや、
所有権を適切なコンテキストに割り当てたとしても、その後に状況が変わって、
データの割当先を別のサービスコンテキストに変えた方がベターになる可能性だってあります。

それらの分割することによって発生する脅威を十分に考えたうえで、
それでもマイクロサービスとして切り分けた方が、ビジネス上恩恵があると判定された場合にのみ、最もリスクが低くて可逆性を担保できる場所から切り分けるというように考えます。

:::note info
上記で書いたように、まずはモジュラーモノリス構造にて、
概念スキーマによってデータ群を論理分割し、各スキーマ内のデータドメインを
各モジュールに所有権を割り当てというようにすることを目指しましょう。
:::

:::note warn
どのモジュールが概念スキーマによって分割されたどのデータドメインを所有すると思われるのか？は、チーム内で共通認識が持てるように、しておきましょう。
:::



# 所有の仕方
所有の仕方には大きく分けて３種類存在する。
根底は情報エキスパートの考えだが、それだけでは全体所有や共同所有には対処しきれない。
まずは３つのそれぞれの概要について。

## 単独所有
下図のように

サービスAはテーブルXに対してのみ書き込みを行い、
サービスBはテーブルYに対してのみ書き込みを行い、
サービスCはテーブルZに対してのみ書き込みを行うという場合。

<img width="500" alt="所有権①.png (10.9 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/26/135213/c8cbf781-8604-4834-b2b3-b72abbab65a7.png">

つまり1つのテーブルに対して、1つのサービスしか書き込みをしないという場合。
この場合には非常にシンプルである。
以下のように境界を定義し、カプセル化する。

<img width="500" alt="境界付けられた.png (12.7 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/26/135213/a7a6bdaa-b01c-4665-8a90-d413ed7cc3cd.png">

:::note info
まずはこの単独所有ができないか？を考える。
それができなかった時に、次の全体か共同所有を考えるようにする。
:::

## 全体所有
1つのテーブルに対して、ほとんど(またはすべて)のサービスから書き込みが起きる際には、
全体共有が生じる。

### 問題点
数十、数百以上のサービスが1つのテーブルに対して書き込みを行う場合、
せっかくデータドメインごとに分割したのにもかかわらず、
データドメインごとに分割する前の問題点であった

:::note warn
・変更の制御
・データベースへのコネクション枯渇
・スケーラビリティ
・耐障害性
:::

のすべての問題が再発してしまう。

### ソリューション
たとえば以下のような図において、テーブルXは既存のすべてのサービスから書き込みをされているとする。
この程度のサービス数であれば問題ないかもしれないが、
実際問題これがより大量の数十などのサービスから書き込みをされていたとしたら、
今のままでは上記のような運用特性上の問題が起きてしまう。
<img width="500" alt="全体所有.png (16.7 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/26/135213/aa37d869-3eb4-4f81-a4ad-9a618a61cb2d.png">


そこで以下のように、テーブルX専用の所有者であるサービスを設けて、
他のサービスAやBなどがテーブルXに書き込みを行いたい時には、
そのサービスに情報を送信して、Xの所有者(図のX所有サービス)自体が書き込みを行う。
<img width="500" alt="全体所有ソリューション.png (13.8 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/26/135213/363775b2-dde1-499b-8e7e-e45f8853a2cb.png">

図には描いていないが、永続的なキューを使用してメッセージを送る。
そうすればメッセージ送る先とかに障害が起きたとしても送りたい情報は失われないことを保証できる。

## 共同所有
上記のすべてやほとんどのサービスがテーブルを所有するのではなく、
一部の複数のサービスが同じテーブルに対して書き込みを行う場合にこの共同所有がある。

この共同所有には、いくつかのパターンにわかれる。

:::note warn
ただし、その中でデータドメインパターンについては、
マイクロサービスとは言えないアーキテクチャスタイルに感じるため、
個人的にはあまりオススメできない。
:::

# テーブル分割パターン
書籍に書かれたパターンは、商品のマスタと、在庫概念に分割しているため、
アナリシスパターンの知識レベルと操作レベルの分割に近しい考え方である。

知識と操作の分離とは、たとえば対象のビジネスにおいて、
商品のマスターデータに関するものと、手に取れる物理的な商品とを分けて考えたいという場合に、概念モデル上でも分離して考えることである。

マイクロサービスでいうと以下の図のように
知識レベルの方の商品のコンテキスト境界である【カタログサービス】
操作レベルである方の商品コンテキスト境界である【在庫サービス】

もともと１つであった商品テーブルをこれら２つに分割することで対応する。

そうすることで、共同所有であった状態から単独所有にできる。

:::note warn
ただし、この場合には知識レベルの商品側と操作レベルの方の商品との間で、削除や更新時のデータの整合性などの問題点がどうしても避けられない。
:::

:::note warn
また、データモデリング上で1つのテーブルに対して、
知識と操作が混在しているように、２つ以上のコンテキストが混ざっている
と言えるような時にしか有効とは言えない。
:::

## メリット
### データの単独所有
なんといっても単独所有にできるので、非常にシンプルになることだ。

### 耐障害性
後続のサービスコンソリデーションパターンなどに比べて、ダウンしたりするリスクも低い。

### 境界付けられたコンテキスト維持
分割したテーブル間に強い整合性が求められないケースにおいては、
コンテキスト境界の維持、およびそのサービスを運用するチームにとって、
認知負荷が高まりにくい状態をキープできる。

## デメリット
このパターンで非常に重要になってくるのは、分散アーキテクチャを選んだ場合に、
可用性と整合性の両方を取ることはできないということだ。(∵CAP定理)
ビジネスモデル上の品質として、どちらがエンドユーザーにとって嬉しいのか？
を選ばなくてはならない。


# データドメインパターン
このパターンはマイクロサービスとはまだ言える状態ではない。

:::note info
マイクロサービスにおける１つの境界付けられたコンテキスト内には、
オブジェクト指向のカプセル化と一緒の考え方で、
テーブルとそれに対する書き込みをするサービスプロセスをまとめ、
他コンテキストからのテーブルへの直接アクセスを禁止(データ隠蔽)すること。
:::

## 事実
これに対して、データドメインパターンはマイクロサービスの量子としては、
まだ未完成状態である。
テーブルしかないデータドメインのみを１つのコンテキスト境界内に定義しているからだ。

## 主張
よって、まだどのサービスにテーブルの所有権を持たせるのかがまだ不明といった場合に、
一時的にこのパターンを適用する際には構わないと感じている。

チームトポロジー書籍の物理本、P.89に「チームをまたぐ重要な情報を視える化することは～」という一文がまさにこのデータドメインパターンの組織構造を指していると思われる。

余談ではあるが、自分は案件の中でこのパターンのアーキテクチャを見たことがある。
それは超大規模エンタープライズであり、
あるビジネスプロセス群を管理する組織と、別のビジネスプロセス群を管理する組織が分かれていた。そしてデータ基盤をマネジメントする組織はまた別に存在していた。


:::note warn
ただし個人的には、サービスとして分割する前に、
上図でいうとカタログモジュールと、在庫モジュールに論理分割しておいて、
それらを含む１段階マクロなコンポーネントとして、商品サービスを定義し、
その内部に商品テーブルを持つというようにする方がベターと感じる。

この場合、在庫とカタログに関する計2つの責務が商品サービスには存在することになるが、そのデメリットを覆うだけの利点の方が上回る。
:::


## メリット

## デメリット
下図をご覧いただければお分かりかと思いますが、データスキーマが変更されたら
それに伴ってそれを使用するサービス側への変更時の問題である。

### ①データスキーマの変更によるサービス数の増加
境界を飛び越えての変更の波紋が伴うことから、
そのテーブルを使用するサービスをすべてマネジメントできていないと、
どれかのサービスが落ちるなどの問題が起こる。

なので、対象のデータドメインを使うサービス数が数個であればまだいいが、
数十とかってなってくるとどれか考慮漏れが起きたりしかねない。

### ②データスキーマの変更によるテスト範囲の増加
データスキーマが変更されたら、当然それを使用するサービスプロセス側もすべてテストし直す必要がある。
サービスが数個ならまだかわいい方だが、これが数十とかになってくると、
テストコストは絶望的に高くなることは定性的にも容易に想像がつく。

### ③ データ書き込み権限の統制を取るのがめんどう
サービスを開発する側からすると、
密なコミュニケーションがないと、「あ！ちょうどあのデータ使いたかったんだよラッキー」みたいなことが起こりかねないので、書き込みを行える制限をかけないととんでもないことになるのは自明である。

### ④データスキーマの変更によるデプロイコストの増加
データドメインの量子と、それを使うサービス量子のすべてで実質１つのデプロイ量子
であることから、その範囲が高くつきやすい。

:::note warn
そもそも境界付けられたコンテキストの範囲を超えてのデプロイを強いられるのが
個人的にはこのパターンが嫌いな理由の１つである。(完全に私個人の主観)
:::



# 委譲パターン
これは代表のようなサービスがテーブルを単独所有し、
他のサービスからの更新は、その所有者に更新処理を送って代行するという思想である。

しかし、どのサービスを所有者とするのか？という課題がある。

## メリット
### テーブルの単独所有が可能
これも先ほどのデータ分割と一緒で、テーブルの単独所有権を実現できるのが最大のメリットである。

### 

## デメリット
### ①サービス間結合が密である

# サービスコンソリデーションパターン
これは複数のテーブルの所有者サービスを１つに統合してしまおうという思想である。
つまり、意図的に荒い粒度のサービスにすることによって、単独所有にするということ。

一応単独所有にはなるものの、サービスの粒度感が大きくなってしまうことで、
他のマイクロサービスとの粒度不揃いや、デプロイ時のリスク問題などの問題が出てくる。

## メリット
### アトミックである
物理的に１つのサービスとしてまとまるので、アトミックトランザクションを維持できる。
強い整合性を必要とする場合には、この恩恵を受ける。

### パフォーマンス性が高い
サービスが分かれている時に比べて、１つにまとめっている方がパフォーマンスが高いのは言うまでもない。

## デメリット
### 認知負荷が高まる
もともとロジックとしてはわかれていたものを１つにまとめるので、
チートポ的にいうと、管理するチーム全体の認知負荷量が高まる。

### テストコストの増加
図形的に見て自明なように、まとまることによってテスト範囲がその分広がる。

### デプロイリスクが上がってしまう
テスト範囲の広がりに伴い、全体をデプロイする際のリスクが高くなってしまう。

### 耐障害性が低下
１つにまとまることによって、まとめた部分が一緒にダウンすることになるので、
まとめる前に比べて、それぞれの耐障害性は相対的に下がる。
対象コンテキスト内のDBに対して、単純計算でまとめる前に比べて倍のアクセスがなされるのだから、DBアクセスが集中してダウンするという可能性も高まってしまう

### スケーラビリティの柔軟さ低下
もともと別々であったサービスを１つにまとめるのだから、必然的にそれら全体的にスケーリングすることになる。
一部分だけをスケールというように柔軟にはいかなくなる。

# 補足事項
最後にUAFと絡めた補足事項を記載しておきます。
今回扱ったデータの所有権は、ServicesビューにおけるInformation列の定義に役立ちます。

![UAFGrid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781175/0c78be07-f483-d6d1-d068-d6589ae4671d.png)

逆コンウェイ的にAA層で考えたデータのコンテキスト境界やデータの所有権の割り当てを
DA層やBA層に反映させるのです。

その際にUAFグリッドで十分に定義しきれていなかった、
Servicesビューにおける各サービスに対するデータの所有権をInformationビューに更新します。