| Autor |
Mensagem |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 29/08/2008 19:04:19
|
victorwss
JWizard
![[Avatar]](/images/avatar/4ab232445f9b21b65dfdf6ea5f27f704.png)
Membro desde: 18/12/2007 14:46:00
Mensagens: 2409
Localização: São Paulo - SP
Offline
|
Bem, pessoal. Estive analisando alguns sistemas com arquitetura "bolo de ovo" (*), e cheguei a algumas conclusões sobre o porque que essa coisa horrorosa é tão comum.
Primeiro erro:
VOs (no sentido anêmico) são apenas um monte de getters e setters burros que apenas tornam os atributos públicos com um falso encapsulamento. Estes atributos se limitam a apenas refletir o BD.
Normalmente o BD é criado primeiro (mesmo porque sem ele, o projeto quase não sai do lugar). Daí para projetar o sistema, sem ter idéia do que vai sair direito ou das regras de negócio, os programadores começam a estruturar o projeto simplesmente espelhando o BD.
Segundo erro:
Me tomando como exemplo, estou dando manutenção em um projeto que usa um framework de persistência que é horrível. Basicamente ele faz CRUD em apenas uma única tabela por vez (ou seja, nunca gera SQLs que contenham joins). Isso força o desenvolvedor a modelar as classes refletindo o BD (reforçando o erro 1). Esse framework seta os atributos diretamente, ou seja, se você tivesse algo assim: e o framework fosse setar o diametro da sua classe, vai ocorrer um belo NoSuchFieldException, uma vez que ele não acha o atributo raio. Isso força você a espelhar a estrutura do BD.
Terceiro erro:
Ok, joguemos no lixo os frameworks que trabalham com atributos e troquemos por frameworks que usam getters e setters. Essa abordagem força você a colocar getters e setters em tudo, o que provavelmente torna a maior parte dos campos como se fossem públicos e se não fizer isso, o framework explodirá com um belo NoSuchMethodException. Dificilmente poderá ser feita alguma validação no setter, pois se alguma exceção for lançada, o framework provavelmente não saberá tratá-la. O máximo que você pode fazer é falhar silenciosamente ou setar algum outro valor diferente daquele do parâmetro do setter.
Quarto erro:
Os frameworks quase sempre criam os seus objetos de uma única forma: Através do construtor padrão (e normalmente público). Esse construtor, por obviamente não receber parâmetros, é obrigado a setar valores padrão nos atributos ou então deixá-los todos nulos. Em seguida o framework invoca os setters em uma ordem não-conhecida para popular o objeto, o que torna difícil controlar a consistência dele. Pior ainda no caso de acesso direto aos atributos: não há forma de evitar que o objeto entre em estado inválido. Também não é possível lançar exceções de dentro do construtor e nem fazer qualquer tipo de delegação. O framework também nunca avisará que o objeto está pronto e que nenhum outro atributo ou setar será usado, o que impossibilita fazer a verificação de consistência após o framework fazer o trabalho.
Quinto erro:
Como toda a estrutura da aplicação está nas VOs e estas tem que ser burras porque o framework de persistência é burro, a lógica da aplicação acaba tendo que ir para outro lugar, aí é que surge a BO. Mas, o estado da aplicação está todos nos VOs porque o framework os criou assim. Acaba parecendo ser inútil (**) replicar esse estado nos BOs, o que de fato mantém o estado dos objetos separado das operações que estes realizam.
Sexto erro:
Nas camadas acima da camada de negócio (camadas de apresentação, normalmente). Frequentemente é necessário acessar o estado dos objetos. Como as BOs são stateless e a quantidade de acesso a propriedades é grande, as VOs acabam sendo passadas a elas diretamente. A situação fica ainda pior quando a camada de apresentação e de negócio estão em JVMs distintas, pois nesse caso o padrão TO é recomendado. O TOs normalmente é (e deve) ser modelado como um objeto com getters burros (o que implica atributos praticamente refletindo os getters). Mas por questão de reusabilidade, uma vez que o VO nada mais é do que o TO com os setters a mais, o VO acaba assumindo o lugar do TO.
Pronto, a caminhada rumo a arquitetura "bolo de ovo" está completa!
(*) Inventei esse nome "bolo de ovo" porque vem de "BOLOVO" que já era usado e é constituído por BOs e VOs. Além disso, os ovos devem ser quebrados (assim como os objetos são quebrados devido ao falso encapsulamento) e um monte de ovos juntos é uma bela meleca! Mas no final ainda é um sistema em camadas (como em um bolo).
(**) Na verdade esse problema pode ser a solução.
Para resolver o problema e fugir da arquitetura bolo de ovo, é necessário atacar a sua causa. Qual é a principal causa? frameworks de persistência ruins, que forçam a aplicação a ser modelada de uma forma relacional, e não OO. Ou seja, a primeira coisa a fazer é escolher um framework decente (ou então usar a JDBC na unha). Isso elimina de cara o segundo, o terceiro e o quarto erro, o que impede que o quinto e o sexto ocorram.
Ok, mas nem sempre é possível se livrar do framework, então o que fazer? Isolá-lo. O framework vai precisar de um objeto burro para trabalhar, pois bem, lhe dê esse objeto e use-o apenas para se comunicar com o framework e jogue-o fora tão logo tenha cumprido sua missão, nem que seja preciso copiar os atributos para o seu objeto de negócio.
Pois bem pessoal, essa é a minha visão. Gostaria de comentários acerca disso.
This message was edited 3 times. Last update was at 29/08/2008 19:09:37
|
Victor Williams Stafusa da Silva
Bacharel em Ciência da Computação - UFMT // Especialista em Desenvolvimento Java - CEFET/MT // Doutorando em Ciência da Computação - IME-USP
SCJP 6.0 - 19/12/2007 - PASS - 88% // SCWCD 5 - 17/05/2008 - PASS - 79% // SCJA - 09/09/2008 - PASS - 96% // SCSNI - 30/06/2009 - PASS - 68% // SCBCD 5 - 31/05/2010 - PASS - 95%
Próximos: SCJD (encalhado com o projeto), SCEA parte I (estudando). Algum dia desses: SCMAD, OCA, SCEA e SCDJWS.
Computação: uma ciência holística e esotérica!
E então veio Deus a terra e disse aos homens: Não dividireis por zero.
XML is a giant step in no direction at all. (Erik Naggum)
Arquitetura de sistemas: Eu prefiro ser essa metamorfose ambulante do que ter aquela velha opinião formada sobre tudo.
Diga não as drogas: Não use java.util.Vector.
Cuidado: Este usuário pode ter temperamento agressivo.
Always code as if the person who will maintain your code is a maniac serial killer that knows where you live.
I am the maniac serial killer that knows where you live who will maintain your code.
É impossível falar de CMMI (Capability Maturity Model Integration) sem saber o que é CIMM (Capability Im-Maturity Model).
Se você escreve "concerteza", "concerteza" você andou matando aulas de português. |
|
|
 |
|
|
![[Post New]](/templates/default/images/icon_minipost_new.gif) 29/08/2008 19:34:41
|
Leonardo3001
GUJ Ranger
Membro desde: 04/07/2007 18:28:58
Mensagens: 975
Offline
|
Concordo.
Falta aquela visão de que se constrói o sistema a partir da visão do usuário, e vai "preenchendo o miolo" a medida que se constrói. E costuma-se fazer software exatamente a partir da estrutura da base, levando todo o projeto a ter dependências do BD. Quando se descobre um "campo faltando", um relacionamento que "não é bem assim", todo o sistema precisa ser modificado.
Pra remover a dependência do BD basta um pattern: strategy. Um objeto que precisa acessar a origem dos dados, conhecerá apenas uma interface de acesso (repository?), cuja implementação é irrelevante inicialmente. Pode ser XML, objetos em memória, banco de acesso local... qualquer coisa que dê pra testar fácil. Com o tempo, a medida que se conhece melhor o negócio, faz-se as tabelas do BD real e a implementação da interface de acesso.
Apesar de você não citar nenhum framework, vale citar que JPA/Hibernate é ótimo. Normalmente, faço o mapeamento a partir dos atributos privados dos objetos,e aí não se precisa de getter e setter, podendo lançar interfaces públicas da maneira que me convier.
|
Leonardo Veríssimo
-------------------------------------------------
Objectzilla |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 29/08/2008 19:52:11
|
Marcio Duran
GUJ Master
![[Avatar]](/images/avatar/df0e19d29493ef2136fc3e2fc029c054.jpg)
Membro desde: 23/01/2008 11:14:35
Mensagens: 1905
Offline
|
Talvez essa seja a melhor resposta !!!
JBoss Seam Framework
http://www.divshare.com/download/3772432-d51
O Seam está na versão 2.0, e foi desenvolvido inicialmente por Gavin King, criador do
hibernate e líder da especificação Java Persistence API.
Umas das facilidades do Seam é a fácil integração com outros frameworks JSF como
IceFaces e RichFaces, que utilizam ajax encapsulado e que cuidam da parte de
apresentação, a integração com esses frameworks é bem transparente.
O Seam também se integra facilmente com uma série de outros framework como:
JPA - Java Persistence API e Hibernate
EJB 3 - Enterprise Java Bean 3
JfreeChart
Google Web Toolkit
; )
This message was edited 2 times. Last update was at 29/08/2008 20:06:38
|
Consultor Open Source
Comunidade JavaLivros
Twitter Comunidade JavaLivros
Novo Blog do MiddleHeaven |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 29/08/2008 20:35:50
|
cordjr
Thread.start()
![[Avatar]](/images/avatar/8576d5a526fe75112fee46cc3a77e927.jpg)
Membro desde: 10/11/2006 00:56:48
Mensagens: 25
Offline
|
Marcio Duran, vc poderia explicar melhor a sua resposta
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 29/08/2008 20:37:03
|
tnaires
GUJ Master
![[Avatar]](/images/avatar/5f6371c9126149517d9ba475def53139.png)
Membro desde: 22/12/2003 08:05:58
Mensagens: 1678
Localização: Porto Alegre/RS - Natal/RN
Offline
|
Por favor, este tópico começou interessante, não comecem a criticar o que o Márcio Duran falou senão vai avacalhar...
|
Tarso Nunes Aires
Blog - http://cabritin.wordpress.com/
Delicious - http://delicious.com/tnaires
Twitter - @tnaires
 |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 29/08/2008 21:02:28
|
Marcio Duran
GUJ Master
![[Avatar]](/images/avatar/df0e19d29493ef2136fc3e2fc029c054.jpg)
Membro desde: 23/01/2008 11:14:35
Mensagens: 1905
Offline
|
cordjr wrote:Marcio Duran, vc poderia explicar melhor a sua resposta
Basta você ler, o que escreveram acima, depois se você for uma pessoa que gosta de ir em palestra e procurar soluções novas, vai perceber mecanismo ao FrameWork mais especializado tem já existe por ai, que é o Jboss seam já foi estudado para tal contexto.
É como se alguem aqui, tivesse uma melhor solução ou que gostaria de promover uma visão de melhor responsabilidade aos objetos ou um pensamento sulrreal sobre patterns que já foram estudados....
O que vocês dão previsão(ou querem resolver programaticamente) já foi estudado, e tem muita coisa nova ai que poucas pessoas, conhecem
Recomendo o link abaixo
http://jbossbrasil.ning.com/
This message was edited 1 time. Last update was at 29/08/2008 21:03:14
|
Consultor Open Source
Comunidade JavaLivros
Twitter Comunidade JavaLivros
Novo Blog do MiddleHeaven |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 29/08/2008 21:49:06
|
saoj
JWizard
![[Avatar]](/images/avatar/2e7ceec8361275c4e31fee5fe422740b.png)
Membro desde: 09/03/2004 23:34:46
Mensagens: 2657
Localização: Chicago, EUA
Offline
|
O post do victorwss foi bastante interessante mas essa choradeira em torno de beans anêmicos eu nunca entendi direito.
Por exemplo, tenho uma tabela JOBS que tem um monte de campos. Isso porque a minha entidade JOB realmente tem um monte de informação como deadline, partes, canal, formato de tela, idioma, titulo, etc.
Então o meu objeto Job vai ter que ter todas essas informações. Com certeza vai ter que ter getter para todas elas e com certeza vai ter que ter setters para todas elas. De getter não dá para escapar e dos setters daria se vc tivesse um construtor gigantesco recebendo tudo. Então qual é o problema de ter uma kacetada de setters and getters? É claro o objeto provavelmente não vai ter só isso e alguma lógica do negócio pode e deve ser codificado dentro dele, mas daí e taxá-lo de anêmico eu acho um exagero.
A maioria dos projetos envolvem principalmente CRUDs, ou seja, criar e editar beans, e por essa operação ser algo bem crú o bean acaba ficando inicialmente anêmico mesmo. Logo não vejo porque o desespero nesses casos...
This message was edited 2 times. Last update was at 29/08/2008 21:51:25
|
Sergio A Oliveira Jr. - saoj
ExperiMENTA:
Mentawai = http://www.mentaframework.org - Full-stack Java Web Framework com Configuracão Programática
MentaQueue = http://mentaqueue.soliveirajr.com - Queue de alta-performance.
MentaLog = http://mentalog.soliveirajr.com - Non-intrusive, fast, garbage-less, colored and straightforward logging
MentaBean = http://mentabean.soliveirajr.com - Tiny ORM with SQL Builder
MentaRegex = http://mentaregex.soliveirajr.com - Perl-style regex for Java.
MentaContainer = http://mentacontainer.soliveirajr.com - Straightforward IoC, DI e Auto-Wiring
Space4J = http://www.space4j.org - Banco-de-dados de Objetos em Memória
Options-Lib = https://github.com/saoj/options-lib - Ruby classes para ter acesso as opcoes do Yahoo Finance
Selleto = http://www.selleto.com.br
Flipinion = http://www.flipinion.com
Kawai = http://www.kawaiwiki.org
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 30/08/2008 10:36:05
|
Leonardo3001
GUJ Ranger
Membro desde: 04/07/2007 18:28:58
Mensagens: 975
Offline
|
saoj wrote:O post do victorwss foi bastante interessante mas essa choradeira em torno de beans anêmicos eu nunca entendi direito.
Por exemplo, tenho uma tabela JOBS que tem um monte de campos. Isso porque a minha entidade JOB realmente tem um monte de informação como deadline, partes, canal, formato de tela, idioma, titulo, etc.
Então o meu objeto Job vai ter que ter todas essas informações. Com certeza vai ter que ter getter para todas elas e com certeza vai ter que ter setters para todas elas. De getter não dá para escapar e dos setters daria se vc tivesse um construtor gigantesco recebendo tudo. Então qual é o problema de ter uma kacetada de setters and getters? É claro o objeto provavelmente não vai ter só isso e alguma lógica do negócio pode e deve ser codificado dentro dele, mas daí e taxá-lo de anêmico eu acho um exagero.
A maioria dos projetos envolvem principalmente CRUDs, ou seja, criar e editar beans, e por essa operação ser algo bem crú o bean acaba ficando inicialmente anêmico mesmo. Logo não vejo porque o desespero nesses casos...
Realmente, se for somente CRUD não há porque se preocupar nos objetos serem anêmicos. O problema reside nessa "virada de chave", quando se descobre que não é somente buscar ou editar, existe algum "processamento". E aí, o que se faz? O arquiteto lavou as mãos ao ter dito, sem pensar, que é só um sisteminha CRUD. Metade dos desenvolvedores tem uma religião de que enfiar regra de negócio nos objetos é pecado (aliás, até polimorfismo pra eles é pecado). Some-se a isso uma cultura de não fazer testes unitários, que se traduz a uma cultura de medo de mudanças. No final, será feita a reunião onde vai "se definir a camada de negócio" e que não terminará até que tudo fique redondo.
Esse filme acima eu já vi várias vezes, e sei que não acaba bem.
|
Leonardo Veríssimo
-------------------------------------------------
Objectzilla |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 30/08/2008 10:45:06
|
saoj
JWizard
![[Avatar]](/images/avatar/2e7ceec8361275c4e31fee5fe422740b.png)
Membro desde: 09/03/2004 23:34:46
Mensagens: 2657
Localização: Chicago, EUA
Offline
|
Metade dos desenvolvedores tem uma religião de que enfiar regra de negócio nos objetos é pecado
Nunca ouvi falar sobre isso. Isso seria total falta de experiencia com OO. Se o cara não sabe OO então anemia será a menor das complicações.
Vc diz que o cara vai fazer isso:
Ao invés disso:
Nesse caso o problema é simplesmente uma não-compreensao de OO. Não tem nada haver com VO, BO, anemia, etc.
O que pode estar acontecendo tb é que as pessoas estão confundindo UserService, UserLogic ou UserFacade com camada de negócios. As regras de negócio, sempre que possível, devem estar dentro das entidades. O que isso tem haver com VO, BO, TO? Isso é o fundamento primeiro de OO e se o cara não sabe OO direito então ferrou.
Só tem um jeito de aprender OO e não é lendo um livro. É programando, programando, programando... Modelando, modelando, modelando sistemas OO...
This message was edited 3 times. Last update was at 30/08/2008 10:56:46
|
Sergio A Oliveira Jr. - saoj
ExperiMENTA:
Mentawai = http://www.mentaframework.org - Full-stack Java Web Framework com Configuracão Programática
MentaQueue = http://mentaqueue.soliveirajr.com - Queue de alta-performance.
MentaLog = http://mentalog.soliveirajr.com - Non-intrusive, fast, garbage-less, colored and straightforward logging
MentaBean = http://mentabean.soliveirajr.com - Tiny ORM with SQL Builder
MentaRegex = http://mentaregex.soliveirajr.com - Perl-style regex for Java.
MentaContainer = http://mentacontainer.soliveirajr.com - Straightforward IoC, DI e Auto-Wiring
Space4J = http://www.space4j.org - Banco-de-dados de Objetos em Memória
Options-Lib = https://github.com/saoj/options-lib - Ruby classes para ter acesso as opcoes do Yahoo Finance
Selleto = http://www.selleto.com.br
Flipinion = http://www.flipinion.com
Kawai = http://www.kawaiwiki.org
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 30/08/2008 11:22:58
|
cmoscoso
Virtual Machine Man
Membro desde: 23/10/2007 10:08:29
Mensagens: 687
Offline
|
Apenas pra deixar claro que o termo VO (Value Object) utilizado por vcs corresponde ao DTO ou TO enada tem a ver com Value Object do DDD.
Metade dos desenvolvedores tem uma religião de que enfiar regra de negócio nos objetos é pecado
O problema maior ao meu ver é separar os dados das regras de negocio. O primeiro erro foi direto ao ponto, desenvolvimento orientado a banco de dados.
saoj wrote:
Nesse caso o problema é simplesmente uma não-compreensao de OO. Não tem nada haver com VO, BO, anemia, etc.
O que pode estar acontecendo tb é que as pessoas estão confundindo UserService, UserLogic ou UserFacade com camada de negócios. As regras de negócio, sempre que possível, devem estar dentro das entidades. O que isso tem haver com VO, BO, TO? Isso é o fundamento primeiro de OO e se o cara não sabe OO direito então ferrou.
Só tem um jeito de aprender OO e não é lendo um livro. É programando, programando, programando... Modelando, modelando, modelando sistemas OO...
É mesmo dificil identificar o que é regra de aplicacao ou negocio mas eu diria que as regras de negocio nao estao apenas nas entidades, mas tb em outros objetos que pertencem a camada de domino.
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 30/08/2008 11:37:33
|
pcalcado
Moderador
![[Avatar]](/images/avatar/110eec23201d80e40d0c4a48954e2ff5.jpg)
Membro desde: 08/03/2004 17:19:35
Mensagens: 5174
Localização: Sydney - Australia
Offline
|
Paulo Silveira e eu criamos o nome BOLOVO enquanto fazíamos nossa apresentação no JustJava 2007 exatamente para indicar uma arquitetura baseada nestes.
Em Java, existem três motivos básicos para o uso de objetos anêmicos ser popular:
1 - Falta de entendimento sobre programação orientada a objetos -as pessoas continuam usando estruturas e procedimentos
2 - Uso extensivo deste tipo de arquitetura por frameworks e bibliotecas no passado- inclusive com a Sun deturpando o nome de "JavaBeans" de um modelo de componentes visuais para qualquer-coisa-com-get-e-set.
3 - O padrão Transfer Object (antigo Value Object) do Core J2EE Patters e utilizado em quase todas as Blueprints - ele legitimou o uso.
Leonardo3001 wrote:
Realmente, se for somente CRUD não há porque se preocupar nos objetos serem anêmicos. O problema reside nessa "virada de chave", quando se descobre que não é somente buscar ou editar, existe algum "processamento". E aí, o que se faz?
Eu não consigo pensar em nenhum sistema que valha a pena ser desenvolvido por um time especializado que não tenha regras de negócio. Se o sistema não possui "processamento" existem diversas aplicações estilo MS Access que podem criar o "sistema" em poucas horas por uma fração do preço.
Partindo do ponto que temos regras de negócios e que decidimos utilizar OO (poderíamos ter decidido utilizar outro paradigma) mesmo CRUD deveriam ter objetos de verdade. Note que uma coisa é possuir objetos, outra é quais são estes objetos. Se você não modelar seu negócio próximo ao domínio -criando classes artificiais, não usando camadas ou o que for- mas utilizar objetos com atributo e comportamento vai ainda assim ter um sistema OO.
O grande problema dos getters e setters é que boa parte deles não é necessário. Você só deve expôr o que precisa ser exposto e dado que um objeto é geralmente o dono de sua lógica o que precisa ser exposto (i.e. get/set) é muito pouco num sistema OO. Uma das melhores técncias de design para evitar criar modelos anêmicos é Test-Driven Development.
|
Phillip Calçado "Shoes"
http://fragmental.tw/
http://blog.fragmental.com.br/
"It is unfortunate that much of what is called 'object-oriented programming today is simply old style programming with fancier constructs." - Alan Kay |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 30/08/2008 13:24:50
|
g4j
GUJ Ranger
![[Avatar]](/images/avatar/bea3c20edb84a0dd83a99a9a7274bc67.jpg)
Membro desde: 02/05/2007 14:32:03
Mensagens: 816
Localização: Curitiba
Offline
|
Ao meu ver os tais "VOs anêmicos" refletem basicamente o modelo de dados, qual o problema de ter classes separadas, os tais BO, pra trabalhar com o VO puro? Isso é tão errado assim? Lógico que existem coisas que podemos tratar no próprio VO e elas devem ser feitas nele.
Não acho horroroso a forma de ter tais "classes anemicas", acho que a tendência criada por frameworks de persistência talvez nos tenha levado a criar tais modelos.
Mesmo que o banco de dados seja criado como base no nosso modelo de classes, provavelmente o banco vai refletir os atributos e teremos os tais getters / setters. Abandonar os frameworks por conta disso? No way, tentar de outra forma (jdbc na unha)?
As vezes temos tempo correndo x prazo e acho que talvez isso conte mais do que pensar na anemia dos VOs ou troca do modelo / framework de persistência.
|
Gerson Luiz Chagas
SCJP 5.0
SCWCD 5.0
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 30/08/2008 14:53:37
|
Marcio Duran
GUJ Master
![[Avatar]](/images/avatar/df0e19d29493ef2136fc3e2fc029c054.jpg)
Membro desde: 23/01/2008 11:14:35
Mensagens: 1905
Offline
|
Scala é a solução !!!
"Modularidade é praticamente sinônimo de baixo acoplamento: dividir o programa em pedaços pequenos, independentes, fáceis de combinar e reusar em vários contextos."
; )
This message was edited 1 time. Last update was at 30/08/2008 14:54:11
|
Consultor Open Source
Comunidade JavaLivros
Twitter Comunidade JavaLivros
Novo Blog do MiddleHeaven |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 30/08/2008 21:56:39
|
sergiotaborda
GUJ Expert
![[Avatar]](/images/avatar/b4a0e0fbaa9f16d8947c49f4e610b549.png)
Membro desde: 22/03/2005 20:57:48
Mensagens: 3433
Offline
|
victorwss wrote:
Primeiro erro:
VOs (no sentido anêmico) são apenas um monte de getters e setters burros que apenas tornam os atributos públicos com um falso encapsulamento. Estes atributos se limitam a apenas refletir o BD.
Certo. O que vc tlv não tenha percebido é o papel dos get/set. Eles não servem para encapsular ( embora encapsulem), servem para criar - em java - o conceito de propriedade.
Os VO no sentido que está usando a palavra são objetos apenas com propriedades.
Se vc incluir algum método que não é uma propriedade em qualquer objeto java ele não deve ter o nome prefixado com get/set. O seu exemplo do diametro. Diametro não é uma propriedade, é calculado.
Logo não faz sentido ter um getDiametro e um setDiamentro. O que faz sentido é ter um set/getRaio - que é a propriedade e ter um diametro() que é um método que calcula o diametro. Esse método não é uma propriedade, ele contêm inteligência e portanto torno o seu objeto em algo não-anémico.
É uma questão de seguir o padrão Bean (Não confundir com JavaBean) que dita que as propriedades têm que ser marcadas com get/set.
O problema é que muito pouco entendem que em java se declaram propriedades dessa forma e isso causa um monte de problemas.
É verdade que os VO normalmente espelham uma tabela qualquer, mas não precisa ser assim. Isso é falha do modelador, não do padrão , nem da tecnologia. Se a tabela tem 100 campos - como exemplo que o saoj deu - e o cara modela isso como um objeto com 100 campos o que podemos concluir é que ele não sabe - ou não quer - modelar OO. Parta os 100 campos em pedaços que sejam relevantes juntos e crie um objeto com esses objetos como propriedades. Não precisa usar esse objeto se não quiser, pode usar apenas os pedaços por si mesmos (este é o conceito moderno de VO). Continuamos apenas tendo propriedades, mas em nada estamos amarrados ao banco.
Normalmente o BD é criado primeiro (mesmo porque sem ele, o projeto quase não sai do lugar).
Infelizmente a maioria ainda pensa assim. Em OO o que vem primeiro é o modelo de classes que são o coração do programa - o dominio. O testo é plumbing. Modelar o sistema em prol do banco é simplesmente coisa do século passado ( literalmente) e não é OO.
Segundo erro:
Me tomando como exemplo, estou dando manutenção em um projeto que usa um framework de persistência que é horrível. Basicamente ele faz CRUD em apenas uma única tabela por vez (ou seja, nunca gera SQLs que contenham joins).
(...) e o framework fosse setar o diametro da sua classe, vai ocorrer um belo NoSuchFieldException, uma vez que ele não acha o atributo raio. Isso força você a espelhar a estrutura do BD.
Não.
Não conheço o framework de que fala, mas se bem entendi ele utiliza os métodos get/set para ler/escrever os campos. Isso é mais que correto. O framework não pode ler diretamente via reflection direta do atributo provado. Isso é gambiarra. É privado, é suposto ninguem saber que ele existe.
Muitos frameworks leem direto dos campos, mas isso é falho. Experimente usá-los em ambiente seguro e terá uma grande surpresa. O erro é do cara que modelou o diâmetro como uma propriedade quando claramente não é. Até UML tem um símbolo especial para campos desse tipo ("calculados"). Não é nada do outro mundo. E a convenção é muito simples. Não ha modificador e o acesso não começa com get.
Terceiro erro:
Ok, joguemos no lixo os frameworks que trabalham com atributos e troquemos por frameworks que usam getters e setters. Essa abordagem força você a colocar getters e setters em tudo, o que provavelmente torna a maior parte dos campos como se fossem públicos e se não fizer isso, o framework explodirá com um belo NoSuchMethodException.
O que é corretíssimo.
Não ha nenhum problema em colocar get/set porque isso lhe permite definir outras coisas que não são propriedades. Os frameworks de persistencia só se interessam pelas propriedades então se o objeto está bem modelado, não vai haver problema nenhum.
Dificilmente poderá ser feita alguma validação no setter, pois se alguma exceção for lançada, o framework provavelmente não saberá tratá-la. O máximo que você pode fazer é falhar silenciosamente ou setar algum outro valor diferente daquele do parâmetro do setter.
Validação no setter... ora ai está outro mito... o setter faz no máximo uma consistência. Validação e consistência são duas coisas diferentes. Mas veja bem, o framework de persistência (FP)só trabalha com dados que já foram incluídos no objeto. Se quando eles foram incluídos tudo estava bem, isso irá ser sempre assim.O FP não altera os dados, ele só copia. Se estava certo continuará certo.
Mas se as regras do objeto mudaram, ou alguem mexer no banco À mão é bom que haja erros de consistência e até de validação.
Mas diga-me : quando vc lê dados do banco - à mão ou com frameworks - vc passa-os pelo mesmo validador de quando eles vêm da UI ? Passa-os por algum validador ? Se não, é porque vc confia bastante no banco. Se vc confia, porque o FP não pode confiar ?
Insira as consistências à vontade porque sempre lhe serão uteis. Se der pau na hora de carregar do banco é porque o banco mudou ou as regras mudaram, em qualquer caso é bom ser avisado.
Quarto erro:
Os frameworks quase sempre criam os seus objetos de uma única forma: Através do construtor padrão (e normalmente público).
Se assim não fosse eles estariam a) violando o encapsulamento ou b) inferindo regras de construção do dominio. FP não podem fazer nenhuma dessas duas coisas. Sim, é claro que poderiam usar um factory ou um método estático como mais um arsenal mas... na real, qual é o programador que quer fazer isso ? A maioria nem sabe declarar o construtor direito ...
Esse construtor, por obviamente não receber parâmetros, é obrigado a setar valores padrão nos atributos ou então deixá-los todos nulos. Em seguida o framework invoca os setters em uma ordem não-conhecida para popular o objeto, o que torna difícil controlar a consistência dele.
Vê? ai está o erro. A consistência é algo unitário e inerente ao modificador. O modificador sabe, sozinho,
consistir os dados. Se ele não sabe, isso não é consistência, é validação ( que é feita por um outro objeto: o validador). Por outro lado, pensar que ha uma ordem para invocar os set (escrever as propriedades) é absurdo, porque o próprio conceito de propriedade significa que elas são independentes. Se não são, algo está errado na modelagem do objeto, não no FP.
Pior ainda no caso de acesso direto aos atributos: não há forma de evitar que o objeto entre em estado inválido. Também não é possível lançar exceções de dentro do construtor e nem fazer qualquer tipo de delegação. O framework também nunca avisará que o objeto está pronto e que nenhum outro atributo ou setar será usado, o que impossibilita fazer a verificação de consistência após o framework fazer o trabalho.
... gritaria estérica isso ai... o fp vai dar um new no objeto e escrever as propriedades. Isso é feito transacionalmente, se der algum problema em algum dos passos o objeto simplesmente não é criado.
O objeto pode até entrar em estado inconsistente ( pensemos que sim, para continuar o argumento) mas o FP nunca lhe retornará esse objeto. Ele vai dar exception antes.
Portanto, mesmo que ele entre em estado inconsistente, isso não será problema.
( Supondo que o FP está construido corretamente. Se não está é um problema do framework, não do padrão VO ou do padrão Bean)
Quinto erro:
Como toda a estrutura da aplicação está nas VOs e estas tem que ser burras porque o framework de persistência é burro, a lógica da aplicação acaba tendo que ir para outro lugar, aí é que surge a BO. Mas, o estado da aplicação está todos nos VOs porque o framework os criou assim. Acaba parecendo ser inútil (**) replicar esse estado nos BOs, o que de fato mantém o estado dos objetos separado das operações que estes realizam.
Vc assume que o problema é o FP quando na realidade é a modelagem do VO. Se for bem feita o FP não vai interferir. É tudo uma questão de convenção. A lógica não tem que ir para outro lugar - exemplo do diametro(). O ponto é o que fazer com lógica que está acima dos objetos de dados. lógicas que não dependem do estado dos objetos, mas das relações dos seus estados. Isso é colocado em outros objetos - sem estado - que fazem algo. Objetos sem estado são os melhores que ha porque poupam recursos.
Por outro lado, nem todas as lógicas cabem em VO não-anémicos ( Por isso o DDD fala em Services).
Sexto erro:
Nas camadas acima da camada de negócio (camadas de apresentação, normalmente). Frequentemente é necessário acessar o estado dos objetos. Como as BOs são stateless e a quantidade de acesso a propriedades é grande, as VOs acabam sendo passadas a elas diretamente.
Reuso é a razão para fazer isso. O problema é que algumas tecnologias exigem get/set para tudo e mais alguma coisa e não sabem trabalhar com o diametro() apenas. Isso leva o programador a criar um getDiametro. Mas isso está em desacordo com as regras dos Beans e portanto com as dos FP que seguem as regras dos Beans. É bom que todos os frameworks em todas as camadas cumpram as mesmas regras. É o fato disso não ser verdade que leva a absurdos como getDiametro().
A situação fica ainda pior quando a camada de apresentação e de negócio estão em JVMs distintas, pois nesse caso o padrão TO é recomendado. O TOs normalmente é (e deve) ser modelado como um objeto com getters burros (o que implica atributos praticamente refletindo os getters). Mas por questão de reusabilidade, uma vez que o VO nada mais é do que o TO com os setters a mais, o VO acaba assumindo o lugar do TO.
Essa ai nem existe. Se o seu VO é Serializable ( o que não é dificil) ele pode ser usando inter-JVM sem problemas. O problema ocorre quando vc expoe uma interface publica com esses objetos como num webservice, por exemplo. Ai vc precisa da conversão para isolar a camada de apresentação ( webservice) do sistema em si. Mas fora isso , não ha problema nenhum em usar VO Serializáveis no lugar de TO ...
Para resolver o problema e fugir da arquitetura bolo de ovo, é necessário atacar a sua causa. Qual é a principal causa? frameworks de persistência ruins, que forçam a aplicação a ser modelada de uma forma relacional, e não OO.
Não. 'Modeladores' ruins, que sabem a diferença entre getDiametro() e diametro(). 'Desenvolvedores' ruins que não escolhem os seus frameworks de forma compatível e não conhecem os padrões direito acabando por usar o que está na moda sem pensar nas conseqüências.
Ou seja, a primeira coisa a fazer é escolher um framework decente (ou então usar a JDBC na unha). Isso elimina de cara o segundo, o terceiro e o quarto erro, o que impede que o quinto e o sexto ocorram.
A primeira coisa a fazer é aprender a programar direito e entender os padrões. Com isso elimina toda essa treta de anti-padrão de dominio anémico. Veja que todo o problema que vc levantou é baseado num simples erro de modelagem por não entender a diferença entre modificador, acessor e métodos simples , junta com a má escolha de frameworks nas várias camadas. Não ha nenhum bicho papão de bolos de ovo, aliás todos os bolos são de ovo, não dá para fazer bolos sem eles (... até dá, mas na culinária, não na expressão "fazer bolo sem quebrar ovos"... )
Não são os frameworks que são burros. São os seus idealizadores e o seus utilizadores que são ineptos.
É claro que inépcia é uma coisa passageira, basta que as pessoas estudem mais. Algumas outras doenças mais graves e não são tão passageiras... ( como a preguiça , por exemplo...)
|
Criando sua própria API de Validação
Blog do MiddleHeaven |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 30/08/2008 23:24:53
|
pcalcado
Moderador
![[Avatar]](/images/avatar/110eec23201d80e40d0c4a48954e2ff5.jpg)
Membro desde: 08/03/2004 17:19:35
Mensagens: 5174
Localização: Sydney - Australia
Offline
|
g4j wrote:Ao meu ver os tais "VOs anêmicos" refletem basicamente o modelo de dados, qual o problema de ter classes separadas, os tais BO, pra trabalhar com o VO puro? Isso é tão errado assim? Lógico que existem coisas que podemos tratar no próprio VO e elas devem ser feitas nele.
Antes de mais nada, por que você teria TO (VOs são outra coisa)? Leia a descrição do pattern antes de responder.
O que você está usando é apenas uma estrutura de dados, não um objeto. Se você não se importa naquele determinado contexto em usar objetos pode ser uma coisa aceitável mas se você está programando OO não deve ter este tipo de estrutura de dados 'burra'. O fato de você refletir o modelo de dados é exatamente a raiz do problema já que o modelo de dados não é OO. Num sistema OO sem base legada é de se esperar que o banco de dados seja um reflexo do modelo de objetos e não o contrário.
g4j wrote:
Não acho horroroso a forma de ter tais "classes anemicas", acho que a tendência criada por frameworks de persistência talvez nos tenha levado a criar tais modelos.
Frameworks de anos atrás. Há muito tempo que os frameworks (MVC, persistência, o que for) não sequer implicam em -muito menos exigem- modelos anêmicos.
g4j wrote:
Mesmo que o banco de dados seja criado como base no nosso modelo de classes, provavelmente o banco vai refletir os atributos e teremos os tais getters / setters. Abandonar os frameworks por conta disso? No way, tentar de outra forma (jdbc na unha)?
Qual framework e exige isso? O Hibernate trabalha diretamente com atributos (sem necessidade de get/set) há muito tempo. Ainda que se tenha a necessidade uma coisa é criar um método para atender a um framework mal construído outra coisa é utilizar este método internamente no seu sistema (provavelmente criando um sistema mal construído).
g4j wrote:
As vezes temos tempo correndo x prazo e acho que talvez isso conte mais do que pensar na anemia dos VOs ou troca do modelo / framework de persistência.
É justificável que na primeira vez que alguém entenda que modelos anêmicos devem ser evitados ele esteja com prazos apertados e não consiga fazer a refatoração. O problema é que isso não acontece só na primeira vez.
|
Phillip Calçado "Shoes"
http://fragmental.tw/
http://blog.fragmental.com.br/
"It is unfortunate that much of what is called 'object-oriented programming today is simply old style programming with fancier constructs." - Alan Kay |
|
|
 |
|
|
|
|