名前の粒度を気にした名前設計

# 背景
先日、ソフトウェアアーキテクチャハードパーツのワークショップをやってきた。
そこで参加者の方から「〇〇管理とかって名前のクラス名やサービス名を付けたりしますか？」
と質問されて咄嗟に口から出てきた言葉が、自分でもだいぶしっくり来たので、
そのことについてお話ししていきたいと思います。
以下の内容は完全な我流になるため、信ぴょう性の保証はしません。

# 前提知識
ソフトウェアには【一様性】という特徴がある。
ある領域で適用できる思想は、他の領域でも適用できる思想という性質である。

# おさらい
まずパッケージには１つ以上のクラス群の集合やインターフェイスが入っている。
<img width="450" alt="貸出コンポーネント.png (19.4 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2023/07/07/135213/ada95bf5-2fe3-4780-b8e7-c0ae337a2ee3.png">
注：上図は正確な設計クラス図ではなく、あくまでも粒度の確認のための概念図である。


そしてまずは再利用性を考えずに1つのパッケージには、
メンテナンス観点から1つのパッケージ粒度の責務、変更理由になるように設計する。
この際の私なりのオススメポイントは、
【クラスやインターフェイスのまとめりに対して、唯一１つの抽象化した名前を付けること】である。　
この【唯一１つ】てのがポイントで複数の名前を付けられるような状態ってのは、
複数の責務、複数のコンテキストが混在したまとまりってことになってしまう。

別にその領域に対して、どこも変更頻度が低くて安定してきてたら
複数のコンテキスト含んでいることをあえて良しとするのもコストの観点から言えばOKといえるだろう。
しかしながら、開発初期段階の不確実な状況下ではオススメできない。

この考え方はサービスの責務という観点でも同様に考えていい。
しかしながら、サービスの粒度では凝集という責務観点だけで、その大きさを決めてはいけない。
それについては後述する。

## ループバックチェック
そして忘れてはいけないのが名前のチェック！！
パッケージに名前を付けたら、
①パッケージ名だけ見て、詳細(中身のクラス群)隠してどんなクラス群あるかな？
て予測する。　この推測とあってたら次は②へ

②クラス群だけ見てパッケージ名を付ける。
これで①②のループバックチェックの繰り返しで名前を洗練する。

# サービスとは
サービスは、１つ以上のパッケージの集合からなる。(下図を参照)
<img width="600" alt="ブロック定義図1.png (18.7 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2023/08/28/135213/d1774052-3a86-4106-ba25-6ebe7ab9ce48.png">
図の楕円で囲んだ領域がサービスである。

※一見すると、貸出ってサービスと、返却ってサービスの２つのコンテキストが
１つのサービスコンテキストに混ざってるんじゃないのかって思うけども、
もともとのドメインモデリングの結果、貸出と返却は密な結合であるため、
これらの領域を分割するメリットの方が少ないと判断したので、
１つのサービスコンテキストに貸出と返却が混ざっているのである。

## サービスに対する名前の付け方
ここで前提に書いた一様性を思い出してほしいのだが、
パッケージがクラス群のまとまりに対して、マクロな名前を付けたのと同じように
サービスもパッケージ群に対して、マクロな名前を付けるのと似たようなもん。

なのでサービスも、パッケージのまとまりに対して
【たった１つの名前を付けたれるかどうか】がサービスのもつ責務の個数といえるし、
ここでも名前のループバックチェック流行っておいた方がいい。

しかしながら、サービスは責務の観点だけで分離してしまうと、
耐障害性やセキュリティ、トランザクションなどといった
他の観点では分けない方がいい場合もあるので、あえて責務が複数なのを許容することがあることには注意したい。

# 本題
さて、本題の「〇〇管理」という名前をつけるのか？というものだが、
わたしは「絶対につけない」と即答した。理由は以下である。
・モデリングをしてて【顧客管理】【貸出管理】とかってパーツがあったら
それはそもそもクラスの粒度のものなのか？
それともパッケージの粒度のものなのか？
サービスの粒度のものなのか？
そもそもの責務の内容はなんなのか？　という混乱を招くからだ。
名前に一貫性がないのはそのパーツがどの粒度なのかわからなくなる。
(上記の図では日本語名にしてたのと図からわかるので気にしてないが)

すると、どこのパッケージにも属さずに、
サービス直下に置かれたクラス(孤立クラスという)が出現する可能性が出てきてしまい、
クラスとパッケージがまさかの同じ粒度で扱われてしまうっていうトラブルが発生しかねない。

## 名前空間設計
そこで構造が崩れないように名前空間に一貫性を必ず持たせる方針を徹底することで
構造が崩れるのを予防する。
この時コードだけを見ていても思い描きづらいからラフでもいいから下図のように
図を描いてみることをオススメする。
<img width="600" alt="貸出サービス.jpg (45.6 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2023/07/07/135213/ca479843-fc20-4020-b22a-75d8348aee57.jpg">


<img width="500" alt="貸出コンポーネント.png (19.4 kB)" src="https://img.esa.io/uploads/production/attachments/5827/2023/07/07/135213/74104e7f-1e88-4d24-99f6-03b976aed72c.png">

たとえば、貸出パッケージを指したい時に
libraryBookRentalService. rentalというように
サービス名. パッケージ名　と一貫性を持たせるようにして、
決して貸出パッケージを指したい時に　rental　とだけ呼ばないこと。
rentalだけだとこれ見ただけの人はサービスのことを指してるのか？
それともパッケージ粒度のものを指してるのかがわからない。

わからないと自覚できてるならまだいいが、わからないことがわかっていない結果、
本来はパッケージ粒度のものを変更してもらいたかったにもかかわらず、
間違ってサービス粒度のものを変更されてしまうなんてことに繋がりかねない。


## オーケストレーター
「サービスの流れを制御するオーケストレータには〇〇サービス管理、
という名前を付けることあるのかな～？」なんて話題も出たが、
これもやはり上記と似たような理由でNGとした方がいいように思う。

せめて第三者が名前だけを見て
「あ！これは名前から察するにサービス全体の流れを制御する役割のサービスだな」
とわかるように【〇〇オーケストレータ】と名前を付けるのが望ましい。


# まとめ
以上をまとめると、名前を見た瞬間にその対象が
サービスの粒度？パッケージ粒度？クラスの粒度なのか？の特定が名前見ただけで可能であり、
かつ
責務が明確でわかりやすいことが名前設計において非常に重要であると言える。