RESTful APIは貧弱なドメインモデルを奨励する傾向がありますか?


34

ドメイン駆動設計とRESTの両方をサービス指向アーキテクチャに適用しようとしているプロジェクトに取り組んでいます。100%REST準拠について心配する必要はありません。リソース指向のHTTP API(〜RichardsonのREST成熟度モデルのレベル2)を構築しようとしていると言った方が良いでしょう。それでも、RPCスタイルのHTTPリクエストの使用は避けようとしています。つまり、例えば、POSTdo を使用するのではなく、RFC2616に従ってHTTP動詞を実装しようとしますIsPostalAddressValid(...)

ただし、これに重点を置くことは、ドメイン駆動設計を適用しようとする試みを犠牲にしているようです。だけではGETPOSTPUTDELETEおよびその他のいくつかのほとんど使用されない方法で、私たちは汚いサービスを構築する傾向があり、そして汚いサービスは、貧血のドメインモデルを持っている傾向があります。

POST:データを受信し、検証し、データにダンプします。GET:データを取得して返します。実際のビジネスロジックはありません。また、サービス間でメッセージ(イベント)を使用しますが、ビジネスロジックのほとんどは最終的にその周りに構築されるように思われます。

RESTとDDDは何らかのレベルで緊張していますか?(または、ここで何かを誤解していますか?他の何か間違っているのでしょうか?)RPCスタイルのHTTP呼び出しを回避しながら、サービス指向アーキテクチャで強力なドメインモデルを構築することは可能ですか?


1
POSTは、意図的に「意図的にあいまい」になるように設計されました POSTの結果は実装固有です。Twitterや他のAPIデザイナーが行うことを実行できず、独自の特定の要件に従ってAPIの非CRUD部分で各POSTメソッドを定義することを妨げるものは何ですか?
ロバートハーヴェイ

@RobertHarvey POSTは作成物として解釈しました。再び標準を見ると、おそらくそれは過度に単純化されています。たとえば、POSTはIsPostalAddressValid(...)、「フォームを送信した結果などのデータブロックをデータ処理プロセスに提供する」に適合すると思いますか?
カザーク

これは、CREATE動詞(および、その点でUPDATE動詞)がないためです。私は、これらの動詞が(何らかの理由で)標準から欠落していると主張しているため、「他のすべて」のためにPOSTを選択する必要があります。この場合の「データ処理プロセス」は、住所を調べて、その分析の結果に対応する値を返すプロセスです。
ロバートハーヴェイ

1
@RobertHarvey:POSTとPUT / PATCHは単にあなたが望んでいたCREATEとUPDATEの動詞であると信じています。動詞が非RESTfulなデザインであってもある程度意味をなすように、名前が異なるだけです。
ライライアン

@LieRyan:それを認めます。CRUDは定義上貧血データモデルを意味すると思います。たとえば、MVCのMにいる場合、何らかの動作を実行できますが、異種システム間では実行できません。CRUD以外のすべてについては、POSTが必要です。
ロバートハーヴェイ

回答:


38

マーティン・ファウラーの分散システムに関する最初の法則:「オブジェクトを配布しないでください!」リモートインターフェイスは粗く、内部インターフェイスは細かくする必要があります。多くの場合、リッチドメインモデルは境界付きコンテキスト内でのみ適用されます

REST APIは、両方とも独自の内部モデルを持つ2つの異なるコンテキストを分離します。コンテキストは、「貧弱な」オブジェクト(DTO)を使用して、粗視化インターフェース(REST API)を介して通信します。

あなたの場合、コンテキストをREST APIである境界に広げようとしているように聞こえます。これにより、きめの細かいリモートインターフェイスまたは貧弱なモデルが作成される可能性があります。プロジェクトによっては、問題になる場合とそうでない場合があります。


1
Fowlerは多くの良い考えを持っていますが、元のEJB仕様と実装がどんな惨事であったかを忘れないでください。その後、彼らはgetName()のようなすべてのマイナーな操作に対する低レベルのメソッド呼び出しがネットワーク/負荷の悪夢であると判断しました。粒度の粗いインターフェイスは、エンティティグラフ/メッセージ全体が動詞と名詞のコンテキストで送受信されるという概念になります。
ダレルティーグ14年

9

POSTは、意図的に「意図的にあいまい」になるように設計されました POSTの結果は実装固有です。Twitterや他のAPIデザイナーが行うことを実行できず、独自の特定の要件に従ってAPIの非CRUD部分で各POSTメソッドを定義することを妨げるものは何ですか?POSTはキャッチオール動詞です。実行したい操作に他の動詞がどれも適切でない場合に使用します。

別の言い方をすれば、「「スマート」オブジェクトはRPCスタイルの設計を促進するのか?」と同じように質問することができます マーティン・ファウラー(「Anemic Domain Model」という用語を生み出した)でさえ、裸のDTOにはいくつかの利点があることを認めています。

ドメインオブジェクトに動作を設定することは、レイヤ化を使用して永続性やプレゼンテーションの責任などのドメインロジックを分離するという堅実なアプローチと矛盾するべきではありません。ドメインオブジェクトにあるべきロジックは、ドメインロジック -検証、計算、ビジネスルール-好きなものです。

Richardson Maturity Modelについては、「Anemic Domain Models」について気にすることなくレベル3に到達できます。動作をブラウザに転送することは決してないことを覚えておいてください(モデルにJavascriptを挿入する予定がない限り)。

RESTは主にマシンの独立性に関するものです。エンドポイントがリソースを表す程度までRESTモデルを実装し、APIのコンシューマーが標準的な方法でそれらのリソースに簡単にアクセスして維持できるようにします。それが貧血のように思えるなら、それもそうです。

こちらもご覧ください
、私はより多くの動詞が必要


これは確かに質問のRFC2616側に対応していると思います。リソース指向になろうとしている、つまり、RESTのRichardson成熟度モデルで少なくともレベル2を達成しようとしているという事実はどうでしょうか。
カザーク

1
martinfowler.com/articles/richardsonMaturityModel.htmlを読みます。「Anemic Domain Models」について気にすることなく、レベル3に到達できます。動作をブラウザに転送することは決してないことを覚えておいてください(モデルにJavascriptを挿入する予定がない限り)。
ロバートハーヴェイ

4

REST APIはプレゼンテーション層の1つのタイプにすぎません。ドメインモデルとは関係ありません。

あなたが投稿した質問は、あなたが何らかの形で互いに適応する必要があるという混乱から生じています。あなたはしません。

ORMを介してドメインモデルをRDBMSにマッピングするのと同じ方法で、ドメインモデルをREST APIにマッピングします。このマッピングレイヤーが必要です。

ドメイン←ORM→RDBMS
ドメイン←RESTマッピング→REST API


3

私見私は彼らが貧血領域モデル(ADM)を奨励する傾向があるとは思わないが、彼らはあなたにいくらかの時間をかけて物事を考えることを要求する。

まず、ADMの主な特徴は、ADMの動作がほとんどまたはまったくないことだと思います。これは、システムに動作がないということではなく、通常何らかのServiceクラスにあるというだけです(http://vimeo.com/43598193を参照)。

もちろん、ADMに動作が存在しない場合、どうなりますか?もちろん、答えはデータです。それで、これはどのようにREST APIにマッピングされますか?おそらく、データはリソースのコンテンツにマップされ、動作はHTTP動詞にマップされます。

したがって、リッチドメインモデルを構築するために必要なものはすべて揃っているので、HTTP動詞がデータのドメイン操作にどのようにマッピングされるかを確認し、それらの操作をデータをカプセル化する同じクラスに配置する必要があります。

人々が問題に陥りやすいのは、動作が単純なCRUDを超えている場合、つまりドメインの他の部分に副作用がある場合に、HTTP動詞がドメインの動作にどのようにマッピングされるかを見るのが難しいことですHTTPリクエストによって変更されるリソース。その問題を解決する1つの方法は、ドメインイベントを使用することです(http://www.udidahan.com/2009/06/14/domain-events-salvation/)。


3

この記事は主題に非常に関連しており、あなたの質問に答えると思います。

私があなたの質問に非常によく答えると思う中核概念は、言及された記事の次の段落に要約されています:

「REST APIのリソースとドメイン駆動設計のドメインエンティティを区別することは非常に重要です。ドメイン駆動設計は物事の実装側(API実装を含む)に適用され、REST APIのリソースはAPI設計と契約を駆動します。選択は、基盤となるドメイン実装の詳細に依存するべきではありません。」


1

私が見た/構築したいくつかの合理的に成功した実装は、エンティティに作用する粗粒度の「ビジネスに優しい」方法を使用して動詞と名詞のメタファーをどのように組み合わせるかという質問に答えます。

そのため、(拡大された)getName()メソッド/サービスの代わりに、expose getPerson()がidentifier-type / IDのようなものを渡し、Personエンティティ全体を返します。

そのようなコンテキストでのPersonエンティティの振る舞いを適切に伝えることができないため(また、おそらくこれをデータ中心のコンテキストにするべきではありません)、リクエスト/レスポンスのペアのデータ(オブジェクト)サービス/秒。

サービスと定義された動詞自体は、ドメインに許可されたいくつかの動作、コントロール、さらにはエンティティの状態遷移規則を追加します。たとえば、transferPerson()サービス呼び出しで発生することに関するドメイン固有のロジックがありますが、インターフェイス自体は、内部の動作を定義せずに入力/出力エンティティ/データのみを定義します。

たとえば、転送動詞の実装はPersonクラスに属している、またはPerson中心のサービスに関連付けられていると言う著者には同意しません。確かに、方法転送のためPersonとオプションは、その(この単純な例では)良くによって定義されますCarrier、ここPerson転送方法が入手可能であるか、または転送でもどのようにジェットエンジンの仕事を知っている場所を(取る方法も、何の知識がないこととにかく)。

これにより、Personエンティティは貧血になりますか?そうは思いません。

外部クラスによって定義されるべきではない、健康状態のようなPersonの内部にあるPerson固有の事柄についてのロジックが存在する可能性があります。

ただし、ユースケースによっては、特定のシステム(輸送システムの座席割り当てサービスなど)でエンティティクラスに重要な/関連する動作がないことは完全に受け入れられます。そのようなシステムは、Personインスタンスと関連する識別子を処理するRESTベースのサービスを実装できますが、内部動作を定義/実装することはありません。


良い点---これは、他の答えがまだ持っていなかった新鮮な視点をもたらします。
カザーク14年

0

可能な限りPOSTを使用して、モデルを動詞の基本セットに詰め込もうとしているという問題はありますか?

その必要はありません-ほとんどの人にとってRESTはPOST、GET、PUT、DELETEを意味しますが、http rfcには次のように書かれています。

HTTP / 1.1の一般的なメソッドのセットを以下に定義します。このセットは拡張できますが、追加のメソッドは、個別に拡張されたクライアントとサーバーで同じセマンティクスを共有するとは想定できません。

また、SMTPなどのシステムは、同じスタイルの動詞ベースのメソッドを使用しますが、まったく異なるセットを使用します。

したがって、これらを使用しなければならない理由はありません。好きな動詞のセットを使用できます(ただし、基本4で必要なすべてを少し考えて実行できることに気付くでしょう)。RESTを他のメカニズムと区別するのは、これらの動詞を実装するステートレスで一貫した方法です。あなたは基本的にRESTを行っていないので、層間にメッセージパッシングシステムを実装しようとしないでください、あなたは間違いなくRESTの利点を失うことになるメッセージパッシング、RPCまたはメッセージキューメカニズムを代わりにしていますHTTP接続を介して非常にうまく機能するように単純化されています)。

フル機能の複雑なメッセージングプロトコルが必要な場合は、それを構築します(Webで可能であれば、RESTが非常に人気がある理由があります)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.