ビジネスロジックバリデーションの例外の種類

ビジネスロジックのバリデーションは DomainException を継承したものを投げる

バリューオブジェクトやエンティティやドメインサービスで投げられることの多いビジネスロジックのバリデーションの例外ですが、
その例外はphpstormのdocコメントにて@throwsが必要な(Exceptionをextendしたもの)で投げるべきかコメントが必要ないDomainExceptionを継承したもので投げるべきかを悩んでいたのですが、
DomainExceptionを継承したもので投げるべきだと私の中で答えがでました。

入力フォームなどでビジネスロジックのバリデーションの例外をキャッチして、Viewに表示したいことがあり、@throwsが必要な例外だとcatchすることが明示的なのでそっちかなと思ったのですが。
下記のスライドを見てビジネスロジックの例外を投げるクラスからしたら、システムを落とすように例外を投げることを推奨していたので DomainException を継承してビジネスロジックのバリデーションは投げるべきだなと決めました。
では、落とすように例外をなげたらそれをキャッチしてはいけないかというとそうではなくて、アーキテクチャ/フレームワーク等では逆に落とさないようにcatchすることを推奨しています。

https://speakerdeck.com/twada/php-conference-2016?slide=56
こちらのスライドである通り、

1
2
3
ミクロでは正当性を重視し、マクロでは堅牢性を重視する
個々のクラスは正当性を重視し、堅牢性はアーキテクチャ/フレームワーク等で保証するのがオススメ。
例:個々のクラスはfail fast原則で書き、Webフレームワークやグローバルハンドラがキャッチして500エラー画面等を出す責務を負う

とありました。
正当性と堅牢性とか意味が分からなければ、このページの5ページ前ぐらいから読むといいと思います。

また、Viewに表示したいから@throwsが必要な例外を投げるとかドメインがViewに配慮する考え方もおかしいですよね。

ビジネスロジックのエラーは例外的状況である

そもそもビジネスロジックのバリデーションで例外を投げるのはおかしい、
例外は例外的な状況にだけ利用するべきだと意見されたことがあるのですが、
それは、例外的な状況の縮小解釈です。
https://qiita.com/kata/items/bd129ba6113a61126389#%E9%A0%85%E7%9B%AE57-%E4%BE%8B%E5%A4%96%E7%9A%84%E7%8A%B6%E6%85%8B%E3%81%AB%E3%81%A0%E3%81%91%E4%BE%8B%E5%A4%96%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B
に書かれている通り、

1
ArrayIndexOutOfBoundsExceptionを使用して配列のループ処理の脱出するなどアホな事はしない

このレベルでの状況で例外を使うなということで、ビジネスロジックのバリデーションエラーについては例外的状況と捉えてよいと考えます。

また、こちらのスライドの14ページに
https://www.slideshare.net/t_wada/exception-design-by-contract

1
2
3
例外は例外的な状況にだけ利用するべき
例外は、その名が示す通り、例外的状況に対してのみ使用するべきです。
通常の制御フローにたいしては、決して使用すべきではありません。

とありますが、この通常の制御フローを示すものも前のページでのループを抜ける制御のレベルで使うなといっていますし。
15ページの

1
2
3
例外は例外的な問題のみに使用すること
「すべての例外ハンドラーを除去しても、このプログラムは動作することができるだろうか?」
答えが「ノー」であれば、例外では無い状況下で例外が使われている

についても、ビジネスロジックの例外のキャッチをすべて行わなくても動作することはできます。
29ページにて

1
2
技術的例外とビジネス例外を明確に区別する
技術的例外は貫通させてフレームワークに任せる。ビジネス例外は準正常系なので呼び出し側で対処する

ビジネスロジックのバリデーションの例外を準正常系として利用することを認めています。