マイクロサービス分割におけるモデリングの観点

マイクロサービスアーキテクチャの5章は、モノリスをどうやって分割していくかが焦点です。サービス間での依存関係をできるだけ断つために、共有データや共有テーブルを避け、分割していくやり方が書かれています。

![](https://www.oreilly.co.jp/books/images/picture978-4-87311-760-7.gif)

モデリングの観点からは、記述が不足なところがあって、現場のモデルに照らし合わせて考えることが難しいので、これをもう少し掘り下げて考えてみます。

データモデリングの手法としては、拙作の[イミュータブルデータモデル](http://www.slideshare.net/kawasima/ss-40471672)が前提となりますので、未見の方はそちらをまずご参照ください。

[![](http://image.slidesharecdn.com/random-141019235040-conversion-gate01/95/-1-638.jpg)](http://www.slideshare.net/kawasima/ss-40471672)


エンティティは、リソース系とイベント系の2種類に大別するので、これらの関連の種類で言うと、R-R, E-R, E-Eの3つあります。これを順に分割するとどうなるかを考えます。

これらの呼び方はTM手法に準じます。
http://tmdmaker.osdn.jp/doc/ch08.html

## リソース-リソース(R-R)

### 強い依存関係

リソース間に強い依存関係、「子は親が無ければ存在しえない」があれば、そこで分割するのはやめたほうがよいでしょう。

![image](https://qiita-image-store.s3.amazonaws.com/0/8475/a3867884-7ed2-a2f3-af05-99fe2f2e4f60.png)

上の例では、ホテルと部屋の関係において、部屋はホテルが無いと存在しえないので、部屋だけサービス化されることはまずないでしょう。この間での分割は運用の面倒さしか産まないと思われます。

### 弱い依存関係(コンポジットの関係)

次に、リソース同士が独立して存在し得る関係性は分割の対象になりうるかもしれません。

この場合、リソース間に対照表を置きます。

例えばパーツショップが、BTOパソコンも販売するような業務をシステム化するときに、パーツ管理業務とBTOパソコン組み立て業務で、別々の組織構成でマイクロサービス化したいことが出てくるかもしれません。

![image](https://qiita-image-store.s3.amazonaws.com/0/8475/38937bd6-fa79-1d5d-3e53-66307c73e55c.png)

このとき対照表である"パーツ構成"は、どちらのサービスに配置すべきでしょうか? これはパソコンサービス側に配置しておけば良さそうです。

![image](https://qiita-image-store.s3.amazonaws.com/0/8475/4ac49658-243a-058e-501a-0dc77b5e30ec.png)

- パソコンを組み立てるときには、パソコンサービスに問い合わせてパーツ構成を取得し、パーツサービスに問い合わせて、それらの詳細や在庫をまとめて取得する。
- パーツからどのパソコンで使われているかを問い合わせるニーズは、「レポート」の用途でしかなさそう。

似たような関係性には、沿線-駅やエリア-都道府県などがあります。

### 弱い依存関係(コンポジット関係ではない)

じゃらんや楽天トラベルをみると、ユーザが宿をお気に入りに登録(クリップ)する機能があります。

![image](https://qiita-image-store.s3.amazonaws.com/0/8475/2f6056c8-da20-bde2-8223-bcdf55d7057e.png)

顧客と宿は完全に独立して存在しえて、どちらかがどちらかの構成要素になるというコンポジット関係も無いので対等です。この場合、それらの関連を示す「お気に入り」というのはどう扱えばよいのでしょうか?

![image](https://qiita-image-store.s3.amazonaws.com/0/8475/5a7f348c-3be0-1bd9-496e-c4dc7004c2ff.png)

これは一概に正解の形を作るのは難しそうです。この例で顧客と宿がそれぞれ、顧客サービスと宿サービスに分割されているとすると、お気に入りの持ち主は"顧客"なので、顧客サービスにもたせるのが良さそうです。

![image](https://qiita-image-store.s3.amazonaws.com/0/8475/3286a060-566f-a6b1-50bc-510011b72e22.png)

宿サービス側からお気に入りにアクセスしたい用途としては、

- お気に入りに多く登録されている宿のランキングを出す。
- お気に入りに登録されている数と予約アクションの数を比較し、コンバージョンが低い宿への改善提案をする。

あたりが考えられますが、これは"5.13 レポート"として取り扱えば良さそうです。


また、この「お気に入り」はそうなりにくい気がしますが、これが「リコメンド(おすすめの宿)」のような境界付けられたコンテキストとして認識される場合は、独立したサービスになることもあるでしょう。

![image](https://qiita-image-store.s3.amazonaws.com/0/8475/39e2fb57-b840-fe50-a3d9-eb9c6da887c2.png)


## イベント-リソース (E-R)

リソースが複数のイベントから参照される場合、共有することはできないので、リソースエンティティはどのサービスに持つかを決めなくてはなりません。

### リソースが静的(システム内で更新されることがほとんどない)

このケースでのリソースの持ち方は、"5.8 例:共有静的データ"に分かりやすく書いています。

1. 各サービスに重複してリソースエンティティをもちテーブルとして実装する。
2. 各サービスに重複してリソースエンティティをもち、プロパティファイルやEnumなどで実装しコードベースに入れる。
3. リソースエンティティを独立したサービスとする

あまり更新されないんだから重複してもつのは、十分現実的な解かと思います。

### リソースが動的(ガツガツ更新される)

これが一番難しいケースだと思います。キレイな形は取りづらく、リソースエンティティを境界付けられたコンテキストとして認識し、独立したサービスとして扱うことがそこそこ納得のいく落とし所になるかと思います。

"5.9　例:共有データ"の、倉庫と経理が顧客レコードに読み書きしているところから顧客サービスを切り出すのは、その代表的な例ですが、現実にはこんなのもサービスとして切り出さなきゃいけないの? というところが出てきやすい悩みどころになるでしょう。

静的・動的の判断基準も難しく、ある程度の試行錯誤は辞さない設計判断が必要になるでしょう。

## イベント-イベント (E-E)

イベント間の分割は、マイクロサービスサービス分割の主役です。イベントエンティティのまわりに業務の塊ができるので、業務の分割 = イベントエンティティの分割になります。

イベント間の関連は次のように、時系列で早い方のIDを遅い方のエンティティの外部キーとして作られます。

![image](https://qiita-image-store.s3.amazonaws.com/0/8475/4b7a8881-d46f-a55b-57ee-41e5714f8b93.png)

これをサービスに分割する場合は、"5.7 例:外部キー関係の削除"をするだけです。

![image](https://qiita-image-store.s3.amazonaws.com/0/8475/2dbb429b-40a4-194d-30c9-d1ca773d0327.png)

イベント間にn:1の関係があれば、対応表を間に置きます。

![image](https://qiita-image-store.s3.amazonaws.com/0/8475/30e5815b-5a41-d9cb-f4a9-3aa61d043f54.png)

この例の分割は、対応表を時系列の遅い方のエンティティが含まれるサービス側に持ってくるのが自然です。

![image](https://qiita-image-store.s3.amazonaws.com/0/8475/1993536d-4906-2372-798a-a08f1d848632.png)

ただし、イベントエンティティは「××ステータス」のような属性をもち、複数の種類のイベントを包含したモンスターエンティティになっていることが、実際の現場では多いので、これをイミュータブルに設計し直すことがまず必要です。

![slide](http://image.slidesharecdn.com/random-141019235040-conversion-gate01/95/-11-638.jpg)