Me deparei com um projeto onde estão usando DTO na camada de serviço. Algo como:
List<UserDTO> searchUsers( … );
Na minha cabeça isso é o lixo do lixo.
Por que estavam fazendo isso?
:arrow: Para definir o formato da resposta do WebService que é em JSON. Ex: o User pode ter um atributo firstName mais a resposta do protocolo pode esperar name.
:arrow: Por que estavam usando um conversor de object para Json (JacksonView do Spring) que por reflection acessava todas as propriedades do objeto, carregando toda a hierarquia e até causando loop infinito em dependências cíclicas ManyToMany. (Obrigado Hibernate!)
O que eu falei para os malucos:
:arrow: Camada de serviços só pode trabalhar com modelo, entidades reais, nunca DTO.
:arrow: Quando precisar formatar alguma resposta, evitar lazy loading, trocar nome das propriedades, etc. Só há duas opções: 1) template engine (Velocity ou FreeMarker) ou 2) DTO genérico = Map
Isso é para um webservice que retorna respostas em JSON.
Então ficou a pergunta. Quando se justifica usar um DTO. Quem inventou isso?
Eu estou estudando EJB pelo EJB3 In Action e nele ele fala que o DTO foi “criado” para realizar a transmissão de objetos entre contextos diferentes. Pois ele não é o objeto em si, apenas uma representação dele. Ex.: Pessoa e PessoaDTO (conteria apenas strings por exemplo)
Eu trabalhei em um sistema que usava DTO como meio de transporte de informação da View para o Controller. Ao invés de se passar um monte de String picada para o controller trabalhar, passava o DTO que já era o objeto que a View montou.
Eu partilho da sua aversão a DTO. Acho que ele é um ótimo pattern… pro ano 2000. Hoje em dia, não tem a menor necessidade, seja em qualquer contexto, web services ou não, porque:
Se for um ambiente Java puro, o EJB3 pode muito bem trafegar sem carregar as dependências desnecessárias.
Se for um ambiente composto de web services, só anotar os atributos que não desejamos trafegar. Isso inclui, claro, referências a listas.
Acho que o único caso em que se aplica, se for, é o caso em que eu desejo apresentar diferentes visões dos objetos para diferentes clientes. Só que, isso já muda o Design Pattern, já que DTO é feito para falar de transferência de dados e não de máscara de dados. Não sei qual seria o nome do pattern, então, só sei que DTO é que não é.
Exemplo tosco e mal pensado mas que ajuda a explicar:
Voce tem um servico remoto que calcula imposto de cada produto de um carrinho de compras.
Se por acaso seu carrinho tem milhares de itens, serao geradas milhares de chamadas remotas, gastando muito com I/O.
Alguem poderia fazer algo assim:
Pra economizar chamadas remotas.[/quote]
OK, mas com a velocidade de transferência de que dispomos hoje, talvez seja mais interessante (às vezes) trafegar várias vezes pacotes pequenos, dando a chance de outros consumidores efetuarem também pequenos processamentos, do que cada um enviar um pacote muito grande, não? Assim, se der algum problema em alguma das chamadas (a rede não é perfeita), o processamento todo não é perdido. O que você acha?
[quote=asaudate]
OK, mas com a velocidade de transferência de que dispomos hoje, talvez seja mais interessante (às vezes) trafegar várias vezes pacotes pequenos, dando a chance de outros consumidores efetuarem também pequenos processamentos, do que cada um enviar um pacote muito grande, não? Assim, se der algum problema em alguma das chamadas (a rede não é perfeita), o processamento todo não é perdido. O que você acha?
[]´s[/quote]
Eu acho que DTO é uma pattern que deve ser aplicada apenas se e quando depois de medir o desempenho da aplicacao, utilizando um profiler ou outra ferramenta adequada, for identificado que o I/O gerado pelas multiplas chamadas é o gargalo. Realmente nao deve ser a abordagem default para servicos remotos.
Sim, mas vc pode usar um Map que é um DTO genérico para qualquer objeto. Ficar criando um DTO para cada comunicação que vc precisa fazer é overkill.
Como eu falei: acredito que o certo nesse caso é passar os próprios objetos do negócio para a view e ela se encarrega de apresentá-los da maneira que ela quiser via templates, JSP, tags, etc. No meu caso a minha view usava reflection para converter o objeto para JSON, o que poderia ser um problema. Então teria que ter uma camada intermediária para preparar um Maps (DTO genérico) para a view. Mas isso nunca deveria ter sido feito na camada de serviços.
Exemplo tosco e mal pensado mas que ajuda a explicar:
Voce tem um servico remoto que calcula imposto de cada produto de um carrinho de compras.
Se por acaso seu carrinho tem milhares de itens, serao geradas milhares de chamadas remotas, gastando muito com I/O.
Alguem poderia fazer algo assim:
Pra economizar chamadas remotas.[/quote]
Não entendi.
Vc vai passar o objeto de negócio Produto ou vai passar um ProdutoDTO. Mesma coisa para o CarrinhoDeCompras.
A comunicação entre sistemas deve ser feita via JSON ou XML. O que se faz é usar DTO como TEMPLATE para FORMATAR essa resposta. Meu ponto é que o melhor é usar template engine ou um DTO genérico (MAP).
O que vejo é que as pessoas estão usando DTO como TEMPLATE ENGINE. No teu caso, cada cliente seria direcionado para um template diferente. Se vc não quiser usar templates, vc teria um IF onde um Map seria preparado de maneira diferente para cada cliente. Depois esse MAP seria convertido para JSON ou XML. No caso aqui estou falando de WebService. Se fosse uma aplicação web vc teria um IF dentro do seu JSP ou dois JSPs diferentes.
O que me deu vontade de fazer foi o seguinte.
:arrow: Para web services
:arrow: Ao invés de dar um forward para um JSP ou TEMPLATE ENGINE que fai gerar a resposta a partir dos OBJETOS DE NEGOCIO.
:arrow: Vc dá um forward para um Objeto Java que vai preparar o MAP. Depois esse MAP é convertido para JSON e pronto.
:arrow: Seria uma maneira de organizar as versões por examplo, para vc não ter um milhão de IFs gerando o seu map no futuro.
Vc vai passar o objeto de negócio Produto ou vai passar um ProdutoDTO. Mesma coisa para o CarrinhoDeCompras.
A comunicação entre sistemas deve ser feita via JSON ou XML. O que se faz é usar DTO como TEMPLATE para FORMATAR essa resposta. Meu ponto é que o melhor é usar template engine ou um DTO genérico (MAP).
[/quote]
Sergio, o ponto é voce agregar varios objetos num objeto só e fazer uma só chamada com esse objeto. Nao tem nada haver com JSON ou XML e sim como vai ser a interface do servico. Nao tem nada haver com template ou formato.
E nao precisa chamar “ProdutoDTO”. Nao tem nenhuma regra.
E DTO generico nao é uma boa idéia, se nao voce perde completamente o sentido de ter uma interface e um contrato.
[quote=saoj]Sim, mas vc pode usar um Map que é um DTO genérico para qualquer objeto. Ficar criando um DTO para cada comunicação que vc precisa fazer é overkill.
Como eu falei: acredito que o certo nesse caso é passar os próprios objetos do negócio para a view e ela se encarrega de apresentá-los da maneira que ela quiser via templates, JSP, tags, etc. No meu caso a minha view usava reflection para converter o objeto para JSON, o que poderia ser um problema. Então teria que ter uma camada intermediária para preparar um Maps (DTO genérico) para a view. Mas isso nunca deveria ter sido feito na camada de serviços.
[/quote]
Um map? Não entendi… Se eu tenho uma classe Pessoa com 5 atributos …
Como vc passaria isso em um map (Sem ser objeto pessoa)?
Supondo uma busca de pessoa por nome, na primeira classe java que recebe o request (servlet/action/sei lah) vc recebe uma chave “nomePessoa” vc fala que é melhor criar um objeto Pessoa e passa-lo para o controle? Já conversaram comigo sobre esse tipo de ação, nunca trabalhei com ele não.
O problema dessa aplicação era o fato de que era algo legado e o framework não tinha como ser atualizado… aí complica né? =/
Então vc está efetivamente criando mais uma entidade para o seu modelo chamada CarrinhoDeCompras porque alguém precisa receber CarrinhoDeCompra. Vc não está pegando o CarrinhoDeCompra e formatando ele via um CarrinhoDeCompraDTO para que vc possa passá-lo na rede. O problema é usar DTO como TEMPLATE. É o que encontrei no projeto aqui. Me corrijam se eu estiver errado, mas qualquer formatação pode e deve ser feita com MAPs.
Vc pode converter qualquer objeto em um MAP. Até propriedades que são objetos, arrays, listas, etc. O seu objeto pessoas acima pode ser facilmente convertido num Map. Jogado na rede em JSON ou XML e reconstruído do outro lado.
O ideal seria usar Reflection para fazer isso, mas porque vc pode ter um objeto via Hibernate, cheio de lazy loading, com hierarquia de objetos longa e até ciclica (obrigado Hibernate) vc provavelmente vai querer fazer isso na mão.
[quote=saoj]
Então vc está efetivamente criando mais uma entidade para o seu modelo chamada CarrinhoDeCompras porque alguém precisa receber CarrinhoDeCompra. Vc não está pegando o CarrinhoDeCompra e formatando ele via um CarrinhoDeCompraDTO para que vc possa passá-lo na rede. [/quote]
Eu nao estou criando uma entidade nova no sistema… estou criando uma classe. So nao chamei ela pelo sufixo DTO. Voce nao precisa criar uma classe nova, pode ser que a classe ja existe no sistema. Provavelmente nao vai existir, ai vc cria uma nova, mas eu nao acho que ela precisa ser uma entidade e nao acho que ela precisa ter o sufixo DTO.
[quote=saoj]
O problema é usar DTO como TEMPLATE. É o que encontrei no projeto aqui. Me corrijam se eu estiver errado, mas qualquer formatação pode e deve ser feita com MAPs.[/quote]
Nao entendi o que significa DTO como Template. E nao é uma boa ideia usar um Map ao inves do uma classe “de verdade”.
*EDIT: Pensando bem, nao é bom reaproveitar classes do sistema para transformar em DTOs… O ideal criar uma classe nova para isso e deixar claro que ele serve apenas para agregar varios objetos numa chamada remota.
[quote=Rubem Azenha][quote=saoj]
Então vc está efetivamente criando mais uma entidade para o seu modelo chamada CarrinhoDeCompras porque alguém precisa receber CarrinhoDeCompra. Vc não está pegando o CarrinhoDeCompra e formatando ele via um CarrinhoDeCompraDTO para que vc possa passá-lo na rede. [/quote]
Eu nao estou criando uma entidade nova no sistema… estou criando uma classe. So nao chamei ela pelo sufixo DTO. Voce nao precisa criar uma classe nova, pode ser que a classe ja existe no sistema. Provavelmente nao vai existir, ai vc cria uma nova, mas eu nao acho que ela precisa ser uma entidade e nao acho que ela precisa ter o sufixo DTO.
[/quote]
Uma classe que representa alguma coisa concreta: CarrinhoDeCompra. Se ela vai ser persistida no banco de dados ou não, não interessa muito. Por que vc não quer chamá-la de entidade? Um carrinho de compras é uma entidade. Se você quer criar apenas um AGRUPADOR de coisas, então use COLLECTIONS.
[quote=“Rubem Azenha”]
Por que? Melhor usar um MAP do que usar um CarrinhoDeCompraDTO, ou seja, um mero formatador para o CarrinhoDeCompra. Consigo ver algumas vantagens de usar DTO. Type checking. As propriedades são métodos e não Strings como Maps, etc. Mas ainda fico com a flexibilidade e limpeza dos Maps.
Se vc quer usar DTO como template para exibir objetos, tudo bem. É factível. Eu consideraria primeiro MAPs e TEMPLATE ENGINE. O Map é um DTO genérico muito poderoso e flexível.
Agora NUNCA meter DTO no meio dos serviços, algo to tipo como encontrei aqui:
[quote=Rubem Azenha]
Eu nao estou criando uma entidade nova no sistema… estou criando uma classe. So nao chamei ela pelo sufixo DTO.[/quote]
Eu gosto dessa abordagem do Azenha: nao usar sufixo. Evita-los ao maximo.
As vantagens em relacao ao Map sao as que voce mesmo citou: ganha type safety e clareza quando for ler codigo de outra pessoa. Ficar jogando Map de um lado pro outros vai fazer a gente trabalhar com a famosa POS: Programacao orientada a strings. Map voce ganha flexibilidade, e de quebra, complexidade para manter. A escolha é sua.
O ponto importante é so lembrar de usar DTO quando tem inumeras invocacoes remotas que poderiam ser feitas tudo numa so. E, como o Azenha ja frisou, nao tem pra que usar o sufixo DTO.
Li toda a discusão e não entendi essa cisma em usar MAP para gerar XML e JSON recorrendo a reflection para buscar os campos, vc vai converter um objeto inteiro para transmitir inclusive usa hierarquia? Acreido que seria a hora de migrar a aplicação para MongoDB ou Couch…
Eu não preciso criar um CarrinhoDeComprasDTO, só crio um CarrinhoDeCompras e ele não vai ser perssisto, vc substituiria isso:
public class CarrinhoDeCompras{
private Collection<ProdutoCarrinho> produtos;
}
public class ProdutoCarrinho{
private Produto produto;
private Integer quantidade;
}
Só ilustrando o que eu entendi dos posts do Rubem (se eu entendi errado por favor me corriga), pra usar um MAP ou COLLECTION?
Me diga vou perder legibilidade e conseguetemente TypeSafe por qual motivo?
Por que? Melhor usar um MAP do que usar um CarrinhoDeCompraDTO, ou seja, um mero formatador para o CarrinhoDeCompra. Consigo ver algumas vantagens de usar DTO. Type checking. As propriedades são métodos e não Strings como Maps, etc. Mas ainda fico com a flexibilidade e limpeza dos Maps.[/quote]
Ja que é pra apelar, faz assim na tua classe:
public static Object executa(Map parametros, String nomeServico)