GRASPパターン①情報エキスパート&高凝集

# 前提
IT企業に転職する前に、デザインパターンを勉強している最中に、
このパターンの背景はいったいなんだ？と混乱していて、
SOLID原則に行きつく際に、たまたまこのGRASPパターンを通った。
その上で、デザインパターンを学んだらめちゃくちゃ理解が早かったので、
原理原則からトップダウンで学習されたい方は、是非設計原則とこのパターンを同時に学習されることを薦める。
この考え方は、マイクロサービスなどのアーキテクチャを考える際にもヒントになる指針が多いので、
是非とも常識にしていただけると今後楽である。
ちなみに以下のパターンは、単体で使うものではなく、ときには組み合わせで使うこともある。

今回は特に切っても切り離せない、情報エキスパートと高凝集の２つについて触れる。
この設計パターンは、高い生産性を出すためのタスクの割当設計の際にも必須の考え方である。

# 対象者と背景
主にこれを読んでほしいのは、設計する人々もそうだが、タスクの割当を決める【PMの方々】である。
コンウェイの法則について書かれた[チームトポロジー](https://amzn.asia/d/7qWQyfT)を読まれた方はお気づきと思うが、タスクの割当(持たせるべき情報も含む)の際に、以下の設計思想を意識せずにチーム設計してしまうと、マジで生産性が低いトラブルが続出してしまう。

それは開発者体験という品質を低下させる要因となり、最悪優秀な人材が離れてしまう事態まで引き起こしかねない。


# 情報エキスパート

## 概要説明
「その責務を全うするのに必要な情報を持つクラスに割り当てるべきである」という考え。
どういうことかというと、
【処理は、その処理が必要とするデータがある所に割り当てよ】ってこと。
つまりこれは
「関係性の高いデータとそのデータを必要とする処理を一か所にまとめよ」というカプセル化の手立てのことです。

## 開発者体験という観点では
チームへのタスクの割当でも重要なパターンです。
ここでしくじると、無関係な責務が混在してしまい、チームは度重なるコンテキストスイッチによって集中力が低下しやすく、成果物の品質低下にも繋がります。


## ドメイン貧血アンチパターン
ドメイン貧血という名前を目にしたことがある人、
またはドメイン貧血を引き起こしたことがある人はお分かりかもですが、
本来割り当てられるべき場所に処理が割り当てられていないと、症状を引き起こします。
その結果、ただ値を返すだけの謎のGetterロジックが出てきたりします。

ドメインに対する理解が浅いうちは、ドメイン貧血になってしまうのは避けられないですが、継続的なリファクタリング活動によって、最終的に正しい概念に対して割り当てるためにも情報エキスパートの考え方はマストです。
この考えがないと、何度DDDモデリングとリファクタリングをしても永遠に次の項目の高い凝集は実現ができないと思ってください。
改善のためのモデリングではなく、ただ単にコストがかかるだけのモデリングとならぬようにするためにも、この情報エキスパートは常識になるように身体にしみこませてください。

## カプセル化のための手段
処理が必要とするデータのない所に、その処理を割り当てないですよね？
ちなみにこの情報エキスパート、静的な概念モデルの動的な側面からの検証として、
シーケンス図を描きながら概念モデルの妥当性の検証と、
各概念に責務の割当をする際に、必ずマストで抑えておかないと正しくカプセル化ができません。

これができていない状況では、実体験としてほぼほぼ
その処理が必要とするデータをどっかからGetterのように引っ張ってくるような処理が高確率で発生してしまいます。
その状態では、データとデータを必要とする処理を纏めよというカプセル化の原則に反します。

## 補足 - マイクロサービスのデータ所有権の考察時 -
またこの情報エキスパートの考え方を常識にしておくと、
マイクロサービスのデータの所有権を考える際に、非常にヒントになると感じます。
そのテーブルに対して書き込み系をしている、密にアクセスしているサービスに対して所有権を割り当てるっていうのが、基本的な発想なので。

:::note warn
情報エキスパートの考え方のみではマイクロサービスのデータ所有権は考えられないけど、ヒントにはなるという意味です。
:::


# 高凝集

## 概要説明
「一つの責務を全うするのに必要最低限かつ、その責務に特化しているプロパティとメソッドのみで構成されるべきである」ということ。
つまりはこれ、単一責任原則にどれだけ近いか？てことを言っています。
もしも情報エキスパートを使って適切に処理の割当がされていないと、この高凝集を満たすことは難しいです。

## 低凝集アンチパターン

ラフスケッチですが、図のように１つのクラス内で
関連の非常に強いデータ群として緑の方のデータ群、
それとは別で
関連の非常に強いデータ群としてブルーの方のデータ群があったとする。

<img width="500" alt="カプセル化１.png (179.5 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/01/24/135213/1839b7fb-0926-4693-84b9-1ff63f9d481a.png">

この時に情報エキスパートに従って、適切に割り当てられた処理が図のように
なっている時、これは関連性の高いものが密になっている高凝集といえるだろうか？
もちろん、図を見てお分かりの通りNOだ。
だって、緑の方とブルーの方が疎な関係性になっている。
高凝集とは、１つのクラス内で密にデータや処理が関係しあっている状況である。

この場合には、
顧客という１つの概念を【顧客】と【顧客ボディサイズ】て２つに分解してあげるのが望ましいです。

:::note warn
一旦ここでは、顧客という曖昧な名前であることは保留とします。
:::

本来は下図のようになっているのが、もっとも高凝集な状態です。

<img width="400" alt="スクリーンショット (490).png (41.0 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/03/135213/1389ed5d-81fd-4641-9728-c08b84bb5eb6.png">

:::note warn
〇が属性、□が処理です。
緑の四角は、緑側の属性しか使っていない処理。
ブルー資格は、ブルーの方の属性しか使っていない処理。
赤い四角は、緑の方の属性とブルーの方の属性を両方使う処理だとします。
:::

ではなぜ下図では適切に情報エキスパートに従って適切に処理を割当たのにも関わらず、高凝集になっていないのであろうか？

<img width="500" alt="カプセル化１.png (179.5 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/01/24/135213/1839b7fb-0926-4693-84b9-1ff63f9d481a.png">

実はこれわたしも過去にやってしまったアンチパターンである。
そして体験したからこそ、以下の理由に集約されると思っている。

### 関係性が疎なデータを混ぜ込んでしまう
実は高凝集には２段階があると考えている。
その１段階目は概念モデリング時のデータのまとまりという静的側面でのまとめ方。
このフェーズにおける密なデータをまとめる作業時に、関係ないデータを混ぜ込んでしまうケース。

その状態では、どんなに情報エキスパートを適切に使いこなしても、不要なものが混ざった１つのクラスが完成してしまう。

### 静的なモデリングのみで決めにかかってしまう 
高凝集の２段階目が動的側面からの検証およびフィードバックだ。

基本的に概念モデリングのような静的側面からのみでモデル図を完成させてしまうのは危険だと私は思っている。
なぜならトランザクションの単位のチェック含めた、
動的側面からその概念モデルを検証してみないことにはわからないことが多々あるからだ。

たとえば下図のような１つのクラスを例にとって考えてみよう。

<img width="400" alt="スクリーンショット (490).png (41.0 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/03/135213/1389ed5d-81fd-4641-9728-c08b84bb5eb6.png">

この属性の区画に注目してみてほしい。
静的側面でのモデリングの時には、緑のデータ群とブルーのデータ群には密な関係性が見られなかったことを意味している。

たったそれだけでこれらは概念として分けると決め打ちにかかってしまってはいけない！！


## アンチパターンにはまらないための対処法

### データのまとまりに対して名前を付けてみる

概念モデルの段階で無関係なデータが混ざらないようにするためには様々な手法があるが、ここではその１つの手法を紹介する。

これはデータの側面での境界付けられたコンテキストである【データドメイン】の考え方を学ばれると、さらに理解が向上すると感じる。

まずは初期フェーズのDDDモデリング時には、ユビキタス言語を定義するためにスコープを定義した上で、関係性の高いデータの集合を列挙していっていると思う。
この時１つ１つのデータは意図が明確なほどわかりやすいのが理想である。
ユビキタス言語を集団でモデリングする際に、皆さんが意識してやられていると思う。

:::note alert
くれぐれも【顧客】みたいないかんようにも捉えられる名前を付けてはいけない。
:::

次に集めた関係が密であると思われるデータの集合に対して名前を付けてみるのだ。
データドメインに対して名前を付けるという作業である。
その際、その名前意図が唯一１つに名前が決まらないようであれば、無関係なデータが混ざっている可能性が非常に高い。

これが情報エキスパートに従っていたけど、高凝集を実現できないという最大の理由である。
データのまとめ方というフェーズにおいてそもそも無関係なものをまぜこんでいたということ。


### 概念モデルを動的側面のモデリングで検証
:::note info
一旦初期の概念モデルのフェーズでは、分けるか分けないのか不明だからとりあえず分けておくとかならOK。
ここでは、一旦概念モデル時に
【オーダーメイドスーツ購入者】と【購入者ボディサイズ】分けたと仮定して記述を進める。
:::

ビジネスフロー、動的側面からも考えてみてこの静的側面モデルを検証してみてからでないと、必要十分に安全なドメインモデルとは言い切れない。

そして処理を割り当てていった結果、下図のように赤い処理に関しては分けた概念の両方にまたがることが分かった。
<img width="600" alt="スクリーンショット (491).png (57.5 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/03/135213/c0455551-c21a-491d-bc0a-383d3448e170.png">

この時点で概念モデル時に分けた２つの概念はシーケンス図などを用いた動的側面から検証した際、実は１つに纏まっているべきだと判明したのである。
よって概念モデルを更新した結果、１つの高凝集を実現したクラスが出来上がるのである。

<img width="400" alt="スクリーンショット (490).png (41.0 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2024/03/03/135213/1389ed5d-81fd-4641-9728-c08b84bb5eb6.png">

### 責務に対して名前を考えてみる
情報エキスパートに従って割り当てた後に、その処理の集合に対して名前を考えてみる。
もしもこの際に名前が具体的に付けようがない、または複数の名前が付けられ得るって時には、その１つのクラスに複数の責務が集中しており、高凝集とはいえない状態である。

:::note warn
なんでもクラスの単位まできっちり単一責務になるように分けるのは過剰なリファクタリングをしていると言えなくもないので、同じパッケージ内に存在する別のクラスにあるべきものが１つに纏まってしまっている程度なら定性的にも許容範囲内であろう。
その場合でもパッケージ名は責務が明確になっていなければ、全く別のパッケージにあるべき責務が混在している可能性がある。
:::


# まとめ
概念モデリングの時に、このデータとこのデータ密な関係ともいえるし、
そうでないともいえるよなっていう時には、
迷う時間が無駄なので、一旦シーケンス図を描いて動的側面から検証してしまいましょう。

情報エキスパートと 高凝集は、２つ揃ってデータ隠蔽してカプセル化がやっと完成です。
モデリングとセットで是非とも常識といえるくらい練習してみてください。
というのも、クラスよりマクロなパッケージだのサービスとかの粒度のものとかでも、
この 高凝集という考え方が非常に重要になってくるからです。

詳しくは私が以前書いたコンポーネントの凝集原則を参照ください。

https://qiita.com/Kudo_panda/items/e143e6186bd840060d1c

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

https://qiita.com/Kudo_panda/items/62012f0c10e04b968074