web-dev-qa-db-ja.com

ボブおじさんのクリーンなアーキテクチャ-各レイヤーのエンティティ/モデルクラス?

背景:

私はAndroidアプリでアンクルボブのクリーンアーキテクチャを使用しようとしています。それを行うための正しい方法を示しようとしている多くのオープンソースプロジェクトを調べたところ、- an興味深い実装 RxAndroidに基づいています。

私が気づいたこと:

すべてのレイヤー(プレゼンテーション、ドメイン、データ)には、同じエンティティ(UMLを話す)のモデルクラスがあります。さらに、データが境界を越えたとき(レイヤーから別のレイヤーへ)にオブジェクトの変換を処理するマッパークラスがあります。

質問:

すべてのCRUD操作が必要な場合、モデルクラスがすべて同じ属性になることがわかっている場合、すべてのレイヤーにモデルクラスが必要ですか?または、クリーンアーキテクチャを使用する場合のルールまたはベストプラクティスですか?

49
Rami Jemli

私の意見では、それはそれが意味する方法では絶対にありません。そして、それはDRYの違反です。

アイデアは、真ん中のエンティティ/ドメインオブジェクトは、ドメインをできるだけ適切かつ便利に表すようにモデル化されるというものです。それはすべての中心にあり、ドメイン自体はほとんどの場合変更されないため、すべてがそれに依存する可能性があります。

外部のデータベースがこれらのオブジェクトを直接格納できる場合、レイヤーを分離するためにそれらを別の形式にマッピングしても意味がないだけでなく、モデルの複製が作成されますが、これは意図されていません。

まず、クリーンなアーキテクチャは、異なる典型的な環境/シナリオを念頭に置いて作成されました。独自のタイプの特別なオブジェクトを必要とする巨大な外層を持つビジネスサーバーアプリケーション。たとえば、SQLRowオブジェクトを生成し、アイテムを更新する代わりにSQLTransactionsを必要とするデータベース。中心でそれらを使用する場合、コアはデータベースに依存するため、依存関係の方向に違反することになります。

エンティティオブジェクトをロードおよび格納する軽量のORMでは、そうではありません。内部SQLRowとドメイン間のマッピングを行います。 ORMの@Entitiyアノテーションをドメインオブジェクトに挿入する必要がある場合でも、これは外側のレイヤーの「メンション」を確立しないと私は主張します。注釈は単なるメタデータであるため、特に注釈を探していないコードでは注釈が表示されません。さらに重要なことに、それらを削除したり、別のデータベースの注釈で置き換えたりしても、何も変更する必要はありません。

対照的に、ドメインを変更し、それらすべてのマッパーを作成した場合は、大幅に変更する必要があります。


修正:上記は少し単純化されており、間違っている可能性さえあります。なぜなら、レイヤーごとに表現を作成する必要があるクリーンアーキテクチャの部分があるからです。しかし、それはアプリケーションのコンテキストで見られる必要があります。

つまり、以下は https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html

重要なことは、分離された単純なデータ構造が境界を越えて渡されることです。 エンティティまたはデータベース行をだまして渡したくありません。データ構造に、依存関係ルールに違反するような依存関係を持たせたくありません。

エンティティを中心から外側のレイヤーに渡すことは、依存関係ルールに違反していませんが、言及されています。しかし、これには想定されるアプリケーションのコンテキストでの理由があります。エンティティを渡すと、アプリケーションロジックが外側に移動します。外側のレイヤーは、内側のオブジェクトを解釈する方法を知る必要があります。それらは、「ユースケース」レイヤーのような内側のレイヤーが行うことになっていることを効果的に行う必要があります。

それに加えて、コアを変更しても必ずしも外側のレイヤーを変更する必要がないように、レイヤーを分離します(SteveCallenderのコメントを参照)。そのコンテキストでは、オブジェクトが使用される目的を具体的にどのように表すかを簡単に確認できます。また、その層は、このコミュニケーションの目的で特別に作成されたオブジェクトに関して、互いに対話する必要があります。これは、各レイヤーに1つ、レイヤー間のトランスポートに1つという3つの表現があることも意味します。

そして、上記のアドレスである https://blog.8thlight.com/uncle-bob/2011/11/22/Clean-Architecture.html があります。

他の人々は、私のアドバイスの最終的な結果は、たくさんの重複したコードと、システムのレイヤーを越えたあるデータ構造から別のデータ構造への大量のデータの大量コピーであることを心配しました。確かに私もこれを望んでいません。そして、私が示唆していないことは、必然的にデータ構造の繰り返しとフィールドコピーの過度の原因となるでしょう。

IMOは、オブジェクトの単純な1:1コピーは、実際には適切なレイヤーや抽象化を使用していないため、アーキテクチャのにおいがすることを意味します。

彼は後ですべての「コピー」をどのように想像するかを説明します

2つの間で単純なデータ構造を渡すことにより、UIをビジネスルールから分離します。コントローラーにはビジネスルールについて何も知らせません。代わりに、コントローラーはHttpRequestオブジェクトを単純なバニラデータ構造にアンパックし、そのデータ構造を、ビジネスオブジェクトを呼び出すことでユースケースを実装するインタラクターオブジェクトに渡します。次に、インタラクターは応答データを別のVanillaデータ構造に収集し、それをUIに返します。ビューはビジネスオブジェクトについて知りません。彼らはそのデータ構造を調べて応答を提示するだけです。

このアプリケーションでは、表現に大きな違いがあります。流れるデータはエンティティだけではありません。そして、これは異なるクラスを保証し、要求します。

ただし、単純なAndroidアプリケーションに適用すると、Photoエンティティに約0のビジネスルールがあり、それらを扱う「ユースケース」はほとんど存在しません。キャッシングとダウンロード(IMOをより明示的に表現する必要があります)の方が実際に心配です。写真を個別に表現するポイントが消え始めます。実際の写真であるにもかかわらず、写真自体がデータ転送オブジェクトであるとさえ感じますbusiness-logic-core-layerがありません。

写真を表示したい場合、 "2つの間に単純なデータ構造を渡すことにより、UIをビジネスルールから分離します" "の間に違いがあります途中で3回名前を変更します」

さらに、これらのデモアプリケーションがクリーンなアーキテクチャを表現できない点は、レイヤーを分離するためにレイヤーの分離に非常に重点を置いているが、アプリケーションの機能を効果的に隠していることです。これは https://blog.8thlight.com/uncle-bob/2011/09/30/Screaming-Architecture.html -つまり

ソフトウェアアプリケーションのアーキテクチャは、アプリケーションのユースケースについて悲鳴を上げる

クリーンなアーキテクチャでレイヤーを分離することに重点が置かれているとは思いません。依存関係の方向性についてであり、アプリケーションのコア(エンティティとユースケース)を表現することに焦点を当てています。理想的には、外部への依存関係がないJavaです。そのコアへの依存関係はそれほど重要ではありません。

したがって、アプリケーションに実際にビジネスルールとユースケースを表すコアがあり、異なる人が異なるレイヤーで作業している場合は、意図した方法でそれらを分離してください。一方、単純なアプリを自分ですべて作成する場合は、無理をしないでください。滑らかな境界を持つ2つのレイヤーで十分です。また、レイヤーも後で追加できます。

57
zapl

正解です。また、SRPを受け入れるため、DRYの違反はありません。

次に例を示します。business-MethodcreateX(String name)があり、business-Method内で呼び出されるDAOレイヤーにメソッドcreateX(String name)がある場合があります。彼らは同じ署名を持っているかもしれませんし、多分委任しかないかもしれませんが、彼らは異なる目的を持っています。 UseCaseでcreateX(String name)を持つこともできます。それでも冗長ではありません。つまり、同じシグネチャが同じセマンティクスを意味するわけではありません。セマンティクスを明確にするために、他の名前を選択してください。これ自体に名前を付けても、SRPにはまったく影響しません。

UseCaseはアプリケーション固有のロジックを担当し、ビジネスオブジェクトはアプリケーションに依存しないロジックを担当し、DAOは格納を担当します。

セマンティクスが異なるため、すべてのレイヤーに独自の表現および通信モデルがある場合があります。 「エンティティ」を「ビジネスオブジェクト」と見なすことが多く、それらを分離する必要性がわからないことがよくあります。しかし、「巨大な」プロジェクトでは、レイヤーを適切に分離するための努力が必要です。プロジェクトが大きいほど、異なるレイヤーやクラスで表現される異なるセマンティクスが必要になる可能性が高まります。

同じセマンティクスのさまざまな側面を考えることができます。 User-Objectは画面に表示する必要があり、内部整合性ルールがいくつかあり、どこかに保存する必要があります。各アスペクトは、異なるクラス(SRP)で表す必要があります。マッパーの作成はお尻に苦痛を伴う可能性があるため、これらの側面で私が取り組んだほとんどのプロジェクトでは、1つのクラスに溶け込んでいます。これは明らかにSRPの違反ですが、誰も本当に気にしません。

クリーンアーキテクチャとS.O.L.I.Dのアプリケーションを呼び出します。 「社会的に受け入れられない」。許可されれば私はそれで働きます。現在、私はそれを行うことを許可されていません。 S.O.L.I.D.の服用について考えなければならない瞬間を待ちます。真剣に。

7
user205407

いいえ、すべてのレイヤーにモデルクラスを作成する必要はありません。

EntityDATA_LAYER)-Databaseオブジェクトの完全または部分的な表現です。 DATA_LAYER

MapperDOMAIN_LAYER)-実際には、エンティティをModelClassに変換するクラスであり、DOMAIN_LAYERで使用されます

見てください: https://github.com/lifedemons/photoviewer

5
deathember