web-dev-qa-db-ja.com

「ビジネスロジックレイヤー」はMVCアプリケーションにどこに適合しますか?

最初に、だれかがだまされて叫ぶ前に、私はそれを簡単なタイトルで要約するのに苦労しました。別のタイトルは、「ドメインモデルとMVCモデルの違いは何ですか?」または「モデルとは何ですか?」

概念的には、モデルはビューとコントローラーが使用するデータであると理解しています。それを超えて、モデルを構成するものについては非常に多くの異なる意見があるようです。ドメインモデル、アプリモデル、ビューモデル、サービスモデルなどとは.

たとえば、最近リポジトリのパターンについて尋ねた質問で、リポジトリがモデルの一部であると指摘されました。ただし、モデルを永続性モデルおよびビジネスロジック層から分離する必要があるという他の意見を読みました。結局のところ、Repositoryパターンは、モデルから具体的な永続化メソッドを切り離すことを想定していませんか?他の人は、ドメインモデルとMVCモデルには違いがあると言います。

簡単な例を見てみましょう。 MVCデフォルトプロジェクトに含まれているAccountController。含まれているアカウントコードのデザインが悪い、SRPに違反しているなどの意見をいくつか読みました。MVCアプリケーションの「適切な」メンバーシップモデルを設計する場合、それはどうなりますか。

モデルからASP.NETサービス(メンバーシッププロバイダー、ロールプロバイダーなど)をどのように分離しますか?それとも、あなたはまったくですか?

私の見方では、モデルは「純粋」で、おそらく検証ロジックを備えている必要がありますが、ビジネスルール(検証以外)から分離する必要があります。たとえば、新しいアカウントの作成時に誰かにメールを送信する必要があるというビジネスルールがあるとします。私の見解では、それは実際にはモデルに属していません。それはどこに属しますか?

この問題に光を当てたい人はいますか?

85

私がそれをやった方法-そしてそれが正しいか間違っていると言っているのではない、私は私のビュー、そして私のビューに適用するモデルを持つことです。このモデルには、データ注釈や検証ルールなど、自分のビューに関連するもののみが含まれています。コントローラーには、モデルを構築するためのロジックのみが格納されます。すべてのビジネスロジックを収容するサービスレイヤーがあります。コントローラーがサービス層を呼び出します。それを超えて私のリポジトリ層です。

私のドメインオブジェクトは個別に(実際には独自のプロジェクトに)格納されます。独自のデータ注釈と検証ルールがあります。リポジトリは、データベースに保存する前にドメイン内のオブジェクトを検証します。ドメイン内のすべてのオブジェクトは、検証が組み込まれた基本クラスから継承するため、リポジトリは汎用であり、すべてを検証します(そして、基本クラスから継承する必要があります)。

2セットのモデルを作成することはコードの重複であり、ある程度までであると考えるかもしれません。しかし、ドメインオブジェクトがビューに適していない完全に合理的なインスタンスがあります。

適切な例は、クレジットカードを使用する場合です。支払いを処理するときにcvvを要求する必要がありますが、cvvを保存できません(これを行うには50,000ドルの罰金です)。しかし、私はあなたにあなたのクレジットカードを編集できるようにしたい-アドレス、名前、または有効期限の変更。ただし、編集時に番号やcvvを提供することはありません。また、ページのプレーンテキストにクレジットカード番号を記載することはありません。私のドメインには、新しいクレジットカードを保存するために必要なこれらの値がありますが、私の編集モデルにはカード番号やcvvも含まれていません。

非常に多くのレイヤーのもう1つの利点は、正しく設計されていれば、構造マップまたは別のIoCコンテナーを使用して、アプリケーションに悪影響を与えることなくピースを交換できることです。

私の意見では、コントローラーコードはビューを対象としたコードのみである必要があります。これを表示、非表示など。サービスレイヤーは、アプリのビジネスロジックを格納する必要があります。すべてを1か所にまとめるのが好きなので、ビジネスルールを簡単に変更したり微調整したりできます。リポジトリレイヤーは比較的愚かである必要があります-ビジネスロジックがなく、データを照会してドメインオブジェクトを返すだけです。ビューモデルをドメインモデルから分離することにより、カスタム検証ルールに関してはるかに柔軟になります。また、すべてのデータを非表示フィールドのビューにダンプし、クライアントとサーバー間で前後にプッシュする(またはバックエンドで再構築する)必要がないことも意味します。ビューモデルには、ビューに関連する情報のみが格納されます。ビューロジックまたはカウントまたは列挙型のブール値を持つようにカスタマイズして、ビュー自体が次のような複雑なロジックステートメントで散らからないようにすることができます。

<% if (!String.IsNullOrEmpty(Model.SomeObject.SomeProperty) && 
    Model.SomeObject.SomeInt == 3 && ...) { %>

すべてが広がっていて重層になっているように見えますが、このように設計されることを目的としています。完璧ですか?あんまり。しかし、コントローラーからリポジトリーを呼び出し、コントローラー、リポジトリー、およびモデルにビジネスロジックを混在させる過去のデザインよりも、私はそれを好みます。

69
Josh

ビュー(ページ)、コントローラー、サービス、データオブジェクト(モデル)がある従来のWebアプリケーション構造にMVC要素がどのように正確に適合するのか、よく疑問に思いました。あなたが言ったように、それの多くのバージョンがあります。

混乱は、上記の広く受け入れられているアーキテクチャが原因であると考えています。このアーキテクチャでは、「貧血ドメインモデル」(疑惑)アンチパターンを使用しています。貧血データモデルの「アンチパターン性」についてはあまり詳しく説明しません(私の努力を見て、物事を説明できます here (Javaベースですが、どの言語にも関連します) )。しかし、要するに、これはモデルがデータのみを保持し、ビジネスロジックがサービス/マネージャーに配置されることを意味します。

しかし、 ドメイン駆動型アーキテクチャ があり、ドメインオブジェクトは、ステートロジックとビジネスロジックの両方があると予想される方法であると仮定しましょう。そして、このドメイン主導の観点では、次のことが行われます。

  • ビューはUIです
  • コントローラーはUIの入力を収集し、モデルのメソッドを呼び出し、UIに応答を返します
  • モデルはビジネスコンポーネントであり、データを保持しますが、ビジネスロジックも持ちます。

私はそれがあなたの主な質問に答えると思います。リポジトリレイヤーなどのレイヤーを追加すると、事態は複雑になります。多くの場合、モデルに配置されたビジネスロジックによって呼び出されることをお勧めします(したがって、各ドメインオブジェクトにはリポジトリへの参照があります)。私がリンクした私の記事では、これはベストプラクティスではないと主張します。そして、実際には、サービス層を持つことは悪いことではありません。ちなみに、ドメインドリブンデザインはサービスレイヤーを除外しませんが、「薄く」、ドメインオブジェクトを調整するだけであると考えられます(ビジネスロジックはありません)。

広く採用されている貧弱なデータモデルのパラダイム(良いか悪いか)では、モデルはサービスレイヤーとデータオブジェクトの両方になります。

17
Bozho

私の考えでは、

モデル-

ビジネスロジックを含めるべきではなく、プラグ可能(WCFのようなシナリオ)でなければなりません。ビューにバインドするために使用されるため、プロパティが必要です。

ビジネスの論理 -

「ドメインサービスレイヤー」に配置する必要があり、完全に別のレイヤーです。また、ここにもう1つレイヤー「アプリケーションサービス」を追加します。

App Servicesはドメインサービスレイヤーと通信してビジネスロジックを適用し、最後にモデルを返します。

そのため、コントローラーはアプリケーションサービスにモデルを要求し、フローは次のようになります。

    Controller->Application Services(using domain services)->Model
3
paragy

MVCパターンとAsp.netフレームワークは、モデルがどうあるべきかを区別しません。

MS独自の例には、モデルに永続性クラスが含まれています。モデルへのメンバーシップに関する質問。これは依存します。モデルのクラスは何かによって所有されていますか?ログインした人と表示されるデータの間にリンクがありますか?編集可能な権限システムのデータ部分のフィルタリングはありますか?ドメインのオブジェクト部分を最後に更新または編集したのは、他の誰かがそれを見る必要があるか、またはバックエンドのサポートのために何かを必要としているのですか?

電子メールの例も依存しています。ドメインイベントまたは特にイベントに精通していますか?メールを送信する別のサービスはありますか?電子メールを送信する行為はドメインの一部ですか、それともシステムの範囲外のアプリケーションレベルの問題ですか? UIは、メールが正常に送信されたかどうかを知る必要がありますか?送信に失敗したメールは再試行が必要ですか?送信された電子メールのコンテンツは、サポートまたは顧客サービスの要件のために保存する必要がありますか?

これらのタイプの質問は非常に広範かつ主観的ですが、あなたとあなたに投票した誰もがこれを理解できるように私は答えています。

要件/タイムライン/リソースはすべて、システムのアーキテクチャに流れ込みます。 収益モデル でも効果があります。また、撮影するパターンを考慮する必要があります。 DDDは、persistence-as-modelアプリケーションとは大きく異なり、その間のすべてのスロップは特定のアプリでも有効です。アプリをテストするために撮影していますか?これにはすべて効果があります。

2
John Farrell