私の同僚はDTOの使用に反対しており、REST apiに対してシリアル化されたEntity/Domainオブジェクトを返すだけでよいと感じています。DTOはアンチパターンであり、この記事を掲載していると感じています Data Transfer Object is a Shame 。同僚が提案しているように、サイトに掲載された記事には「DTO問題」を解決するための異なるアプローチがありますが、個人的には常に3つの理由でDTOを使用することを好みました。
ORMが使用されていない場合、ポイント2は大きな問題ではありません。私はまだ問題を見ることができますが、次のようなものがあれば
class Order {
private Long orderId;
// additional fields go here
private List<LineItem> lineItems;
}
class LineItem {
private Long id;
private BigDecimal amount;
private int qty;
}
クライアントが注文のリストだけを必要としていて、ラインアイテムを気にしていなかったとしましょう。 DTOが関与していなかった場合、Orderオブジェクトにデータを入力して、lineItemsを空のリストのままにしておくことができますが、そうでない場合とそうでない場合があり、混乱を招く可能性があります。または、すべてのデータをロードして転送できますが、それは無駄であり、パフォーマンスに影響を与える可能性があります。
DTOをスキップしてドメインオブジェクトを返すのに適切な時間はありますか?それとも私は間違っていると思い、DTOは使用すべきパターンではありません。別のアプローチはありますか?
まず第一に、単にインターネット上の誰かの記事を引用するだけでは、慣習を変えるための十分な正当化を構成しません。あなたは長所と短所を比較検討し、自分で決心する必要があります。
引用した記事の著者 ORMが嫌い であることに注意してください。彼は、データをコードにカプセル化するという厳密な原則に従います。これは、オブジェクト指向の基本原則のようなものです。 ORMはインテリジェンスのクラスを取り除くため、ORMを強く嫌っています。それについては間違いありません。
彼のORM憎悪の記事で、彼は(多かれ少なかれ)クラスが自分自身をデータベースに保存する責任を負うべきであると書いています。永続性の無知は、クラスがデータベースの主君について何も知らないことを意味します ORMで現実的な方法でこれを実現することは困難です 。彼は、インターフェースを使用して永続性の無知の問題を回避し、データをその基礎となる実装について無知にします。
公平を期すために、私は彼の内面に非常に似たコードを書いていますが、彼よりも少し能率的です(Javaは非常に冗長であるとの評判があり、DTOインターフェースを気にしません)。しばらくの間Entity Frameworkと取り組んだ後、私は Dapper を使用し、代わりにSQLクエリを記述し始めました。データベースのパフォーマンスが向上し、複雑さが軽減され、ターゲットが細かくなります。
いわゆる「データ転送オブジェクト」を実装するクラスは、このコードを配置するのに最適な場所です。 IdbConnection
オブジェクトを渡すだけで、クラスにはデータベースからの読み取りとデータベースへの永続化に必要なすべてのものが含まれます。
私の質問は、なぜこれがどちらかまたは両方の選択肢でなければならないのでしょうか? DTOを必要とするデータベースから何かが必要な場合は、DTOを使用します。 「ドメインオブジェクト」と呼んでいるものが必要な場合は、代わりにそれを使用してください。
Data Domain Object(DTO)はプレゼンテーションレイヤーのオブジェクトから分離する必要があると思います。
「Data Transfer Object is Shame」については、アンチパターンなどの記事を読んだのですが、コードを書きたくないので、なぜデザインパターンがそこにあるのか本当に理解できないので、人々がそう言っているのは面倒だと思います。そもそも。
1つはセキュリティ上の理由からです。つまり、内部データ構造を外部に公開したくないので公開しないでください。プレゼンテーションレイヤーオブジェクトを使用すると、応答データを必要なものだけに制限できます。
次に、セキュリティはさておき、マイクロサービスや分散サービスの世界にいる場合、またはアプリケーションがモジュールで設計されている場合は、責任とデータオブジェクトの分離がより理にかなっています。
これを想像してみてください。休憩用に3つのライブラリがあります。
- A.ユーザーAPI(サービスインターフェイス)-Bに依存
- B.ユーザーデータオブジェクト
- C.ユーザープロバイダー(実際の実装)-AおよびBに依存
およびデータストレージレイヤー用の3つのライブラリー(ビジネスレイヤーがあるはずですが、簡単にするために省略します)
- D.ユーザーデータサービス(インターフェース)-Eに依存
- E.ユーザーデータオブジェクト(DTO)
- F.ユーザーデータサービスプロバイダー(実装)-DおよびEに依存
したがって、ユーザーデータオブジェクトのみを使用する別のデータサービスモジュールがあるとします。これは、ライブラリEのみに依存する必要があります。次に、ユーザーデータオブジェクトを借用したい別のRESTfulサービスがある場合、それらはBのみに依存できます。そして、物事は透明で可能な限りアトミックである必要があり、それによってコードの再利用性が促進されます。
私のアプリケーションは小さいと言う人もいるかもしれませんが、定型文をすべて使わずにすばやく出力したいだけなのですが、できませんが、そうはしないようにと言ってきました。これらの例の多くは過去に見たことがあります。RoR、NodeJSなどです。
事は、彼らはあなたをどこかに本当に速く連れて行くでしょう、しかし単純なものを単純な方法で解決するだけですが、複雑なものは実際には複雑にされます。
したがって、私にとっては、最初からベストプラクティスに従うのではなく、すべてを廃棄してやり直すよりも遅く心配せず、同じ時間(それ以上ではない)を費やすことになると信じて、すぐ後で。