Como usar Transfer Object?

Olá PCalcado,

  A arquitetura de camadas que usamos é a seguinte: 

         
          VISÃO         _ 
            <=>           |
        CONTROLE      |   --- > WAR
            <=>           |
       DELEGAÇÃO   _|
            <=> 
         SISTEMA      _
            <=>           |  ----> EJB JAR
         DOMÍNIO     _ |   

 
  Para vc entender a dependência que o "Hibernate Domain Bean" gera nas aplicações clientes, experimente criar um WAR que receba um POJO que foi utilizado pelo Hibernate em um archive EJB como retorno de um determinado método de negócio, implementado por um Session Bean. Para o exemplo ficar legal, procure implantar as aplicações de forma independente, de preferência em application servers distintos, no melhor exemplo um TomCat e um JBoss. 

 Você vai perceber que para  "deployar" a sua aplicação Web no TomCat você vai ter que fornecer o jar do Hibernate.  Isso acontece  por que o POJO que representa uma entidade de negócio, que teoricamente é um objeto Java comum, é estendido pelo  Hibernate. Ou seja, o objeto que chega como retorno para você na tua camada de delegação não é mais um "Plain Java" mas um objeto Hibernate. Daí a tal da dependência. 

Quanto ao fato de criar estruturas paralelas, a primeira vista, realmente parece o fim do mundo. Concordo com você que "duplicar código" é sempre uma má idéia. Mas o fato de trabalhar por contratos e tentar isolar os clientes de componentes mais internos, eu considero crucial. O "Hibernate Domain Bean" acaba se tornando um "Mochileiro das Galáxias". Sai das camdas mais baixas do sistema (camada de persistência) e vai parar nas páginas JSP. Isso para mim é o que se chama de "ALTO ACOPLAMENTO". Ou seja, deixamos de ter trabalho criando estruturas paralelas mas ganhamos uma alta dependência dos clientes com pacotes e interfaces do tipo [i]br.com.acme.xpto.entidades.Aluno[/i]. Realmente não acredito que se justifique.

Abração.

Algumas perguntas:

  1. Camada de delegacao? Huh? :shock:

  2. [quote=Renatov]Para vc entender a dependência que o “Hibernate Domain Bean” gera nas aplicações clientes, experimente criar um WAR que receba um POJO que foi utilizado pelo Hibernate em um archive EJB como retorno de um determinado método de negócio, implementado por um Session Bean. Para o exemplo ficar legal, procure implantar as aplicações de forma independente, de preferência em application servers distintos, no melhor exemplo um TomCat e um JBoss.
    [/quote]

Pra que? :?

Lembre-se da primeira grande regra de sistemas distribuidos: nao construa sistemas distribuidos :wink:

O sue problema é classloading: O classloader RMI não está disponível no seu contexto.

Como você resolve isso com EJBs se não colocar um jboss-client.jar da vida no classpath?

De qualquer modo este é o exemplo clássico do uso de DTOs: troca entre duas camadas físicas. Como falei o problema é arquitetrual.

Não senhor. Objetos de infra-estrutura gerados automaticamente como os do Hibernate não podem ser considerados mochileiros porque são transparentes apra o desenvolvedor/projetista.

Por seu argumento AOP é algo que provoca acoplamento e aumenta a dependência, já que se baseia em substituir classes por stubs e proxies.

Recomendada a leitura do Patterns of Enterprise Application Architecture.

Regras de Négocio utilizam o padrão composto e aconselho que fiquem em uma classe separada.

Por exemplo: Se você tiver que implementar mais regras de négocio para cliente diferentes?

Classes de objetos do dominio, ou conceito do mundo real chamadas de Classe Conceitual.

Mas temos objetos chamados de Classe de Software - Classe que representa uma perspectiva de especificação ou implementação de um elemento de software, independente do processo ou método. Utilize o padrão Invensão Pura, sem obrigatoriamente utilizar um posfixo DTO, VO ect.

Uma classe anêmica só é anêmica se forçada.
Martin Fowler não expandiu tanto seu conceito assim.

“Mochileiro das Galáxias” KKK

@pcalcado, o que o Renatov (espero não ter me enganado) está tentando dizer é que (se entendi bem): Se uma entidade possui uma collection o Hibernate “injeta” um objeto que possui caracteristicas bem diferente de uma collection da api Java e que pertence a api do Hibernate, se algum método que manipule essa collection for acionado em um local onde a infra do hibernate não estiver presente ocorre a exception. Isso geralmente ocorre em sistemas onde o modelo está sob o “dominio” de um web server e o cliente é um swing por exemplo.

@todos, no livro pojo in action (indicado tambem pelo pcalcado, aliás obrigado por essa dica) o autor comenta sobre esse dilema.

flws

Cara, falando sério…

Não acho que o uso de DTOs deva ser condenado em ambientes não-distribuídos. É uma forma muito elegante de resolver o problema e usa o principio de separação de responsabilidades favorecendo o desacoplamento do código. Um problema que eu vejo em deixar o DTO de lado e criar uma classe que englobe tudo como no caso citado acima (Aluno), é o seguinte. Quando o DAO vai buscar alunos por classe por exemplo, você vai criar uma coleçào de alunos (classe Aluno com dados e métodos de negócio) e retornar para o view. Fica meio sem quê nem pra quê.
Além disso, o cara aí em cima lembro muito bem a facilidade em usar este padrão com os frameworks MVC que assumem este que DTO será o padrão usado na modelagem das classes de dados.

Cara, realmente são opiniões muito distintas…

Mas cheguei nesta conclusão após enfrentar um projeto imenso para secretaria de fazenda envolvendo um Contribuinte, Impostos, Declarações… Você já pensou no que seria um contribuinte com todas as suas regras de negócio e todos os seus atributos (sim, não há como negar que contribuinte possui atributos) em uma única classe, apenas para fazer com que Contribuinte seja responsável por tudo inerente ao contribuinte?! Concordo que seria lindo, que é o princípio de OO e tudo mais… mas é inviável. Teríamos uma classe com mais de 15000 linhas fora a persistência. Pense em um obterContribuintePorFiltro() em um DAO. Você já pensou na marreta que é instanciar uma classe de contribuinte com todos os seus métodos de negócio e persistência (entendo que se o contribuinte é responsável por tudo relacionado ao contribuinte, seus métodos não devem se limitar apenas a validação) e retornar uma coleção destes para exibir numa grid?
Prefiro saber que um contribuinte é um Contribuinte e que este contém as informações do meu contribuinte. Quem vai validar e estabelecer regras de negócio relacionadas a algum procedimento feito com um contribuinte é o objeto de negócio apropriado. Quem vai persistir é o DAO apropriado. Na view eu recupero e seto as informações do contribuinte e passo o contribuinte para quem sabe o que fazer com o contribuinte!

Mas é questão de opinião e experiência… Projeto grande faz a gente mudar a visão às vezes.

Discordo. O princípio de separação de responsabilidade alega que quem detém a informação é o responsável pela ação. Mas os DTOs não são detentores de informação nenhuma, é só um objeto repleto de atributos distintos.

Um Aluno englobar o que é inerente ao aluno não vejo como problema. Aliás, o que há de errado em se retornar um Aluno quando se solicita um Aluno?Ao menos para mim é estranho você retornar um objeto alienígena toda vez que solicitar uma entidade.

[quote=mvcsouza]
Além disso, o cara aí em cima lembro muito bem a facilidade em usar este padrão com os frameworks MVC que assumem este que DTO será o padrão usado na modelagem das classes de dados. [/quote]
Qual framework em específico assume que você utilizará um DTO?[/quote]

pcalcado,

Compreendo, mas no seu modelo “Sem DTO” o que chega para o Servlet? Não há dependência entre MostraAluno e Aluno? Acho que é uma dependência entra as três camadas da mesma forma… Prefiro trabalhar com aluno sendo apenas os dados do aluno. Quem tem que saber fazer os precessos em cima do aluno são as classes reponsáveis pelos processos. Veja que não discordo do seu ponto de vista com relação ao purismo OO. Mas não consigo concordar em manter uma estrutura pesada como um aluno quando tudo o que eu preciso na view são apenas os dados do aluno… E se existe uma possibilidade do seu projeto crescer e você separar o container web do de aplicações para distribuir? Deixa o peso da aplicação só la no container e nas classes de negócio… Acho que devemos expor o que é estritamente necessário para a camada. A view só precisa dos dados e passa a bola pra frente.
Por outro lado, se é para deixar tudo encapsulado em um Aluno, que este delegue para as classe especializadas como DAOs e BOs… Acho que não podemos querer puristas sempre, se fosse assim, o Aluno tinha que se persistir!!! Para que DAO?

Eu considero que há muito pano na manga para discussão…

[quote=Thiago Senna]
, desde que ele acesse uma interface que possui os métodos de persistência!

Ou seja, vc teria uma classes com seus métodos de persistência desacoplado da sua lógica de negócio, e sua classe de negócio é que diz quando ele deve ser persistido ou não![/quote]

Concordo, mas a interface que possui os métodos de persistência seria implementada por uma classe especializada, correto? E não o próprio Aluno como no caso em questão.

Essa é a discussão: até que ponto deve-se embutir funcionalidade numa classe que representa o Aluno e a partir de quando deve-se delegar para classes especializadas? Eu sou a favor do TO puro… Classes especializadas cuidariam do resto, mesmo com o efeito colateral da dependência do TO entre as camadas, que na minha opinião é perfeitamente aceitável e administrável. Alguma coisa tem que ser passada entra as camadas(View, Controller, Model), senão nào há comunicação entre elas…

caro pcalcado,

Temos uma percepçào um pouco diferente do que seria o DTO, ou de como usá-lo. No diagrama que você mostrou, com relação às sequencias do modelo com DTO, não há a necessidade de se persistir o estado no objeto Aluno, conforme você ilustrou. Isto já foi feito no DTO e esta é justamente a sua função, manter estado. Se o DTO mantém estado, não há necessidade de se criar um objeto Aluno e restaurar o estado a partir de um AlunoDTO, nem o contrário.

Veja um exemplo de como seria um pseudo fluxo em código:

/***********  Na Servlet ****************
AlunoDTO aluno = new AlunoDTO()
// persiste estado no DTO a partir dos parametros do request
aluno.setEstado( *** a partir dos parameters **** );  

GerenciadorAluno.incluir(aluno);




/**************************************
class GerenciadorAluno {
   
  public void incluir(AlunoDTO aluno) {
       // Valida o aluno e inclui via DAO ou se a inclusão for complexa e
       // envolver processos de negógio delega para o AlunoBO que se
       // encarrega de tratar as regras
       // AlunoBO.incluir(aluno);
        AlunoDAO.incluir(aluno);
  }
}

Esta é a seqüência. Portanto, perceba que não há necessidade de injetar o estado do aluno em um objeto Aluno a partir de um AlunoDTO. O alunoDTO em si é o estado. Penso que o objeto Aluno sugerido por você existiria como um BO, no caso da necessidade de validações especiais e realizações de regras de negócio durante determinada operação sobre o aluno.


Isto ao meu ver especializa o código e não espalha código como alguns colegas disseram. O desenvolvedor sabe com base no padrão onde está cada especialidade de código, seja validação, persistência e negócio. Além disso, a comunicaçào das mensagens entre as camadas se dá de forma muito mais otimizada, e de quebra eu não preciso alterar o meu código se algum dia precisar fazer uma chamada remota!

Abraços,

Nào entendi muito bem esta questão. Pelo que percebi, você atribui ao fato de se criar um Session Façade a solução das chamadas remotas? O que quis dizer foi que meus objetos DTO usados hoje apenas para manutenção de estado na aplicação seriam a forma mais adequada para transferência numa chamada remota, ou seja, não precisaria me preocupar com estruturas mais otimizadas para tranasferência de minhas entidades. As entidades já são esta estrutura.

Não sei se você usa esta prática em aplicações distribuídas com seus projetos, mas aqui é comum a criação de um session façade para cada módulo do sistema. Por exemplo, um façade para um módulo de Mátricula, um Façade para o módulo de cobrança, um façade para o módulo de Controle de Notas… Como a aplicação já trabalha desta forma (recebendo e devolvendo entidades DTOs) bastaria adicionar a camada EJB sem alterar muito as assinaturas. Claro que atentando para o padrão Session Façade (seu conceito).

Pense numa declaração de imposto que envolva dependentes, valores, bens, dados do contribuinte, rendas… E a quantidade gigantesca de regras associadas a cada variação em cada um de seus atributos no momento de sua criação?

Realmente, não entendi… No código do exemplo, o Servlet chama o gerenciador. Por favor, exemplifique o caso com um exemplo citando o nome da técnica ou padrão que deveria ser usado.

Valeu,

T+,

Com relação às suas perguntas direcionadas a performance de rede… Não sei, mas penso que a transferência de objetos burros será inquestionavelmente menos custosa em qualquer situação do que um objeto de mesma entidade com inteligência… Mas o fato do objeto conter listas e mais listas de referências a outros objetos seria um problema em qualquer situação numa tentativa de minimizar os custo de transferência. Este caso normalmente seria feito via gambiarra como você conhece o DTO!

Com relação ao último item, o código de exemplo já não está fazendo isso, na medida em que ele faz uma chamada ao Gerenciador ao invés de chamar diretamente o DAO?

Com relação a ser ou não burrice ou horrível passar Objetos burros na mesma layer… Realmente não considero. Acho que é uma forma padronizada e unificada de se representar a entidade… A questão agora em minha mente é:

Até onde vai a inteligência da Entidade?? Aluno tem que saber fazer o que com ele mesmo? Quando eu passo para o BO??

pcalcado,

Isso para mim é uma dura discussão… Seu exemplo na minha opinião expressa exatamente sua opinião que, como já te falei, não a considero de forma nenhuma incorreta. Só acho que ainda há uma etapada a ser vencida no seu código.

Uma coisa me surgiu na cabeça: Você falou sobre a separação entre a view e a aplicação usando uma camada leve e tal… Como o Gerenciador do Exemplo. Só que veja bem: Se eu recupero um aluno na view e restauro um estado qualquer neste Aluno, eu posso muito bem, na view, executar o Aluno.save() que, ao meu ver, seria um rompimento desta camada… Posso estar errado…

Vou colocar alguns trechos sobre este assunto que foi publicado por Fernando Lozano na java magazine (não sei qual sua opinião a respeito desta revista muito menos sobre o autor), mas vale como mais uma opinião:

"Talvez sua dúvida surja de um erro comum na modelagem orientada a objetos - o de modelar classes de informação, por exemplo “Cliente”, agregando a elas funcionalidades de negócios. Mas é necessario modelar os próprios processos de negócios, em geral decorrentes dos casos de uso do sistema. As classes que realizam tais processos não têm estado persistente (pois representam atividades sendo realizadas), e são elas que contêm a inteligência de negócios do sistema. Para modelar esses processos adequadamente, em vez de diagramas de classes, procure concentrar-se nos diagramas de atividades (para modelar o processo em si) e os de sequencia/colaboração (permitindo identificar como as classes trabalham juntas para realizar o processo no sistema) (…)

A classe ClienteDTO não deve ser responsável pela sua inclusão, atualização, etc. Nem, digamos, por validar o seu prórpio crédito ou classificar a si mesma como um “cliente vip”. Como o conceito de cliente é independente de tecnologias e produtos, por exemplo, de banco de dados, ele deve ser modelado numa classe separada e pode ser utilizado por vários processos de negócios diferentes. Por isso deve estar disponível de forma leve, sem sem criar dependências artificiais entre tais processos. (…)

Coloque agora o cliente em algum contexto, por exemplo, a venda de eletrodomésticos. Aqui o cliente poderia ser utilizado no processo de vendas, junto com dados do produto, nota fiscal, pagamento, condições de entrega, etc. Uma classe de negócios reúne todas as informações necessárias (os dtos correspondentes) e efetiva a operação, provavelmente chamando em sua implementação métodos dos DAOs relacionados e/ou outras classes de negócios.

Pense bem: não faz sentido, conceitualmente, inserir inteligência relativa à realização de uma venda em nenhuma classe de informaçào envolvidas. Será que a classe Nota Fiscal deveria saber como autorizar um pagamento por Cartão de Crédito? Deveria “PagamentoEmCartao” saber que existe uma promoçãoem que a própria loja está financiando o parcelamento sem juros do home theater sem repassar nada ao cliente? Estes dois exemplos ilustram possiveis violações de encapsulamento das classes envolvidas, mas o fato é que alguma classe precisa ter esta inteligência. "

Recomendo realmente a leitura deste artigo. Trata-se de um cara experiente que ilustra o texto com vários exemplos reais.

[]`s

Marco Vinicius

Agradeço a você por proporcionar uma discussão de muito bom nível com uma base forte de conhecimento. Isso nos ajuda a ampliar nossa capacidade de visualização dos problemas e como enfrentá-los de forma inteligente.

Caso tenha interesse na revista, procure adquirí-la no próprio site: Edição 20 - Ano III.