私は最近、CQRS à la Greg Youngの記事を読みましたが、まだ CQRS について理解を深めようとしています。
入力の検証をどこで行うべきか、また、2 つの別々の場所で行わなければならない可能性があるかどうかについてはわかりません (そのため、Don't Repeat Yourself ルールに違反し、懸念の分離にも違反している可能性があります)。
次のアプリケーション アーキテクチャがあるとします。
# +--------------------+ ||
# | event store | ||
# +--------------------+ ||
# ^ | ||
# | events | ||
# | v
# +--------------------+ events +--------------------+
# | domain/ | ---------------------> | (denormalized) |
# | business objects | | query repository |
# +--------------------+ || +--------------------+
# ^ ^ ^ ^ ^ || |
# | | | | | || |
# +--------------------+ || |
# | command bus | || |
# +--------------------+ || |
# ^ |
# | +------------------+ |
# +------------ | user interface | <-----------+
# commands +------------------+ UI form data
ドメインは、コマンド バスの背後にある UI から隠されています。つまり、UI はコマンドをドメインに送信できるだけで、ドメイン オブジェクトに直接到達することはありません。
集約ルートがイベントに反応しているときに検証を行うのではなく、それ以前に検証を行う必要があります。
コマンドはドメイン内で (集約ルートによって) イベントに変換されます。これは、検証が行われる可能性のある場所の 1 つです。コマンドを実行できない場合、コマンドは対応するイベントに変換されません。代わりに、(たとえば) 例外がスローされ、コマンド バスを経由して UI に戻り、キャッチされます。
問題:
コマンドを実行できない場合は、UI で対応するボタンまたはメニュー項目を無効にしたいと考えています。しかし、途中でコマンドを送信する前に、コマンドが実行できるかどうかをどのように知ることができますか? クエリ側にはビジネス ロジックがまったく含まれていないため、ここでは役に立ちません。コマンド側でできることは、コマンドを送信することだけです。
可能な解決策:
任意のコマンドDoXに対して、対応するダミー コマンドCanDoXを導入します。これは実際には何も実行しませんが、コマンドXがエラーなしで実行できるかどうかをドメインにフィードバックさせます。
UI で (実際にはドメインに属している) いくつかの検証ロジックを複製します。
明らかに、2 番目の解決策は好ましくありません (関心の分離が不足しているため)。しかし、最初のものは本当に良いですか?