Qual é o uso do DTO em vez da Entidade?


18

Estou trabalhando no aplicativo RCP, sou novo nesse aplicativo.

Spring beans são usados ​​para escrever lógica de negócios para salvar / buscar entidades.

Mas, em vez de enviar entidades diretamente para o cliente , estamos convertendo em DTOs e preenchendo o cliente. Ao salvar, novamente estamos convertendo o DTO em entidade e salvando.

Qual é o benefício dessas conversões? Alguém pode explicar?


What's the benefit of these conversions?dissociar o modelo de dados de persistência do modelo de dados (representação) oferecido aos consumidores. Os benefícios da dissociação foram amplamente discutidos no SE. No entanto, o objetivo dos DTOs é reunir em uma única resposta quantas informações forem necessárias para os clientes salvarem chamadas no servidor. O que torna a comunicação cliente-servidor mais suave.
LAIV


Seu exemplo é legal. Quando você é o cliente (visualizações ...), é doloroso mudar, mas o maior problema é quando o sistema já possui integrações de terceiros, que é impossível mudar (contrato, taxas ...). Se o seu sistema tiver integração com terceiros, use o DTO.
Lucas Gonçalves

Respostas:


44

Sempre que um desenvolvedor pergunta "qual é o sentido de fazer isso?", O que eles realmente querem dizer é "não vejo nenhum caso de uso em que isso forneça um benefício". Para esse fim, deixe-me mostrar alguns exemplos.


Todos os exemplos serão baseados neste modelo de dados simples:

Uma Personentidade possui cinco propriedades:Id, FirstName, LastName, Age, CityId

E você pode supor que o aplicativo use esses dados de várias maneiras (relatórios, formulários, pop-ups, ...).

O aplicativo inteiro já existe. Tudo o que eu mencionei é uma alteração na base de código existente. Isso é importante lembrar.


Exemplo 1 - Alterando a estrutura de dados subjacente - sem DTO

Os requisitos foram alterados. A idade da pessoa precisa ser recuperada dinamicamente do banco de dados do governo (vamos assumir com base no nome e sobrenome).

Como você não precisa mais armazenar o Agevalor localmente, ele precisa ser removido da Personentidade. É importante perceber aqui que a entidade representa os dados do banco de dados e nada mais. Se não estiver no banco de dados, não está na entidade.
Quando você recupera a idade do serviço da web do governo, ele será armazenado em um objeto (ou int) diferente.

Mas seu frontend ainda exibe uma idade. Todas as visualizações foram configuradas para usar a Person.Agepropriedade, que agora não existe mais. Um problema se apresenta: todas as visualizações que se referem à Agepessoa precisam ser corrigidas .


Exemplo 2 - Alterando a estrutura de dados subjacente - Com DTO

No sistema antigo, também há PersonDTOentidade com as mesmas cinco propriedades: Id, FirstName, LastName, Age, CityId. Após recuperar a Person, a camada de serviço a converte em a PersonDTOe depois a devolve.

Mas agora, os requisitos mudaram. A idade da pessoa precisa ser recuperada dinamicamente do banco de dados do governo (vamos assumir com base no nome e sobrenome).

Como você não precisa mais armazenar o Agevalor localmente, ele precisa ser removido da Personentidade. É importante perceber aqui que a entidade representa os dados do banco de dados e nada mais. Se não estiver no banco de dados, não está na entidade.

No entanto, como você tem um intermediário PersonDTO, é importante ver que essa classe pode manter a Agepropriedade. A camada de serviço buscará Person, converterá em a PersonDTOe também buscará a idade da pessoa no serviço web do governo, armazenará esse valor PersonDTO.Agee passará esse objeto.

A parte importante aqui é que quem usa a camada de serviço não vê diferença entre o antigo e o novo sistema . Isso inclui seu frontend. No sistema antigo, ele recebeu um PersonDTOobjeto completo . E no novo sistema, ele ainda recebe um PersonDTOobjeto completo . As visualizações não precisam ser atualizadas .

É isso que queremos dizer quando usamos a frase separação de preocupações : Existem duas preocupações diferentes (armazenar os dados no banco de dados, apresentar os dados ao front-end) e eles precisam de um tipo de dados diferente para cada um. Mesmo que esses dois tipos de dados contenham os mesmos dados agora, isso pode mudar no futuro.
No exemplo dado, Agehá uma diferença entre os dois tipos de dados: Person(a entidade do banco de dados) não precisa de um Age, mas PersonDTO(o tipo de dados de front-end) precisa.
Ao separar as preocupações (= criar tipos de dados separados) desde o início, a base de código é muito mais resistente às alterações feitas no modelo de dados.

Você pode argumentar que ter um objeto DTO, quando uma nova coluna é adicionada ao banco de dados, significa que você deve fazer um trabalho duplo, adicionando a propriedade na entidade e no DTO. Isso é tecnicamente correto. Exige um pouco de esforço extra para manter duas classes em vez de uma.

No entanto, você precisa comparar o esforço necessário. Quando uma ou mais novas colunas são adicionadas, copiar / colar algumas propriedades não leva tanto tempo. Quando o modelo de dados muda estruturalmente, é necessário alterar o frontend, possivelmente de maneiras que apenas causam bugs no tempo de execução (e não no tempo de compilação), exige muito mais esforço e exige que os desenvolvedores procurem bugs.


Eu poderia lhe dar mais exemplos, mas o princípio sempre será o mesmo.

Resumir

  • Responsabilidades (preocupações) separadas precisam trabalhar separadamente uma da outra. Eles não devem compartilhar recursos, como classes de dados (por exemplo Person)
  • Só porque uma entidade e seu DTO têm as mesmas propriedades, não significa que você precisa mesclá-las na mesma entidade. Não corte cantos.
    • Como um exemplo mais flagrante, digamos que nosso banco de dados contenha países, músicas e pessoas. Todas essas entidades têm a Name. Mas apenas porque todos eles têm uma Namepropriedade, não significa que devemos fazê-los herdar de uma EntityWithNameclasse base compartilhada . As diferentes Namepropriedades não têm relação significativa.
    • Se alguma das propriedades mudar (por exemplo, uma música Nameé renomeada Titleou uma pessoa recebe um FirstNamee LastName), elas terão que se esforçar mais para desfazer a herança que você nem precisava em primeiro lugar .
    • Embora não seja tão flagrante, seu argumento de que você não precisa de um DTO quando possui uma entidade é o mesmo. Você está olhando para o agora , mas não está se preparando para mudanças futuras. SE a entidade e o DTO forem exatamente iguais, e se você puder garantir que nunca haverá alterações no modelo de dados; então você está certo de que pode omitir o DTO. Mas o importante é que você nunca pode garantir que o modelo de dados nunca será alterado.
  • As boas práticas nem sempre são recompensadas imediatamente. Pode começar a valer a pena no futuro, quando você precisar revisitar um aplicativo antigo.
  • A principal causa de morte das bases de código existentes é deixar a qualidade do código diminuir, dificultando continuamente a manutenção da base de código, até que ela se torne uma bagunça inútil de código espaguete que é inatingível.
  • As boas práticas, como a implementação de uma separação de preocupações do início, visam evitar essa ladeira escorregadia de má manutenção, a fim de manter a base de código em manutenção pelo maior tempo possível.

Como regra geral para considerar a separação de preocupações, pense da seguinte maneira:

Suponha que todas as preocupações (a interface do usuário, o banco de dados, a lógica) sejam tratadas por uma pessoa diferente em um local diferente. Eles só podem se comunicar por email.

Em uma base de código bem separada, uma alteração em uma preocupação específica precisará ser tratada apenas por uma pessoa:

  • Alterar a interface do usuário envolve apenas o desenvolvedor da interface do usuário.
  • Alterar o método de armazenamento de dados envolve apenas o desenvolvedor do banco de dados.
  • Alterar a lógica de negócios envolve apenas o desenvolvedor de negócios.

Se todos esses desenvolvedores usassem a mesma Personentidade e uma pequena alteração fosse feita na entidade, todos precisariam estar envolvidos no processo.

Mas, usando classes de dados separadas para cada camada, esse problema não é tão prevalente:

  • Desde que o desenvolvedor do banco de dados possa retornar um PersonDTOobjeto válido , o desenvolvedor de negócios e a interface do usuário não se importam se ele mudou a maneira como os dados são armazenados / recuperados.
  • Desde que o desenvolvedor comercial armazene os dados no banco de dados e forneça os dados necessários ao front-end, os desenvolvedores do banco de dados e da interface do usuário não se importam se ele decidiu refazer suas regras de negócios.
  • Desde que a interface do usuário possa ser projetada com base no `PersonViewModel, o desenvolvedor da UI poderá criar a interface da maneira que desejar. Os desenvolvedores de banco de dados e negócios não se importam com o que é feito, pois não os afetam.

A frase-chave aqui é que isso não os afeta . A implementação de uma boa separação de preocupações busca minimizar a afetação (e, portanto, a necessidade de envolver) outras partes.

Obviamente, algumas mudanças importantes não podem evitar a inclusão de mais de uma pessoa, por exemplo, quando uma entidade totalmente nova é adicionada ao banco de dados. Mas não subestime a quantidade de pequenas alterações que você precisa fazer durante a vida útil de um aplicativo. As principais mudanças são uma minoria numérica.


Resposta abrangente, obrigado. Eu tenho dúvidas; Aprecie se você responder: 1 - Me corrija, se eu estiver errado. Objeto comercial ou Exibir objeto destina-se à transferência de dados entre a camada de apresentação e a camada comercial e o objeto de entidade destina-se à transferência de dados entre a camada comercial e a camada de acesso a dados . e o DTO pode ser usado como um BO burro. 2 - Suponha que duas visualizações precisem de informações diferentes de uma empresa, e então precisamos de dois DTOs diferentes da empresa?
Arash

1
@Arash (1) "DTO" é realmente uma definição abrangente para qualquer classe de dados usada para a troca entre duas camadas. Um objeto de negócios e um objeto de visualização são ambos DTOs. (2) Isso depende muito de muitas coisas. Criar um novo dto para cada coleção de campos necessária é uma tarefa complicada. Não há nada inerentemente errado em simplesmente devolver um DTO completo da empresa (quando razoável) e depois deixar a visualização escolher os campos nos quais está interessado. É uma questão de encontrar o equilíbrio entre implementar uma separação adequada de preocupações e evitar a superengenharia e a repetição sem sentido.
Flater

Agora isso faz sentido para mim. Muito obrigado. Flater.
Arash

Mais uma pergunta. Você disse "objeto de negócios e um objeto de visualização". Eu pensei que ambos são iguais. Quando pesquisei, percebi que o Business Object tem um significado geral para comparar com o View Object . Mas o Objeto de Negócios deve ser derivado do caso de uso e o Objeto de Entidade deve ser derivado do Modelo de Dados, portanto, eles são diferentes, certo? você poderia explicar um pouco, por favor?
Arash

@Arash: A diferença entre o que você chama de "objeto de negócios" e "objeto de exibição" é contexto . Para nós, humanos, essa distinção é importante para entender as coisas corretamente. Mas o compilador (e por extensão a própria linguagem) não vê diferença técnica entre eles. Quando digo que são iguais, quero dizer isso de uma perspectiva técnica. Ambos são apenas uma classe com propriedades destinadas a reter dados e serem transmitidas. A esse respeito, não há diferença entre eles.
Flater
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.