eu tava lendo alguns textos que falavam de transfer object, e eu vi a implementação dele…ele parece ser um javabean…é isso mesmo?
qual a diferença para um javabean?
no meu caso eu tenho um servlet(controller) um bo e um dao(ambos model)…
eu quero pegar alguns dados do meu banco de dados…
então eu acesso o meu bo e depois o meu dao. O dao cria o TO e retorna para o bo que retorna para o meu servlet para que os dados possam ser exibidos…
se eu não usar um TO qual seria a alternativa?
Rafael_Nunes
Para que o DAO precisa criar o TO?
Retorne as informações que precisa para o BO e do BO para o Controller.
J
jdeveloper
utilizar um TO é o modelo de implementação de DAO que está no corepatterns da sun…
qual seria sua sugestão?
usar uma collection?
_fs
Leia novamente o segundo link que o Thiago Senna postou.
Ele serve para encapsular diversas chamadas de rede numa só. Então te pergunto: seu banco de dados está fisicamente num lugar distante do local físico onde os servlets se encontram? Não? Então não precisa dessa gambiarra horrível \o/
Rafael_Nunes
É só uma das possibilidades de implementação do DAO. E mesmo no catálogo dos TO, eles são bem enfatizados o uso junto com EJB´s(geralmente aplicações distribuídas). Uma das principais vantagens de um TO é reduzir o tráfego de rede.
Você não precisa criar um objeto alienígena deste só pra passar de uma camada pra outra. Retorne uma Collection, ou o próprio objeto.
pcalcado
Que são belas gambiarras para tornar EJB algo menos horrível.
Você não precisa de DTOs fora de um ambiente distribuído.
J
jdeveloper
então eu transfiro data entre as classes através de retorno do método mesmo?
Ex.:
dentro do meu servlet ficaria assim:
List a = meuBO.getData();
dentro do meu método getData() do bo ficaria assim:
return meuDAO.getDATA();
e dentro do método getData() do meu DAO teria:
return list;
acho q ficou um pouco confuso isso q eu escrevi…mas… :roll:
pcalcado
Seu objeto de negócios (dica: evite esse padrão de nome de classes) acessa o DAO?
Thiago_Senna
Haáaaaaaaaaaaaaaaaaaaa!!!
Para com isso… vc me obrigou a me lembrar do dia que exibe uma arquitetura como esta como meu maior trunfo no meu projeto de final de curso!
JDeveloper, eu quando comecei aqui no guj tinha a mesma dúvida que você! Eu li o mesmo livro q vc, e cheguei nas mesmas conclusões q vc e o pior, cheguei nesta mesma arquitetura! Vc dúvida?? Veja isto entaum uma bagunça que eu tinha aprontado aqui no fórum!
Então, como vc não está trabalhando em um ambiente distribuído, esqueça o TO, esqueça o BO e mandem todos eles para a pqp!
Ao invés de vc sair criando classes como AlunoTO e AlunoBO, cria uma classe aluno logo de uma vez! É muito mais elegante e mais fácil. Ele guarda dados referente ao objeto e ainda encapsula as lógicas de negócio!
Com certeza, as únicas coisas que serão úteis no seu projeto são os DAO’s, e dependendo do tamanho do projeto, um AbstractFactory ou Façade já poderá ajudar bastante!
Agora pegue um pedaço de papéu e escreva 100x “Eu nunca vou usar DTO em sistemas não distribuídos!”
Abraços!
Thiago Senna
J
jdeveloper
pcalcado:
Seu objeto de negócios (dica: evite esse padrão de nome de classes) acessa o DAO?
qual o problema com o nome?
Eu tenho que fazer um cadastro via web. Então o usuário preenche os campos e dá um submit.
O meu servlet pega a requisição e chama o meu bo para validar campos e etc. O bo então chama o dao para persistir os dados, caso os mesmos sejam válidos…
isso não está correto?
J
jdeveloper
valeu pelas sugestões de leitura… não vou mais usar dto…
Só uma coisa… vc disse pra esquecer o bo…mas não é importante ter uma camada de negócios?
o código fica bem mais organizado?
Abraços
pcalcado
jdeveloper:
qual o problema com o nome?
Eu tenho que fazer um cadastro via web. Então o usuário preenche os campos e dá um submit.
O meu servlet pega a requisição e chama o meu bo para validar campos e etc. O bo então chama o dao para persistir os dados, caso os mesmos sejam válidos…
isso não está correto?
Funciona? Então está correto.
Só que tudo pode ser melhorado,e quanto mais você se preocupar com design do seu sistema, menos chance de virar noite dando manutenção em bugs bizarros.
Vamos devagar, do que se trata sua aplicação?
W
wellmattos
Eu gosto de usar DTO nas minhas arquiteturas, sendo elas distribuidas ou não, por exemplo para montar frameworks vc precisa utilizar um DTO para transferir os dados de uma camada para outra abstraindo assim por exemplo qual a interface que vc utiliza e deixando a regra de negocio limpa… utilizando apenas seus BO na camada de negócio não levando ele para a camada de interface…
pcalcado
wellmattos:
Eu gosto de usar DTO nas minhas arquiteturas, sendo elas distribuidas ou não, por exemplo para montar frameworks vc precisa utilizar um DTO para transferir os dados de uma camada para outra abstraindo assim por exemplo qual a interface que vc utiliza e deixando a regra de negocio limpa… utilizando apenas seus BO na camada de negócio não levando ele para a camada de interface…
Para usar frameworks decentes (ou até indecentes como Struts) você não rpecisa de VO. Aliás, você só rpecisa deles numa arquitetura altamente distribuída (que as blueprints do JEE sempre prezam, mas que quase nunca acotnece no mundo real).
O que você chama de montar frameworks?
J
jdeveloper
É o seguinte:
Eu tenho q fazer um sistema que faz a inscrição de um usuário online.
Então ele tem basicamente que preencher um cadastro pessoal e de acordo com o tipo de opcao de inscricao q ele escolhe o sistema exibe uma ou outra opção nas telas.
Eu pensei em fazer o seguinte:
Usar um jsp como minha camada de apresentação.
Usar um servlet como controlador.
Usar um BO e um DAO como meu model.
Então o usuário preenche o cadastro(jsp) e envia para o servlet. Esse servlet pega os dados do usuário, armazena em um objeto e envia para a minha camada de negócios para basicamente validar campos.
Se os dados digitados pelo usuário estiverem corretos eu passo esse objeto para a minha camada de negócios para q ele possa ser persistido.
Entendeu?
Isso não está correto?
_fs
Está correto. E basta um objeto Aluno, um AlunoDAO e um CadastroServlet para isso
classCadastroServlet{publicvoidexecute(){Alunoaluno=newAluno();// popula o objeto aluno com os dados da requestif(!aluno.validate()){// redireciona de volta com os errorreturn;}AlunoDAOdao=newAlunoDAO();dao.save(aluno);// ou quem sabealuno.save();// aluno que chama o DAO}}
J
jdeveloper
LIPE:
Está correto. E basta um objeto Aluno, um AlunoDAO e um CadastroServlet para isso :D
classCadastroServlet{publicvoidexecute(){Alunoaluno=newAluno();// popula o objeto aluno com os dados da requestif(!aluno.validate()){// redireciona de volta com os errorreturn;}AlunoDAOdao=newAlunoDAO();dao.save(aluno);// ou quem sabealuno.save();// aluno que chama o DAO}}
não seria melhor criar mais uma classe para validar os dados...ao invés de validar os dados dentro do servlet...?
_fs
Existem diversas maneiras de validar dados escolha a sua hehe
Eu gosto de usar strategy:
classAluno {
privateValidationStrategyvalidationStrategy;
publicbooleanvalidate() {
validationStrategy.validate( this );
}
}
A implementação de ValidationStrategy varia.
kina
Uma pergunta.
Qual a diferença dos dois? (Aluno, AlunoVO) ??
Por acaso o Aluno tem regra? o aluno faz persistência?
Porque no meu VO eu não deixo assim:
Assim deixando a minha classe “mais leve” pois não tenho métodos para serem persistidos?
_fs
Serialize uma classe com 10 métodos e outra com 100 métodos e compare os tamanhos dos arquivos. Se o “overhead da sua rede” for grande demais, use VO
Thiago_Senna
jdeveloper:
Só uma coisa… vc disse pra esquecer o bo…mas não é importante ter uma camada de negócios?
o código fica bem mais organizado?
Vc precisa saber trabalhar com sua camada de negócio, não com o Desgin Pattern Business Object.
No dia a dia, vc vai ver que o pessoal nem fala em BO, eles falam logo classes de negócio.
Por exemplo, no exemplo que o Lipe passou, a classe Aluno possui um método validate! E vc perguntou se não seria melhor criar uma outra classe para cuidar da validação.
Isso vai do seu gosto, mas já que está usando OO, nada melhor do que o próprio aluno validar seus próprios dados!
Voltado ao assunto BO, a classe Aluno seria equivalemente a classe AlunoBO. Subtende-se que a classe Aluno é a classe de negócio e acabo! Business Object é um design pattern que até hoje eu naum sei pq criaram ele!
J
jdeveloper
Thiago Senna:
Voltado ao assunto BO, a classe Aluno seria equivalemente a classe AlunoBO. Subtende-se que a classe Aluno é a classe de negócio e acabo! Business Object é um design pattern que até hoje eu naum sei pq criaram ele!
Entendi o q vc quer dizer…
Mas eu to pensando em fazer uma classe CadastroServlet, uma AlunoBean, uma AlunoBO e uma AlunoDAO…
assim a classe q vc chamou de Aluno ficaria só pra armazenar os dados do aluno(AlunoBean).
o q vc acha?
Thiago_Senna
jdeveloper:
Thiago Senna:
Voltado ao assunto BO, a classe Aluno seria equivalemente a classe AlunoBO. Subtende-se que a classe Aluno é a classe de negócio e acabo! Business Object é um design pattern que até hoje eu naum sei pq criaram ele!
Entendi o q vc quer dizer…
Mas eu to pensando em fazer uma classe CadastroServlet, uma AlunoBean, uma AlunoBO e uma AlunoDAO…
assim a classe q vc chamou de Aluno ficaria só pra armazenar os dados do aluno(AlunoBean).
o q vc acha?
O que eu acho, péssimo…
Criar uma classe AlunoBean e outra AlunoBO é uma coisa muito feia!
O exemplo que o pessoal passou é um espetáculo, onde Vc tem uma classe Aluno, AlunoDAO e o CadastraAlunoAction (Controle)!
Se vc quer não quer o método validate dentro da classe aluno (aluno.validate()), então cria uma classe só pra validação, tipo
ValidateUtil, NegociaValidateUtil, sei lá!
Uma outra possibilidade é vc fazer a validação dos dados do aluno no controle. Se o seu controle + view garantir que não entrará dados inválidos na camada de negócio, então vc pode optar por não usar a validação dentro da classe aluno!
J
jdeveloper
Obrigado a todos pela ajuda…alguns conceitos estão muito mais claros agora…
Abraços
_fs
JDeveloper, o que estamos tentando te dizer é que não há necessidade de ter AlunoBean e AlunoBO :thumbup:
Pode nos dizer por que acha que é necessário? Ou é uma questão de gosto mesmo?
pcalcado
kina:
Assim deixando a minha classe “mais leve” pois não tenho métodos para serem persistidos?
Num DTO de verdade, utilizado para transmitir dados por uma rede e não para pegar dados do DAO e passar pro Joãozinho, você vai querer minimizar o tráfego, então é bom observar bastante os seus casos de uso e achar a melhor maneira de empacotar dados dos objetos de verdade em DTOs gordos que só servem para isso.
O padrão memento pode salvar vidas neste caso.
_fs
Como??
J
jdeveloper
LIPE:
JDeveloper, o que estamos tentando te dizer é que não há necessidade de ter AlunoBean e AlunoBO :thumbup:
Pode nos dizer por que acha que é necessário? Ou é uma questão de gosto mesmo?
Eu acho q o código fica mais limpo se vc usar uma classe bean só pra armazenar dados do usuário e outra classe para realizar as regras de negócio.
No meu caso eu pretendo usar uma classe para armazenar os dados obtidos em várias telas. A cada tela que o usuário vai preenchendo eu vou adicionando os dados a essa classe.
Se eu armazenar os dados do usuário e as regras de negócio somente em uma classe essa classe vai ficar muito grande…o q eu acho ruim.
Entendeu?
pcalcado
LIPE:
Como??
Pegue seu objeto, extraia um memento. Junte todos os mementos dos objetos que precisar passar pela rede, empacote num grande DTO e mande pela rede.
Na outra ponta, injete (palavrinha na moda 8) ) o memento nos objetos do cliente, fazendo um update.
Na real é um jeito de evitar assemblers.
_fs
Shoes: mas para que juntar os mementos num DTO e não os próprios objetos?
Quantos atributos suas classes costumam ter a ponto de “ficar muito grande” colocar mais uma meia dúzia de métodos de negócio? @.@
pcalcado
LIPE:
Shoes: mas para que juntar os mementos num DTO e não os próprios objetos?
Um memento deve ser menor (em recursos, memória, blablabla) que um objeto inteiro, e ele tem o mínimo necessário apra recompôr o estado.
Quando você tem problemas numa rede a ponto de realmente precisar de DTOs, passar o mínimo possível de bytes pelo fio é essencial.
J
jdeveloper
LIPE:
Quantos atributos suas classes costumam ter a ponto de “ficar muito grande” colocar mais uma meia dúzia de métodos de negócio? @.@
é uma classe de cadastro…então tem nome,idade,rg,cep,cpf,etc…
enfim…tem pelo menos 20 atributos…
20 atributos + 20 get + 20 set + os métodos de negócio…é bastante, não acha?
_fs
Shoes: entendi realmente boa idéia.
jdeveloper: ah … getters e setters isso faz mal cara hehe
F
fabio.patricio
jdeveloper:
LIPE:
Quantos atributos suas classes costumam ter a ponto de “ficar muito grande” colocar mais uma meia dúzia de métodos de negócio? @.@
é uma classe de cadastro…então tem nome,idade,rg,cep,cpf,etc…
enfim…tem pelo menos 20 atributos…
20 atributos + 20 get + 20 set + os métodos de negócio…é bastante, não acha?
Nao.
Faca a dica do Lipe. Pegue esse teu objeto e serialize ele em disco. Pegue uma lista com pequena quantidade desse objeto dentro e serialize em disco tb, pegue uma lista com grande qunatidade de objetos deste dentro e serialize tb. Verifique o tamanho e faca sua avaliacao.
É a melhor maneira para ter uma boa conclusao do que é grande ou nao para trafegar na rede.
]['s
_fs
fab, penso que ele se referiu ao tamanho do código.
[size=8]fab :XD:[/size]
J
jdeveloper
LIPE:
fab, penso que ele se referiu ao tamanho do código.
[size=8]fab :XD:[/size]
é isso mesmo…o código fica muito grande…a manutenção fica mais difícil…
_fs
Para mim difícil é manter um relacionamento que só faz sentido para “o código não ficar muito grande” hehe
Na sua IDE não tem code-folding? Já tentou não usar getters e setters?
J
jdeveloper
LIPE:
Na sua IDE não tem code-folding? Já tentou não usar getters e setters? :D
não sei o q é code-folding :roll: atualmente eu to usando o netbeans 4.1
como é que eu vou preencher os meus atributos sem utilizar set? tiro o encapsulamento? melhor não,neh?
como é que eu vou pegar os dados para depois persistir sem usar get?
Rafael_Nunes
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.
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.
Qual framework em específico assume que você utilizará um DTO?
F
fabio.patricio
jdeveloper:
LIPE:
fab, penso que ele se referiu ao tamanho do código.
[size=8]fab :XD:[/size]
é isso mesmo…o código fica muito grande…a manutenção fica mais difícil…
Haaaa…nesse caso esquece os get e set burro sem necessidade. :mrgreen:
E falando nisso, fazer em duas classes nao ficaria maior nao? Alem de ter um outro .java enchendo o saco.
]['s
Thiago_Senna
Olá!
jdeveloper:
é uma classe de cadastro…então tem nome,idade,rg,cep,cpf,etc…
enfim…tem pelo menos 20 atributos…
20 atributos + 20 get + 20 set + os métodos de negócio…é bastante, não acha?
1 - Talvez vc possa melhor seu modelo. Por exemplo, quando houver muita coisa, talvez vc possa quebrar esta classe em outras responsabilidades. Por exemplo, vc poderia criar uma classe Endereco. Na classe endereco vc coloca o endereco, cidade, bairro, rua, cep e etc…
Tente identificar em suas classes que é possível melhorá-las, e desacoplar dados em comum em uma outra classe!
2 - Não vejo problemas caso haja 20 atributos e 40 getters e setters em sua classe. Se vc não tiver como fugir dos getters e setters, e só vc se organizar. Por exemplo:
Se organize, que cria algumas convenções como por exemplo, deixe todos os seus métodos de negócio no final da classe! Assim, se vc tiver que trabalhar em algum método de negócio, vc sabe que a única coisa a fazer é se mover para o final do arquivo e encontrar o seu método de negócio!
Com os recursos das IDE´s que temos hoje, como o eclipse por exemplo, segure o control e clique com o mouse em cima do método que ele já te leva para a implementação do método!
Não há pq separar uma classe contendo só os métodos de negócio!
Abraços!
Thiago Senna
F
fabio.patricio
:?
J
jdeveloper
fabgp2001:
E falando nisso, fazer em duas classes nao ficaria maior nao? Alem de ter um outro .java enchendo o saco.
]['s
Se for pensar assim (quanto menos classes melhor)…então faz tudo em uma classe só…os dados do aluno as regras de negocio e os metodos de persistencia… eu acho q fica muito feio!
pcalcado
Você pode me dizer como? Qual a responsabilidade do DTO e do tal BO?
A responsabilidade do DTO é pegar os dados do BO e passar para outro canto? Porque você não passa o BO?
Neste modelo você vai ter lógica de negócios altamente acoplada ao DTO, DTO altamente acoplado ao BO e View altamente ao DTO.
Lembre que dependência é transitiva, então tudo continua dependendo de tudo, e com mais o DTO no meio. Talvez assim seja melhor:
Como assim?
Para você faz mais sentido criar uma classe B que é uma cópia burra de outra classe A, e que no fim B vai ser usado para gerar um A?
Por que você não gera A em primeiro lugar? Qual o benefício do itnermediário?
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.
Não existem (ou pelo menos não deveriam existir) “classes de dados” num modelo baseado em objetos.
Na verdade, me parece que o problema é um só: separação de responsabilidades. Pelo que você falou, seu entendimento de OOP o faria entupir o tipo com todos os métodos referentes a ele, na verdade você deveria separar as reponsabildiades entre outras classes.
Se você puder citar alguns casos problemáticos da tal classe, podemos trabalhar esse exemplo.
Bom, eu concordo em geral, mas não neste ponto. primeiro porque eu trabalho e trabalhei com projetos grandes e compelxos ao extremo, e os princípios de OOD foram formados baseados em projetos muito mais complexos do que eu ou a grande maioria dos frequentadores do GUJ pode sonhar em meter a mão.
Mauricio_Linhares
Assim, DTO é lixo e só serve pra uma coisa, consertar uma falha dos EJBs, quem não usa EJB não deveria estar usando esse tipo de gambiarra.
Thiago_Senna
Você consegue criar alunos capazes de se persistir e mantendo um código legível…
Como já rolou em outras discussões aqui no guj, Active Record é interessantíssimo, e além do mais, existem outras maneiras de seu objeto ser capaz de se persistir, 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!
pcalcado
Sim, falta a seta entre eles.
A pergutna é, para cada objeto de negócio você pode depender apenas do objeto em questão ou gerar uma dependência desnecessária utilizando um DTO. Para um exemplo com uma classe não aprece muito, mas isso vai crescer expotencialmente num sistema de verdade, e cada vez que você alterar uma coisa, vai alterar todo o ciclo de dependência.
O ponto é: em termos de acoplamento e dependência, DTO só piora.
Isso é programação procedural e existem ferramentas melhores para programar assim do que Java.
Vamos analisar o fluxo:
1 - Com DTO
2 - Sem DTO
Semrpe existe essa possiblidade, um bom projetista vais aber avaliar o custo/beneficio de toda flexibilidade.
Nesse caso especifico, você está falando de um cenário onde um DTO é um bom negócio. O que nós estamos discutindo é onde ele não é um bom negócio.
Acho que entendi seu ponto. O poblema é que você está colocando responsabilidades demais em Aluno.
Um aluno tem por responsabilidade executar suas regras de negócio (entrar em um curso, sair do curso, retornar seu boletim, sei lá…), o que você está falando é em misturar as responsabilidades de outras classes no aluno, por isso pedi um exemplo
Code-folding são aquelas setinhas que aparecem do lado do código para poder abrir/fechar o código. Assim ficam escondidas as linhas de código que não precisa ficar olhando o tempo todo. Acho que tem no Netbeans!
Sobre setters, é exatamente o contrário do que falou hehe quebrar o encapsulamento é chamar esses getters/setters de fora. Para preencher os atributos de seu objeto, use o construtor
Sobre a ausência de getters/setters, leia meus favoritos! Isso foi amplamente discutido aqui no fórum, recomendo a leitura.
F
fabio.patricio
jdeveloper:
fabgp2001:
E falando nisso, fazer em duas classes nao ficaria maior nao? Alem de ter um outro .java enchendo o saco.
]['s
Se for pensar assim (quanto menos classes melhor)…então faz tudo em uma classe só…os dados do aluno as regras de negocio e os metodos de persistencia… eu acho q fica muito feio!
jdeveloper,
Mas estamos falando de duas classes que dizem respeito ao mesmo Objeto, no caso aluno. Nao da pra generalizar como tu fez.
]['s
_fs
mvcsouza entenda que não estamos falando que DTOs nunca devem ser usados. Só estamos dizendo que só devem ser usados em ambientes altamente distribuídos APÓS ter certeza absoluta que a carga de rede está exagerada.
E também não estamos falando para colocar todo o código dentro de Aluno. Mas é dividir as responsabilidades com coerência:
Como deve bem saber por ter participado de projetos grandes, a primeira abordagem rapidamente se torna um inferno de manutenção com código repetido espalhado por todo o projeto.
Thiago_Senna
Muito bém colocado! Com certeza, este é um fator que pode ser um diferencial em um projeto de grande porte!
Hoje estou fazendo refactoring em uma aplicação o o programador usou bastante buffer.write()., buffer.newLine() e buffer.flush(); sempre usando a mesma sequência! O texto que estava sendo passado dentro dos métodos Estava em inglês!
Dái, me abriram um bug para passar para Português! Pronto! Ferrou!
Essa rotina que usava 5 linhas se repete em média 12x distribuidamente em 17 queridas classes!
17 x 12 X 5 = 1020
Agora com meu refactoring, o q antes estava usando 5 linhas começara a uasr 2 linhas, entaum:
17 * 12 * 2 = 408
logo
1020 - 408 = 620
Nessa brincadeira estou eliminando 620 linhas de código desnecessárias.
Acho que este seria um exemplo simples para ilustrar como algumas rotinas repetitivas (mesmo que bém organizadas) podem ser simplificadas!
Fazer este refactoring nisso está super dispendioso, e vou com certeza levar mais de um dia para terminar!
mvcsouza, em minha opinião, acho que sempre que possível é melhor optar pela simplicidade! Apesar de vc gostar desta estrutura com TO, acredito que não usar o TO torne a aplicação mais simples, e até mesmo mais desafiador.
Abraços!
Thiago
pcalcado
Então o que voce está usando não é um DTO/VO/TO. Estes objetos existem apra transmitir dados, não para ser o estado de uma entidade.
No seu caso, então, meus diagramas estão errados, porque existe uma dependência de aluno para o DTO.
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!
Otimizada por que?
Você cria uma classe a mais para cada classe de negocio hoje para evitar que num futuro que pode acotnecer ou não (o mais provável) você não precise criar uma classe para todas as operações remotas (que pode ser uma Session Façade, por exemplo)?
Me diz qual a vantagem de fazer isso e criar uma Façade Remota que retorna e recebe objetos “Aluno”.
E, novamente, qual exemplo você dá de uma classe que tenha tanta regra de negócio que fica impraticável utilizar OOP?
Um outro problema no codigo eh o servlet tocando a camada de persistencia diretamente, utilize uma camada de aplicação leve para isso.
pcalcado
Ola,
Existe uma diferença entre layer e tier. Utilizar DTOs para passar entre layers é besteira se stas ficam na mesma tier. Essa é a discussão. Se você ler o tópico, vai ver que todos aqui comentaram que DTO é sim válido para chamadas remotas. É um mal necessário.
Entretanto, pelo menos num ambiente normal, dificilmente você terá interfaces remotas que justifiquem um DTO. Mesmo onde você tem tais interfaces, é conveniente utilizar um profiler, verificar o tamanho dos objetos serializados, tráfego na rede e todas as outras variáveis para definir o DTO a ser utilizado, lembro que não rpecisa haver um mapeamento de 1 para 1 entre DTO e objeto, pelo contrário, é melhor você colcoar vários objetos num só DTO para economizar recursos.
Sou contra soluções tamanho-unico, mais ainda se envolve EJB. nos projetos em que trabalho varia sempre, e semrpe tentando eliminar ao máximo de EJB em função de tecnologias mais leves.
Pergunta simples:
Sabendo que o problema em trafegar dados em um sistema distribuído numa rede é basicamente o RPC e necessidade constante de trocar dados o tempo todo, o padrão DTO é utilizado para minimizar estas chamadas. Se seus DTOs são menores que um objeto de verdade, qual a vantagem em utilizá-los ao invés de apenas mandar o objeto?
Economizar alguns bytes na transmissão? Vale a pena aumentar a complexidade do seu projeto, criando uma classe só com estado, outra só com comprotamento, só para passar menos dados numa rede?
O real problema de transmissão em sistemas distribuídos não é o tamanho dos objetos individualmente, que geralmente é insignificante, mas sim a quantidade de vai-e-vem de dados o tempo todo e o tamanho do grafo de objetos que deve ser passado, que vaid epender basicamente do que o cliente vai fazer com os objetos.
No exemplo, se AlunoDTO tem uma referencia a um CursoDTO (ou curso BO, nao sei como vc prefere relaciona-los), e CursoDTO tem referencias a diversos outros AlunoDTO, que tem referencias a outros CursoDTo que por sua vez referenciam mais AlunoDTO… como seu DTO te ajuda a melhorar o desempenho?
A discussão já está descambando para a melhor estratégia em um DTO, mas o meu ponto é que não vale a pena complicar sua camada de negocios e criar classes que não obedecem os principios basicos de OOP para um requisito que:
1 - Não é onipresente (pelo contrário, é bem infrequente. Quantos aqui tem a camada de negocios em um servidor e a de web em outro na maioria dos projetos? Quantos viram isso uma ou duas vezes? Quantos nunca viram isso?)
2 - Pode existir, mas não ser necessário o uso de DTO (POJOs podem dar cotna do recado em muitos casos)
3 - Se realmente necessário, pode ser solucionado de uma forma melhor, usando Transfer Object Assemblers em cima de objetos de negócio.
Penso, mas não consigo entender porque você não consegue distribuir isso em objetos ao invés de usar registros.
A técnica se chama Programação em Camadas e Separaçãod e Responsabilidades, você poderia implementar uma Camada de Aplicação (Application Layer) utlizando, por exemplo um façade, ao invés de acessar o DAO de vez, atropelando a Camada de Negócios.
[]s
pcalcado
Bom, isso é fácil de testar
Como falei, fazendo o teste você vai comprovar que não importa passar 50kb a menos, o que importa é minimizar a comunicação, apra isso um DTO empacota tudo que o cliente vai rpecisar, esta é sua finalidade.
Como num mesmo nó você não tem dificuldade em comunicação (está tudo no mesmo espaço de endereçamento), você não vai precisar de um DTO.
Perdão, você está certo, eu não havia vista que começava outro arquivo no meio da tag [ code ], era isso que eu estava dizendo.
Até onde vai a inteligência da Entidade?? Aluno tem que saber fazer o que com ele mesmo? Quando eu passo para o BO??
O BO é o aluno. Isso resume OOP. Estado e comprotamento no mesmo construto.
Agora se você está pergutnando se o aluno tem que ter toda a lógica referente a ele, a respsota é simplesmente: não. Por que? Por que muitas relações em que o aluno participa são de responsabilidade de outros objetos, e devem ser distribuídas.
Imagina o seguinte:
Pelo que eu estou entendendo do seu ponto de vista (eu posso muito bem não ter entendido nada, ams é o que eu acho), o aluno deveria ter algo assim:
Isso foi um exemplo idiota, mas o princípio é este: separar responsabilidades.
pcalcado
Você não está rompendo a separação de camadas se não tocar uma camada que nãoe steja ligada, no caso do save(), não há problema.
Eu sabia que esse artigo ia causar coisas deste tipo
Eu tenho essa revista e estou inclusive escrevendo um post no meu blog sobre isso. Fernando Lozano é sim um cara muito respeitado, mas o que ele afirma não tem fundamento na literatura.
Essa coisa de “antigamente se acahva tal, hoje em dia se acha isso” sem nenhuma referência, sem nenhum motivo (caso seja ele mesmo o autor da teoria), não me parece válido.
Tivemos uma discussão sobre um outro artigo dele aqui, eu o convidei para entrar mas parece que ele não teve tempo de participar.
Eu acho terrivelmente equivocada esta abrodagem e lamento que seja divulgada num veículo tão abrangente como a Java Magazine sem qualquer referência de onde se possa ter mais informação sobre essa teoria.
Segundo o que já li, o futuro da orientação a Objetos é ser Estruturada, com dados de um lado e lógica de outro. Isso não me parece sensato.
Até a próxima então
[]s
C
carneiro
pCalcado,
Finalmente algum tipo de esclarecimento. Realmente eu estava confuso com este tópico, pois o artigo do Fernando Lozano foi um dos meus primeiros contatos com patterns…
Para mim sempre foi regra que: aluno.save() é ruim!
Agora é hora de considerar melhor a questao.
Rubem_Azenha
puxa, eu sei que não é legal colocar objetos totalmente burros em seu sistema, mas deixar os objetos super dotados não me parece muito bom…
pcalcado
O que voce chama de objetos super-dotados?
faq
O que voce chama de objetos super-dotados?
Implicitamente: são objetos com muitos comportamentos.
O que nos leva a uma chamada recursiva nos topicos “programação procedural - objetos burros” , que só pode ser finalizada quando todos souberem que objetos são formados por comportamentos + dados.
Essas tópicos longos com opniões diferentes são o bicho. xD .
Nem sempre é preciso utilizar patterns. Mesmo quando utilizadas, suas patterns não precisam ser identicas ao do autor do livro ou artigo, é preciso saber ser flexivel e toma-las como uma base segura para a sua propria criação. Ou utilizar tim tim por tim tim se ela “te cair como uma luva”.
pcalcado
A grande dificuldade que eu vejo nas duvidas comoe sta eh uma soh: separar responsabilidades.
faq:
Nem sempre é preciso utilizar patterns. Mesmo quando utilizadas, suas patterns não precisam ser identicas ao do autor do livro ou artigo, é preciso saber ser flexivel e toma-las como uma base segura para a sua propria criação. Ou utilizar tim tim por tim tim se ela “te cair como uma luva”.
O mesmo com paradigmas (como OOP), a questao eh que ate agora, neste ou em tantos outros topicos, ainda nao vi um caso onde realmente fosse rpeciso adaptar os conceitos drasticamente.
faq
Por isso são patterns.
Mauricio_Linhares
carneiro:
Para mim sempre foi regra que: aluno.save() é ruim!
Dependendo de como você vai fazer, pode ser bom ou ruim. Eu, por exemplo, implementei o Active Record (o padrão que botaria o “save()” no aluno) com uma única interface (usando AOP) e sem adicionar uma linha de código nas classes do modelo (o Aluno, Turma, Disciplina, Produto ou seja lá o que for).
O que você tem que garantir é que a coisa seja maleável, que seja fácil de dar manutenção e de testar (não ficou tão fácil de testar quanto eu pensava, entretanto…).
pcalcado
Como ja mencionei algumas vezes aqui, ao inves de AR puro e simples, eu prefiro uma abordagem baseada em Observers.
Quando o objeto muda de estado (ou quando recebe um .svae(), mais pratico e usavel) ele avisa seus observadores, o DAO, Repositorio, whatever eh um destes.
Thiago_Senna
IMHO, se seu objeto estiver super dotado é pq ele tem responsabilidade demais, e ele entaum poderia ser quebrado em mais classes de negócio. Assim, todos seus objetos se manteriam simples!
Mas pq ficou mais difícil de testar? Por causa do AOP? Ou por causa do ActiveRecord?
Quando eu testo, eu apenas passo um mock para minha classe de negócio, e no final do teste verifico se o método dao.save(aluno) foi realmente chamado e se recebeu o objeto correto por parâmetro.
UserStorieuserStorie=null;MockmockPM=null;publicvoidsetUp(){userStory=newUserStory("Saving a user story");userStory.setContent("XPTurbine must save user stories.");userStory.setEstimatePoints(2.5f);mockPM=newMock(PersistenceManager.class);}publicvoidtestSaveUserStorie(){mockPM.expectVoid("save",userStory);ReleaseManagermanager=newReleaseManager();manager.setPersistenceManager((PersistenceManager)mockPM.proxy());manager.saveUserStory(userStorie);}publicvoidtearDown(){mockPM.verify();}
Entaum, baseado no exemplo acima, apesar de não ser exatamente um AR, acredito que testar um AR não deve ser muito diferente disso!
Estou errado?
Abraços!
Thiago
cv1
Thiago, o singular de “user stories” eh “user story”
Thiago_Senna
Valeu Carlos, vou arrumar os lugares onde cometi este pequeno deslize!
Mauricio_Linhares
Por causa da AOP, o meu código não fica nas classes do modelo como o seu. É difícil de explicar :lol:
Quando você mexer no AspectJ vai entender :mrgreen:
_fs
pcalcado:
Como ja mencionei algumas vezes aqui, ao inves de AR puro e simples, eu prefiro uma abordagem baseada em Observers.
Quando o objeto muda de estado (ou quando recebe um .svae(), mais pratico e usavel) ele avisa seus observadores, o DAO, Repositorio, whatever eh um destes.
Isso parece legal, mas quais as vantagens em cima de uma simples chamada ao DAO/Repository/WTFory?
pcalcado
LIPE:
Isso parece legal, mas quais as vantagens em cima de uma simples chamada ao DAO/Repository/WTFory?
Imagina seu Façade:
void createNewBugbear(){
bugBear b = bugBearFactory.create();
b.save();
}
Ou
void createNewBugbear(){
bugBear b = bugBearFactory.create();
bugBearDao.save(b);
}
Fora que assim você poderia passar seu objeto diretamente à camada cliente e ela salva-lo quando apropriado (ainda não pensei sobre isso direito).
_fs
Não expressei minha dúvida corretamente. Gosto sim de AR, o que te perguntei foi relacionado à aplicação de Observer
Os repositórios ficam entre os clientes (BugBearManager) e o domínio e referenciar uma camada superior de uma inferior é problema (e isso já deu uma bela discussão na lista de domaindrivendesign).
Se você colocar repositórios como observadores, elimina essa relação baixo-cima com uam abstração.
_fs
Aí na minha humildérrima opinião é perfumaria à toa. Além de gerar outro problema: como diferenciar os diferentes métodos a serem chamados no Repository sendo que com Observer tudo o que pode se fazer é um notify?
se protege do olhar assassino de Shoes
pcalcado
:evil: :evil: :evil:
Ok, mas se tiver algum outro observador, eu padronizaria isso
E o delete()? E se o método create() deve retornar a chave primária? E no caso de load()?
pcalcado
LIPE:
E o delete()? E se o método create() deve retornar a chave primária? E no caso de load()?
O Repositorio continua existindo apra estas coisas
A coisa toda é evitar que todo método de uma interface XYZManager fique salvando o bojeto toda hora (se você rpecisa usar dois ou mais destes num caso de uso, se ferra).
_fs
Entendi, mas uma solução parcial não me parece suficiente:
ahmm… Eu apenas gostaria de registrar aqui minha insatisfação com o uso indiscriminado do DAO pattern.
public class ScrublesDAO {
public void save(Pojo object) {
hibernate = getSession();
hibernate.save(object);
closeSession();
}
public void delete(Pojo object){
hibernate = getSession();
hibernate.delete(object);
closeSession();
}
(...)
}
public class BubblesDAO {
public void save(Pojo object) {
hibernate = getSession();
hibernate.save(object);
closeSession();
}
public void delete(Pojo object){
hibernate = getSession();
hibernate.delete(object);
closeSession();
}
(...)
}
Não é que DAO seja uma idéia ruim, mas a interface Session do Hibernate já nem tem funcionalidade suficientes para a maioria das necessidades de um DAO. IMHO, se você puder evitar utilizar um DAO (e usar uma entidade mais genérica) melhor, você não acha ?
_fs
Para as operações CRUD dá para generalizar sim, ainda mais com Generics como o cv mostrou
Mas não me lembro de criar um DAO/Repository/WTFory só com esses 4 métodos hehe
rodrigousp
Acho que a maioria dos DAOs se resumem a isto. Acho que você poderia querer fazer buscas para alguns objetos chaves. Nesse caso, você poderia utilizar uma classe para realizar as operações de busca. Se isto ainda não for suficiente, ou as operações CRUD forem mais complexas do que as descritas aqui, então o padrão DAO pode ser (muito bem) considerado.
Agora, eu nunca utilizei o generics e sempre consegui generalizar o CRUD (no hibernate), porque o parâmetro desses métodos no session é Object.
Estava passando por um dilema sobre DTO.
Estava pensando em usar DTO’s dinâmicos ou DTH (Data Tranfer HashMaps)
Vi que é bem utilizado pelo pessoal lá fora
só pra dar seqüencia nesse tópico (que está muito, muito maneiro)
eu não gosto de nenhuma das duas idéias.
Em um projeto recente vi que a abordagem do DTH seria legal mas fiquei com receio de complicar muito o código e acabei optando por usar CachedRowSet que, ao meu ver, reduziria esse risco (Floyd Marinescu sugere isso como um pattern mas eu nunca vi ninguém falando em CachedRowSet que não fosse a implementação da sun).
desculpem se falei alguma m ok?
acabei de chegar por aqui.
Também gostaria de trocar idéias sobre isso.
O
okara
Ressucitando o tópico…
Por que os DTH complicariam o código ?
louds
okara:
Ressucitando o tópico…
Por que os DTH complicariam o código ?
Porque você precisa de uma pensa de sets de uma lado e uma tonelada no outro?
Fora que DTH são um engodo, eles geram um tráfego enorme de dados e consomem memória a rodo.
marcelomartins
louds:
okara:
Ressucitando o tópico…
Por que os DTH complicariam o código ?
Porque você precisa de uma pensa de sets de uma lado e uma tonelada no outro?
Fora que DTH são um engodo, eles geram um tráfego enorme de dados e consomem memória a rodo.
Depende.
DTH são uma boa maneira de abstrarir os Beans entre as camadas. E se o trabalho de gerenciar os HashMaps for bem feito (leia-se, o programador não precisa fazer nada) eu acho uma boa alternativa.
O
okara
Tem como dar um exemplo disso ?
marcelomartins
okara:
‘marcelomartins’:
DTH são uma boa maneira de abstrarir os Beans entre as camadas. E se o trabalho de gerenciar os HashMaps for bem feito (leia-se, o programador não precisa fazer nada) eu acho uma boa alternativa.
Tem como dar um exemplo disso ?
Não consegui pensar em nada simples para te exemplificar, então imagina no teu sistema web tu não quer que o JSP conheça tuas classes do dominio.
Então, antes de chegar no JSP uma classes de infraestrutura (framework) ve todos as classes que estão populadas e transforma para HashMaps. No JSP dá pra trabalhar como se fossem as classes no lugar dos HashMap, é transparente.
Não sei se fui bem claro, mas foi uma tentantiva.
O
okara
Você transporta os objetos em forma de hashmaps ?
É isso ?
Mas que vantagem isso teria ?
Eu teria que distribuir os pojos (DTO’s) do mesmo jeito.
Então é melhor transportar pojos.
pcalcado
A vanategm é que você nãp criaria uma classe DTO por objeto, mas a pergunta seria:
Mas porque usar um DTO neste caso em primeiro lugar?
Parabénspeloexcelentefórumepeladiscussãoemaltonível.Gostariadecolocaralgumas"gotas de pimenta"naconversa.DesenvolvemosaquinaempresaalgunssistemasusandoCMP2.0eposteriormentecomeçamosautilizaroHibernatecomoframeworkdepersistência.NosprimeirossistemasfizemosusointensivodeDTOsenossistemasHibernatepassamosautilizarosprópriosDomainBeans.Sópracontextualizar,asaplicaçõessãodivididasemcamadas,ondeoscanaisdeinterfacecomousuáriossãodesenvolvidaseimplantadasemaplicaçõesindependentesdasaplicaçõesdenegócio.Exemplo,aplicaçõesclientesWEBeSWING,comasaplicaçõesservidorasdistribuídasatravésdousodeEJBs.AlgunspontossobreousodosDomainBeanscomomoedadetrocadosmétodoscomasaplicaçõesclientes:1.Asaplicaçõessetornaramdependentesdasoluçãodepersistência.AbibliotecadoHibernatepassouasernecessárianaimplantaçãodasaplicaçõesclientes.Ouseja,seeuusoumTomCatparaimplementarminhasaplicaçõesWEBprecisoanexarojardoHibernateaumcontainerqueésomenteWEB.2.OsDomainBeanHibernate(poiselespassamaserobjetosHibernate)quandoenviadosaoclientesãopassíveisdelançaremexceçõesHibernate.Porexemplo,umobjetoAquepossuaumacoleçãodeobjetosB(tipoFuncionáriocomDependentes)ecujaaassociaçãoestámarcadacomLAZY.Nestecaso,seoprogramadordaaplicaçãoclientetentaracessaracoleçãodeDependentesrecebeumaexceçãoHibernateavisandoquenãoépossível"carregar"osobjetospoisestãoforado"contexto"doHibernate.Essesproblemassempremeremetemaquestãodoisolamentoentreascamadas.Mesmonãotrabalhandocomsistemasdistribuídos(SOAP,RMI,CORBA)aseparaçãológicaentreascamadasdoseusistemadevemcontinuaraexistirenãomepareceumaboapráticaenviarobjetosHibernateouEJB3paraumapáginaJSP.Comotambémocontrário,emuitomaisfácildeserpercebidocomoumapráticaruim,enviarparaascamadasdenégociodaaplicação,objetosStruts(comoosobjetosqueestendemoActionForm)ouobjetosquelidamcomoprotocoloHTTPcomoosHttpServletRequest.
Me parece bastante claro os objetivos de uma aplicação cliente: coletar e exibir dados. Nada mais. O fato de enviar um Bean “parrudo”, cheio de “regras de negócio” acredito que apenas dificulte o trabalho de quem implementa a aplicação cliente. Na grande maioria das vezes você precisa
contextualizar as suas regras de negócio ao escopo de uma transação, fora dela você está sujeito à inconsistências. A lógica de cada caso de uso faz parte da solução do sistema e deve ser descrita na aplicação servidora. Muitas das vezes apenas com os dados “inputados” pelo cliente o estado do objeto ainda se encontra “incompleto”, e que só vai ser “terminado” durante o decorrer da transação na aplicação servidora. Não adianta portanto que os “sets” ou os “validates” sejam executados pela aplicação cliente. É uma função dos componentes de sistema e dos componentes de domínio (vide UML Components - Cheesman).
Quanto a grande dificuldade de criar e manter DTOs, não vejo dessa forma. Exite uma classe (como a maioria das fornecidas pela Apache) que é a BeanUtils, que tem um método muito útil chamado copyProperties(). Com ele é possível facilmente popular os Domain Beans a partir dos Forms e/ou HashMaps e vice-versa. Quanto a gerar e regerar os Assemblers e os próprios DTOS, a maioria das IDEs já faz isso pra você.
Outra coisa, Beans simples normalmente são usados para telas de cadastro. Em grande parte dos casos de uso os objetos que chegam a aplicação cliente são mais complexos. Vide telas de consulta onde normalmente lidamos com “resultsets”, ou grafos de objetos.
Bom, acho que to escrevendo demais … STOP.
Abração.
pcalcado
Oi, Renato,
Isso indica que você não está utilizando separação de Camadas. A Camada de Persistência é a única que deve (pode, na verdade) depender do Hibernate, se seu Tomat não é responsável pela persistência provavelmente você tem um problema de arquitetura.
Novamente vejo um problema de arqutietura aqui. Seus objetos persistidos pelo Hibernate deveriam ser POJOs, eles não podem depender do Hibernate. Essa dependência é um erro de projeto.
Este é um problema de Lazy-Loading, você tem opções para gerenciar este problema na Camada de Persistência ou simplesmente não utilizar este recurso.
Como falei antes este é o problema desta arqutietura: não existe separação de Camadas. Você está deixando lógica de persistência escorrer para a Camada de Negócios e isso não é culpa do framework
Exato e não há porque você fazer isso com Hibernate.
Para isso existem DTOs, que sao um conceito diferente de TO(antigo VO) ou até de objetos burros.
Não entendi o que isso tem a ver com TO/VO.
Hmm… Cheesman? Deixa eu adivinhar: CCE da PUC-Rio?
Uma biblioteca extra só para criar objetos burros? Acho que não condiz muito com OOP.
De qualquer forma o problema não é copiar dados apenas, é manter hierarquias paralelas artificiais de objetos.
Existem dezenas de maneira de lidar com isso num domínio rico, não vejo qual o problema.
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.
Pra que? :?
Lembre-se da primeira grande regra de sistemas distribuidos: nao construa sistemas distribuidos
pcalcado
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.
F_io_Henrique
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.
F_io_Henrique
“Mochileiro das Galáxias” KKK
fantomas
@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
M
mcsouza
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.
M
mcsouza
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.
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.
Qual framework em específico assume que você utilizará um DTO?
M
mcsouza
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…
M
mcsouza
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!
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…
M
mcsouza
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:
/***********NaServlet****************AlunoDTOaluno=newAlunoDTO()// persiste estado no DTO a partir dos parametros do requestaluno.setEstado(***apartirdosparameters****);GerenciadorAluno.incluir(aluno);/**************************************classGerenciadorAluno{publicvoidincluir(AlunoDTOaluno){// 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,
M
mcsouza
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+,
M
mcsouza
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??
M
mcsouza
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.