Runner in the High

技術のことをかくこころみ

クリーンアーキテクチャのUsecaseはなぜControllerへ値を返すのではなくOutput PortとしてPresenterを呼び出すのか

何を言っているのかと言うと、みんな大好きクリーンアーキテクチャの右下に図示されているFlow of Controlのこと。 https://blog.tai2.net/images/CleanArchitecture.jpg 黒線が引かれているということは、つまりUsecaseの中でOutput Portのインターフェイスを持つPresenterの関数なりが最終的に実行されるということである。

ここで湧き上がってくる疑念は「UsecaseがPresenterを呼び出さなくてもControllerに返り値とかで値を返して、Controller経由でPresenterに渡して実行しても同じなんじゃないの?」である。つまりOutput Portというインターフェイスそのものを撤廃してControllerにPresenterを使わせるアイデアである。たしかに、仮にこの方針で行ったとしても依存の方向が壊されることはない。

Software Engineeringでは同様の質問がかなり盛り上がっている。同じようなことはみんな考えるのである。この質問についている回答群はどれもかなり興味深いので、ぜひすべての回答に目を通しておきたい。 softwareengineering.stackexchange.com

UsecaseがPresenterを呼び出すメリットは"UsecaseがPresenterをどう使うかを制御できること"

結論としてメリットはこれに尽きる。

ひとつの例として、もしもPresenterの呼び出しがControllerサイドですべて行われるとしたら、Usecaseの呼び出しののちにPresenterの呼び出しを行わないようなコードが書かれてしまっても、コードレビューで防ぐ以外の方法がない。しかしUsecaseでPresenterを利用するということが実装上約束されていれば、基盤ごと破壊されない限りはUsecaseの呼び出しとPresenterの呼び出しをセットにして実装のミスを防ぐことができる。

また別の例として、Presenterが特定の条件によって呼ばれたり呼ばれなかったり、また複数のPresenterが条件によって呼び分けられたり、呼び出し順序にルールを与える実装が必要になったりするケースでは、もはやアダプタ層であるControllerがここまでの知識を責務として持つのはおかしい。したがってドメイン層であるUsecaseにこのような知識が存在しているほうが自然であると言える。

つまり、PresenterをUsecaseが呼び出すところまでをドメイン層の責務としてカバーすることで、実装のミスとドメインロジックの流出を防いだ堅牢なものにすることができている。これこそまさに原典なりのあるべき姿であると言える。

返り値による表現にアドバンテージがあるケース

とはいえUsecaseがControllerに返り値を与えるパターンが有利なのは、コード表現としての簡潔さやシンプルさが求められる場合である。

さほど規模の大きくないWebアプリケーションを作っている限りは、ほとんどの場合RESTやJSONRPCなどを素直にレンダリングするだけのPresenterで溢れるだろう。その場合にわざわざOutput Portのようなインターフェイスを作って完璧にFlow of Controlを守る価値が果たしてあるのかと言われると疑問が残る。もちろん未来のことは分からないが、実装を差し替えたりテストしたりする必要もさほどなければ、存在する意味もない。

また、実際にやってみると分かるが、ウェブ・フレームワークによってはクリーンアーキテクチャのPresenterという存在との相性が悪いケースがある。クリーンアーキテクチャではPresenterはコールバック的な扱いとしてUsecaseから利用されるが、フレームワークによってはリクエストハンドラの関数の返り値としてレスポンスのデータを返さないと処理が正しく終えられないものがある。UsecaseはControllerの中で実行されてもそれ自体は何も値を返さないため、このタイプのフレームワークとは相性が悪い。こうなると、例えばScalaで言うところのPromiseなどを使って手の込んだ実装をせねばならず、まあまあめんどくさい。

この相性の悪さについてはnrsさんも以下の記事で言及している nrslib.com

加えて、ボブおじさんの言うPresenterは我々がAPIサーバを作る際にイメージするそれよりも、もう少し重厚なHTMLのDOM構造のレンダリングなどに相当するもののようである。

例えばクリーンアーキテクチャの本ではHumble Objectなどのパターンなどが言及されているが、それこそ今の時代のフロントエンド文脈で言う「画面と状態の分離」とほぼ同じことを言っているくらいには、いわゆるフロントエンド領域の設計にまで踏み込んでいる。今現在一般的な、フロントエンド・アプリケーションをSPAとして作り、サーバはプレゼンター層でJSONを毎度返すだけというようなケースではOutput Portのような抽象化は必ずしも必要ではない場合があるし、むしろ使わないほうがポジティブなこともあると言える。

余談

この記事は、現在弊社にインターンで来ている学生とタイトル通りのディスカッションをしたので、ふと思い出して書いてみた。なんでもまずは原典にあたるのは大事であるが、とはいえ「ボブおじさんが言ってるんだからそうするのが当たり前」という考え方はあまりにも思考停止すぎる。アプリケーション設計にはたったひとつの正解なんてないので、こうやって常に疑問を持ちながら探し歩くほかない。

Clean Architecture 達人に学ぶソフトウェアの構造と設計

Clean Architecture 達人に学ぶソフトウェアの構造と設計