3

私は scott millett による本専門的な asp.net デザイン パターンを読みました。彼の例では、彼は Validate() メソッド内でビジネス ロジックを検証し、壊れたルールが壊れている場合はコレクションに追加され、サービス レイヤーはメソッドを呼び出しますGetBrokenRules() と呼ばれるモデル。

現在、DDD に関するいくつかの本、ブログ、フォーラムも読んでおり、DDD ではオブジェクトが無効な状態になることは決してないと書かれています。

私が見た DDD に関する例はすべて、ビジネス ルールが破られたときに、破られたルールのコレクションを返すのではなく、エラーをスローします。私は scott millett による最新のソース コードをダウンロードしましたが、彼はコードを変更して、壊れたルールのリストを返す代わりにエラーをスローするようにしました。他の DDD コード サンプルでも同じアプローチを見てきました。

私は、エラーをスローするとリソースが高価であり、エラーをスローするのではなく、現在のように壊れたルールのコレクションを返す必要があると考えているチーム メンバーと議論してます。ただし、これを行うと、危険なデータが含まれているため無効なオブジェクトが渡され、最後に壊れたルールをチェックするだけです。

私は、この件に関して他の人々の意見がどうであるかを考えていました。ビジネス ルールが失敗したらすぐにエラーをスローする必要がありますか? もしそうなら、そうすることの長所と短所を強調できますか. .net でリソースを消費するスロー エラーがどのように発生するかはわかりません。そのため、その点に反論することはできませんが、これはコーディング標準ではなく、個人的な意見の問題でもあるのではないかと考えていました。

マイク

4

4 に答える 4

4

例外は、実際にスローされた場合にのみコストがかかります。

事前にロジックを検証する必要があるため、例外はほとんどなく、その間にあるはずです。そうでない場合、あなたはそれを間違っています。

例外は、モデルが無効な状態にあることを通知するための最善のメカニズムです。アプリケーションを終了しない場合は、明示的な処理が必要です。

エラーコレクション/戻り値を使用することは、これらが使用コードによって無視される可能性があるため(そして多くの場合そうなります)、良い習慣ではありません。

于 2012-04-17T11:26:43.120 に答える
1

非常に良い議論。古い議論の主題を生き返らせます。私はいくつかのアプローチをテストし、混合が良い代替手段になる可能性があることを発見しました. サービス メソッドまたは ctor への入力パラメーターを検証するときに、例外を使用します。バリデーターを訪問者パターンと一緒に使用して、検証の知識がエンティティの責任の一部ではない場合、ドメイン エンティティを調べます。Persistence-ignorance-religion (私はそうです) の一部である場合は、インフラストラクチャ層にあるバリデーターを使用して、永続化できるかどうかを検証できます (または、アダプターを介して別のシステムにエクスポートすることもできます...)。ただし、エンティティを無効な状態にすることを困難にするためだけに、エンティティでパブリック自動プロパティをほとんど使用しません。また、エンティティが独自のドメイン スコープ/責任に関して自身を検証できるようにします (ここでは SRP に従おうとしています...)。

他の部分/レイヤーに通知するための一般的な解決策として例外をスローすることは、すべての場合に最適であるとは限りませんが、場合によっては最適である可能性があります。

/乾杯

于 2012-04-18T06:23:20.480 に答える
1

@Odedが言ったことは完全に有効です。

ただし、例外をスローせず、無効なオブジェクトを渡さずに、検証を処理する別の方法があります。簡単に言えば、常にファクトリ メソッドを介してオブジェクトを作成します。すべてが正常な場合はインスタンスが返され、それ以外の場合は null が返されます。もちろん、これは、オブジェクトを作成するときに一度 null をチェックする必要があることを意味しますが、それだけです。ファクトリ メソッド (サービスの一部にすることができます) は、ファクトリがエラーを設定できる IValidationDictionary (BCL インターフェイスではない) を引数として取ることができます。ただし、ここでは、ユーザーからの入力データ (フォーマットの検証) についてのみ説明します。ここにはビジネス ルールはありません。状態が無効なコンテキストでオブジェクトが使用される場合は、例外をスローする必要があります。

オブジェクトまたはその集約ルートに CanDoThat() のようなメソッドを設定することで、その 99% を回避できます。If object.CanDoThat(context) はそれを行い、例外を回避します。ただし、並行性のためにその間に状況が変化した場合、例外がトリガーされる可能性があります。

私は通常、次のワークフローを持っています。

  • コントローラー層 (アプリの破損防止層) でのユーザー入力の検証。ここでは、データの書式設定のみが処理されます。
  • データが有効になると、転送されて処理されます (通常はコマンド ハンドラー経由)。
  • 処理するとき、特定のアクションを実行できるかどうかを集約ルートに尋ねます。それができれば、すべてが前進します。
  • できない場合は、次の 2 つのケースがあります。

    1. バグのような何かが間違っている可能性が高いため、ここでは例外が適切です (99% のケース)。
    2. そのコンテキストでは有効な応答であるため、単に無視されます。
  • もちろん、集約ルート レベルではすべて問題ない場合もありますが、データベースの制約のためにリポジトリ レベルでは失敗します。これは、リポジトリが例外をスローすることを意味しますが、これは私が処理します (そのケースが発生する可能性があるため)。ユーザーが応答を期待している場合は、特定の例外をスローしてエラーを通知し、ビューの ModelState を設定します。

コード フローを制御するために例外を使用しているように見えますが、そうではありません。データベースが制約違反の例外をスローすることを期待していますが、それは例外的なケースです。それは毎回発生するわけではなく、ユーザーが回避できる状況ではないからです。最初の例外は永続性に関連するものであるため、次に特定の例外をスローしていますが、コントローラーはそれを認識していないため、その例外的な状態を理解できる方法で伝える必要があります。

わかりました、長い回答ですが、いくつかのエラーは予想されますが、それでも例外であり、そのように扱う必要があるという考えです。ただし、ipnut データにフォーマット検証エラーがある場合、または入力データが特定の方法で無効である場合は、最初の破損対策レイヤーで処理する必要があり、コントローラー自体と例外は必要ありません。コントローラーは、無効な入力を進めないようにする必要があります。それが進行する場合、それはバグであり、例外的な状況です。

うまくいけば、私はあまり混乱していませんでした:)

于 2012-04-17T12:34:23.020 に答える
0

壊れたルールのリストで例外をスローしないのはなぜですか?

ルールの作成、ルールの処理方法の決定、ユーザーへのエラーの通知、およびその間のすべてのネットワーク トラフィックのコストと比較すると、例外のコストはほとんどかかりません。

于 2012-04-18T02:07:23.200 に答える