Un de mes collègues est contre l'utilisation des DTO et pense plutôt que nous devrions simplement renvoyer les objets Entity/Domain sérialisés pour un REST api. Il pense que le DTO est un modèle anti et a situé cet article Données Transférer un objet est une honte . Bien que l'article situé ait une approche différente pour résoudre le "problème DTO" comme le propose mon collègue. Personnellement, j'ai toujours préféré utiliser DTO pour trois raisons.
Le point 2 n'est pas un gros problème si un ORM n'est pas utilisé. Je peux toujours voir peut émettre si vous aviez quelque chose comme ce qui suit
class Order {
private Long orderId;
// additional fields go here
private List<LineItem> lineItems;
}
class LineItem {
private Long id;
private BigDecimal amount;
private int qty;
}
Disons que le client ne voulait qu'une liste de commandes et ne se souciait pas des éléments de campagne. S'il n'y avait pas de DTO impliqué, vous pourriez remplir l'objet Order et laisser les lineItems sous forme de List vide, mais ce serait gênant et déroutant de le remplir dans certains cas, et pas dans d'autres. Ou toutes les données pourraient être chargées et transférées, mais cela semble un gaspillage et un impact potentiel sur les performances.
Existe-t-il chaque fois un moment approprié pour ignorer les DTO et simplement renvoyer l'objet de domaine? Ou est-ce que je pense mal et le DTO n'est pas un modèle qui devrait être utilisé. Y a-t-il une autre approche?
Tout d'abord, le simple fait de citer l'article de quelqu'un sur Internet ne constitue pas une justification suffisante pour modifier une pratique. Vous devez peser le pour et le contre et vous faire votre propre opinion.
Notez que l'auteur de l'article que vous avez cité déteste les ORM . Il suit un principe strict d'encapsulation du code avec ses données, qui est en quelque sorte le principe fondateur de l'orientation objet. Il déteste fortement ORM car il dépouille les classes de leur intelligence, et il n'a pas tort à ce sujet.
Dans son article sur la haine ORM, il écrit (plus ou moins) que les classes devraient être responsables de leur sauvegarde dans la base de données, une pratique qui viole un principe appelé "l'ignorance de la persistance". L'ignorance de la persistance signifie simplement que les classes ne devraient rien savoir de leur seigneur de base de données, et c'est difficile à réaliser de manière réaliste avec les ORM . Il contourne le problème de l'ignorance de la persistance en utilisant des interfaces, rendant ses données ignorantes de son implémentation sous-jacente.
Pour être honnête, j'écris du code qui ressemble beaucoup au sien sous le capot, quoique un peu plus rationalisé que le sien (Java a la réputation d'être très verbeux, et je ne me soucie pas des interfaces DTO). Après avoir lutté avec Entity Framework pendant un certain temps, j'ai commencé à utiliser Dapper et à écrire des requêtes SQL à la place. J'obtiens de meilleures performances, moins de complexité et un ciblage plus fin de la base de données.
La classe qui implémente votre soi-disant "objet de transfert de données" est un bon endroit pour mettre ce code; tout ce que vous avez à faire est de lui remettre un objet IdbConnection
, et la classe a tout ce dont elle a besoin pour lire et persister dans la base de données.
Je suppose que ma question est, pourquoi cela doit-il être un choix// ou? Si vous avez besoin d'un élément de la base de données qui nécessite un DTO, utilisez un DTO. Si vous voulez ce que vous appelez un "objet de domaine", utilisez-le à la place.
Je pense que les objets Data Domain (DTO) doivent être séparés des objets de la couche Présentation.
En ce qui concerne "les objets de transfert de données sont honteux", j'ai lu de tels articles sur l'anti-modèle, etc. la première place.
Tout d'abord pour des raisons de sécurité, c'est-à-dire que vous ne voulez pas exposer votre structure de données interne au monde extérieur et que vous ne devriez pas, et l'objet de couche de présentation vous donne la possibilité de limiter les données de réponse à ce qui est UNIQUEMENT REQUIS.
Deuxièmement, la sécurité mise à part, si vous êtes dans un monde de microservices ou de services distribués, ou si votre application est conçue de manière modulaire, la séparation des responsabilités et des objets de données a plus de sens.
Imaginez ceci: vous avez 3 bibliothèques pour reposantes,
- A. API utilisateur (l'interface de service) - dépend de B
- Objets de données utilisateur
- C. fournisseur d'utilisateur (la mise en œuvre réelle) - dépend de A & B
et 3 bibliothèques pour la couche de stockage de données (il devrait y avoir une couche métier en place, mais je l'ignore pour plus de simplicité)
- D. service de données utilisateur (interface) - dépend de E
- E. Objets de données utilisateur (DTO)
- F. fournisseur de services de données utilisateur (mise en œuvre) - dépend de D & E
Imaginez donc que vous ayez un autre module de service de données qui ne souhaite utiliser que les données utilisateur, il ne devrait dépendre que de la bibliothèque E; alors s'il existe un autre service reposant qui souhaite emprunter des objets de données utilisateur, ils peuvent simplement dépendre de B uniquement. Et ainsi de suite, les choses doivent être transparentes et aussi atomiques que possible, ce qui favorise la réutilisation du code.
Même certains pourraient dire que mon application est petite, et je veux juste la sortir rapidement sans tous les passe-partout, eh bien vous pouvez, mais je ne conseillerai pas, c'est l'expérience qui me dit de ne pas le faire. Nous avons vu beaucoup de ces exemples dans le passé, RoR, NodeJS, ... vous l'avez nommé.
Le truc, c'est qu'ils vous emmèneront quelque part très rapidement, mais seulement en résolvant des choses simples d'une manière simple, mais des choses complexes seront rendues pratiquement complexes.
Donc pour moi, je dirais plutôt suivre les meilleures pratiques depuis le début, et m'inquiéter moins tard que de tout abandonner et de refaire, et croyez-moi, vous allez passer le même (sinon plus) de temps pour obtenir juste plus tard.