ユースケースレイヤーの実装はユースケースを洗い出してから

何を当たり前のことを、みたいなタイトルだが最近実感していることなので。

レイヤードアーキテクチャ、ヘキサゴナルアーキテクチャ、オニオンアーキテクチャはアプリケーション固有のルールを実装するレイヤーを持つ。このレイヤーはアーキテクチャによって、アプリケーションレイヤー、ユースケースレイヤー、サービスレイヤーなどと呼び名は違うが関心事は同じである。

このレイヤーの粒度や責務はどのように設計するのかを明確にすることができていなく、モヤモヤしていたが何となく自分の中の正解が見えてきた。

まず、よくあるパターンで自分も過去そのように設計してしまっていたパターンは、ドメインモデルのCRUDを実装するレイヤーにしてしまうことだ。汎用性があって、一見良い実装に見える。が、この実装だと一つ上のレイヤーであるプレゼンテーションレイヤー(ハンドラーとかコントローラー)で複数のユースケースを呼び出す設計になってしまう。ユースケースの呼び出しの順序の制御であったりどのユースケースを呼び出すか?といった関心事がユースケースから漏れ出て、複数のレイヤーに散らばってしまう。

では、どうするか。まずはアプリケーションのユースケースを明確にするのが良い。アプリケーションのアクターと、そのアクターがアプリケーションで実現できることを洗い出して列挙する。実現できることとユースケースが1対1になる。もちろんモデルのCRUDになるユースケースも出てくるのだが、たまたまそうなっているくらいの認識を持っておく。このように実装することによってプレゼンテーションレイヤーは、最低限のバリデーションとユースケースの入力/出力と外部の入力/出力の調整だけを担うようになり、必ず一つのユースケースだけを呼び出すようになる。(一つのユースケースが複数のプレゼンテーションレイヤーから呼ばれることはある。)複数のユースケースで重複した処理が出てくるかとは思うが、呼び出し順序の制御であれば重複したままにしておく。なぜならその制御がそのユースケースの責務であり、重複しているのは偶々であるからだ。単一のドメインモデルを用いたロジックはドメインモデルのレイヤーに実装して使い回し、複数のドメインモデルを組み合わせたロジックは、ドメインサービスレイヤーに実装する。今のところ、この実装が一番しっくり来るし使い回しやすく、変更の影響が分かりやすいレイヤ分けだと思っている。