GUJ Discussões   :   últimos tópicos   |   categorias   |   GUJ Respostas

O que leva as pessoas a criar VOs anêmicas?

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: [code]public int getDiametro {
return raio * 2;
}

public void setDiametro(int diametro) {
raio = diametro / 2;
}[/code] 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.

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.

Talvez essa seja a melhor resposta !!!

[size=18]JBoss Seam Framework[/size]

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:

:arrow: JPA - Java Persistence API e Hibernate
:arrow: EJB 3 - Enterprise Java Bean 3
:arrow: JfreeChart
:arrow: Google Web Toolkit

[size=25]; )[/size]

Marcio Duran, vc poderia explicar melhor a sua resposta :slight_smile:

Por favor, este tópico começou interessante, não comecem a criticar o que o Márcio Duran falou senão vai avacalhar…

[quote=cordjr]Marcio Duran, vc poderia explicar melhor a sua resposta :slight_smile:
[/quote]
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

:arrow: http://jbossbrasil.ning.com/

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…

[quote=saoj]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…
[/quote]

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.

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:

Account a = getAccount(...);

double funds = a.getFunds();

if (funds >= 1000) {
   a.setFunds(funds -1000);
}

return 1000;

Ao invés disso:

Account a = new Account(...);

if (a.hasFunds(1000)) {
    return a.withdraw(1000);
}

:?: :?: :?:

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…

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.

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.

É 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.

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.

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.

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.

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.”

[size=18]; )[/size]

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.

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.

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.

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.

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.

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 …

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.

… 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)

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).

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().

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 …

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.

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”… :lol: )

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…)

[quote=g4j]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.
[/quote]

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.

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.

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).

É 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.

Eu estava escrevendo, “quotando” tudo, mas desisti.

Pelo que eu entendi, a discussão é pelo simples fato de classes terem todos os comportamentos definido em outras classes, o que muitos chamam de BO, ficando assim somente com os getters/setters.

Mas algumas classes têm somente métodos CRUD. Esses métodos devem estar nas classes?

public class User {
   private int id
   private String name;
   //...
   public Object create(...) {
       //...
   }
   public Object replace(...) {
       //...
   }
   //...
}

Ou então aqui os DAOs entram? Ops, a classe User vai ficar “anêmica”.

Não, creio que você não tenha entendido o princípio.

Um objeto é responsável por seu comportamento. Um objeto não se armazena em si mesmo, você o armazena em algum lugar, daí já surge a necessidade de outro objeto com esta responsabilidade. O ponto é que comportamento (“métodos”) e estado (“atributos”) relativos a um objeto devem estar nele e não em 2 ou mais classes.

[quote=sergiotaborda][quote=victorwss]
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.
[/quote]

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.
[/quote]

Ok, vamos supor o seguinte: No banco de dados existe um campo raio. O que significa que o FP usará o atributo raio ou os respectivos getters e setters. Mas, em todo o sistema se trabalha com o diâmetro. Sim, isso é uma inconsistência, mas vamos supor que seja porque o banco de dados é legado ou pertence a terceiros, por exemplo. Pois bem, como o sistema trabalha com diâmetro mas persiste o raio, eu poderia colocar um par de getters e setters para o diâmetro, centralizando a regra de negócio (conversão de raio para diâmetro e vice-versa) no objeto. Mas, se eu não criasse esses getters e setters, o que aconteceria? Eu seria obrigado a pulverizar a regra de conversão em todo o sistema ou então criar algum outro objeto apenas para fazê-la, quando seria muito mais simples, mais fácil E MAIS OO se o próprio objeto soubesse fazê-la.

Sim, a falha nasce aí. Programação orientada ao BD. Foi por isso que eu chamei isso de "Primeiro erro". É aí que o problema nasce e passa a governar todo o sistema.

Sim, isso é parte do "Primeiro erro". E na maior parte dos casos isso se resolve se o BD refletir o sistema e não o contrário (como o pcalcado disse). O problema é quando o BD é legado ou pertence a terceiros, não se pode deixar que um "desejo profano" do BD interferfira na estrutura do seu sistema.

Então, você não entendeu. O framework em questão (que é um completo lixo por sinal) SEMPRE acessa o atributo diretamente e não quer nem saber se existe getter ou setter. Estou dando manutenção no sistema e tentando refatorá-lo para eliminar esse framework para sempre.

Neste caso, você está afirmando que se toda a minha lógica de negócio for em cima do diâmetro, mas por algum motivo qualquer o BD trabalhe com o raio e isso não possa ser mudado, então eu vou ser obrigado a mudar toda a lógica do meu sistema apenas para satisfazer um desejo do BD porque o raio deveria ser uma propriedade e não o diâmetro?

É correto eu compremeter o encapsulamento do meu objeto só porque o FP precisa disso?

Vamos supor que eu NÃO CONFIE no BD. Vamos supor que o número de parcelas deve sempre ser positivo, mas vamos dizer também que no passado havia algum bug que fazia com que em alguns registros surgisse um número de parcelas negativo. Se no meu setter eu colocar um if (numeroParcelas <= 0) throw new IllegalArgumentException(), qual é o resultado? O FP explode. Até que está correto em ele explodir, pois está trabalhando com algo inválido. O problema é que isso por sua vez pode comprometer a robustez e deixar o sistema extremamente intolerante a falhas (inclusive impedindo que o usuário possa retificar o valor sem acessar o BD diretamente). Isso força eu simplesmente deixar que o objeto fique inválido ou então fazer o setter falhar silenciosamente ou setar algum campo para avisar que o objeto é defeituoso ou qualquer outro tipo de gambiarra apenas para remendar o problema.

Concordo com quase tudo disso, especialmente se o framework pudesse usar uma factory seria muito legal. Só discordo no ponto de "na real, qual é o programador que quer fazer isso ? A maioria nem sabe declarar o construtor direito … " Se eu estiver criando um objeto Semáforo que já venha em um estado "Verde, amarelo ou vermelho", sou obrigado a criá-lo sem estado para depois dar um setCor nele? Isso cria um problema de coesão sequencial. E se a maior parte dos programadores não sabe declarar construtor, bem, acho que não preciso comentar isso.

Ou seja, na verdade eu seria obrigado a colocar a validação em um outro objeto, quando na verdade ela deveria estar no objeto em questão. Mas, isso mostra uma direção a seguir para resolver o problema. Se o VO fosse um objeto que simplesmente fosse usado para isolar o BD e mais nada, o objeto de verdade teria a validação dentro dele mesmo.
Sim, o conceito de propriedades diz que elas devem ser independentes, mas nem sempre isso é possível porque as regras de negócio podem exigir coisas estranhas. E quando isso acontece, fazer o que? Sentar e chorar? Socar gambiarra?

Errado, o problema é exatamente que NÃO vai ocorrer nenhum problema e NÃO vai dar nenhuma exception. Para o FP é como se esses atributos fossem públicos e ele fará o que bem entender com eles e ninguém conseguirá impedi-lo. O máximo que você poderá fazer é verificar se o que o FP produziu faz sentido, mas não há nada que possa impedi-lo de criar e retornar tal objeto.

Em um mundo perfeito (o modelador e o DBA são a mesma pessoa) sim, dá para dizer que esse problema acabaria sendo causa de erro da modelagem. Mas, deixa eu ver se entendi, você acha que separar o estado do objeto da sua lógica é algo bom?

Pois é, leva a isso (ex: Expression Language). Mas, vai fazer o que? O problema na verdade é que definir propriedades como um par de métodos com o prefixo "get" e "set" é a maior gambiarra existente na linguagem java. Neste ponto VB e C# são mais felizes. Quem dera se annotations tivessem existido desde o começo… É por isso que considero essa coisa de (java)beans como um antipadrão, uma vez que se baseia na má idéia de inferir a estrutura dos objetos baseando-se no nome dos métodos. Se annotations tivessem surgido no começo, nada disso teria acontecido.

Por si só isso não é um problema. O problema é que isso acaba criando a falsa idéia de que o uso das VOs é legítimo e dificulta o trabalho de eliminá-las, simplesmente porque isso faz com que elas aparentemente simplesmente não possam ser eliminadas. Uma possível saída seria utilizar Map<String, Object> no lugar, mas isso com quase certeza vai acabar criando problemas ainda piores.

E você se esqueceu do principal: Ter bases de dados e/ou aplicações legadas ou de terceiros. E também frameworks que não entendem diametro() e exigem getDiametro() (que como você sabe, remete aos JavaBeans). Outra coisa é o setDiametro. Você usaria setRaio(valor * 2) em TODOS os lugares que precisassem setar o diâmetro?

Ok, pode-se até quebrar os ovos. O negócio é não fazer meleca!

[quote=sergiotaborda]
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…)[/quote]

Eu não disse que todos os frameworks são burros. Eu disse que há muitos frameworks burros (e isso você tem que concordar).

[quote=victorwss][quote=sergiotaborda]
(…)
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.
[/quote]

Ok, vamos supor o seguinte: No banco de dados existe um campo raio. O que significa que o FP usará o atributo raio ou os respectivos getters e setters. Mas, em todo o sistema se trabalha com o diâmetro. Sim, isso é uma inconsistência, mas vamos supor que seja porque o banco de dados é legado ou pertence a terceiros, por exemplo. Pois bem, como o sistema trabalha com diâmetro mas persiste o raio, eu poderia colocar um par de getters e setters para o diâmetro, centralizando a regra de negócio (conversão de raio para diâmetro e vice-versa) no objeto. Mas, se eu não criasse esses getters e setters, o que aconteceria? Eu seria obrigado a pulverizar a regra de conversão em todo o sistema ou então criar algum outro objeto apenas para fazê-la, quando seria muito mais simples, mais fácil E MAIS OO se o próprio objeto soubesse fazê-la.
[/quote]

Existem mais opções que essas que considerou. Partindo agora do principio que se trata de um banco legado ( coisas que eu não parti no post anterior) vc não pode fugir do contrato que o sistema legado tem. Mas vc pode criar mediadores entre esse contrato e o contrato da sua nova aplicação.
Se o objeto original requer um raio porque é o que vai para o banco via introspecção direta do atributo ( eu tinha entendido que o FP lia o get e usada o set ) não vejo problema em criar o get/setDiametro. ( Eu tinha entendido que criar essa propriedade fazia o FP tentar ler e escrever essa propriedade no banco… se isso não acontece, não ha problema alguma)

Vc tem razão, não se pulveriza a regra, criam-se novos métodos.

Não. O que estou dizendo é que se o diametro é uma consequencia do raio, ele não é uma propriedade. No seu caso, ele é uma propriedade “paralela” ao raio. Mas sendo que o seu FP acessa os atributos diretamente os métodos que existem são irrlevantes.
Se o FP acessasse via get/set como falei ( que é o correto) a existencia de uma propriedade “virtual” como diametro causaria problemas. Mas está certo causar problemas já que ele não é uma propriedade real.
O que eu faria para resolve isso é criar um novo objeto herdado do primeiro mas com as novas propriedades ( padrão Decorator)
Para o FP eu mandava o objeto, como é da mesma classe, não teria problema, e o FP me dá o VO original o qual trasnformo no novo VO. Isso é simples se existir um camada de repositorios ou daos especificos de negocio, mas caso não exista pode, realmente, ser um problema. (é nestes casos que a gente ve se o sistema foi bem desenhado/encapsulado) Nesse caso, em que a unica alternativa é usado o VO original com novos métodos, simplesmente não usaria o get/set , faria algo como diamtero() e atribuiDiamtero() para fugir da nomenclatura. contudo isso interfere com a UI, provavelmente. Nesse caso seriam os objetos da UI a terem que ser mudados.
Fazer refactoring em sistemas legados não é fácil. as suas opções são limitadas e freqüentemente herança é a unica saida porque vc quer que o novo objeto se comporte como o velho, mas com mais alguma coisa. (padrão Decorator , Visitor e em alguns casos Proxy e Adapter)

Eu tinha entendido que o seu FP acessava via get/set e que isso lhe causava um problema quando adicionava o get/setDiametro.
Nesse caso o problema não era do FP e sim do contrato do seu objeto. Foi isso que tentei explicar.
Agora, se o FP acessa os atributos directamente via reflection e ignora os get/set então é o FP que está errado.

Veja, vc inclui campos privados e modificadores e acessores publicos para proteger os dados. Mas ai o seu FP viola as regras e vai direto no coração da coisa. Isso é uma violação clara do encapsulamento. Tlv vc não se importe com isso, mas mais valai os seus atributos serem simplesmente publicos e pronto: fim do problema de encapsulamento. Aceitar as duas coisas - objeto protegido e FP com reflection - não é coerente. Se vc sabe que o FP é introspectivo nos campos directamente nem precisa de set e get.

não é correto comprometer o encapsulamento em hipotese alguma. Mais vale tirá-lo do que viver em um mundo fingido de proteção. Se o FP precisa disso e não ha como alterar o FP , retire o encapsulamento em vez. O problema em legado é que a estrutrua já foi feita e se foi feita torta agora não tem como a endireitares ( não se muito esforço mental para arrajnar truques de OO que funcionam, mantem o sentido legado mas são OO)

Isso é normal. Não é o FP que explode, é o setter. O FP simplesmente reage a isso.

Exatamente!

[quote]O problema é que isso por sua vez pode comprometer a robustez e deixar o sistema extremamente intolerante a falhas (inclusive impedindo que o usuário possa retificar o valor sem acessar o BD diretamente).
[/quote]

O sistema não deve ser tolerante a esse tipo de falhas porque isso é uma violação de segurança. O sistema não deve ignorar isso.
Imagine que foi alguem que entrou no banco e correu um virus que simplesmente troca o sinal de todos os numeros. O sistema não pode tolerar isso. É um desastre. é melhor que ele pare de funcionar do que funcionar errado.

Mas ai é que está. Inválido é diferente de Incosistente. O seu objeto está consistente mesmo com valor negativo. Só que ele não está válido. O FP pode retornar objetos inválidos, o que ele não pode fazer é criar objetos inconsistentes. Se a regra no set é destinada a evitar problemas de leitura de registros com dados impossiveis, isso é consistencia e está certo que tudo dê pau e o sistema como um todo aborte. ( na real, um log é gerado e uma mensagem amigável é enviada ao usuário, o resto do sistema continua funcionando -isso é tolerancia a erro , tb)

Vc está limitando muito as suas opções pensando assim. Vc pode simplesmente ter um construtor privado e ter métodos que lhe retorna o semaforo no estado correto( factory method) Por exemplo:


class Semaforo{

    public static Semaforo verde(){
          Semaforo  s = new Semaforo ();
          s.estado = VERDE;
           return s;
   }
  
   SemaforoEstado estado; // enum VERDE, AMARELO, VERMELHO
   private Semaforo(){}

  public SemaforoEstado  getEstado(){
        return estado;
  }

}

não ha construtor , nem set. Só um get porque a cor é uma propriedade read-only.
É com este tipo de objeto corretamente estruturado que os FP da vida têm problemas.
E eles os têm porque não permitem que factory decida como criar o objeto a partir dos dados do registro.

O objeto NUNCA tem a validação dentro dele mesmo. Ele têm a consistência. Por exemplo, um objeto BigDecimal pode ser positivo, zero ou negativo. Ele consiste o seu estado para que assim seja. Contudo ele não sabe nada sobre validação já que isso é uma regra externa. Um objeto com a responsabilidade de validar precisa ser criado à parte.
Então, sim, vc cria outro objeto, mas não, esse objeto não é de entidade.

Não. Usar OO. O objeto de dados pode ter os dados que ele quiser. O objeto de validação irá validar, se esses dados, estão em conformidade para uma situação especifica. Isso normalmente inclui regras de negocio que podem até ser muito complexas.
A criação de objetos de validação em separado do objeto do dados (SoC) permite que vc escolha o algoritmo de validação e o altere sem mexer no objeto de dados (IoC). E pode até compor os validadores( composite). Assim o validador de objeto cliente é a compsição de validadores singulares para cada campo. E esses são muito reproveitáveis ( isNull, isInRange, hasSize , etc. )

Tudo bem. Não é responsabildiade do FP validar o objeto. Se o sistema aceita que objeto seja modificado via reflection isso signfiica que qualquer coisas é um estado consistente (que é o mesmo que dizer que não ha consistencia alguma).
Vc pode resolver isso facilmente com um objeto validador para interomper as coisas se os dados não podem ser aceites.

Não. O que eu acho é que o pessoal escolhe errado na hora de definir o que é “a lógica do objeto”.
Por exemplo, lançar métodos de crud no objeto é considerado por alguns a “lógica do objecto” quando isso não poderia ser mais contrário ao que seria a “lógica do objecto”. O exemplo bom é o BigDecimal. Vc pode usá-lo como VO e ele não contem nenhuma lógica do negocio. Contudo ele contém muita lógica do seu domínio (operações aritméticas, conversões ,etc).
Poderíamos dizer que BigDecimal é um objeto cheio de “lógica de objeto” mas vazio de "lógica de sistema"
eu acho que vc deve criar objetos ricos no sentido que eles contenham "lógicas de objeto’ e até lógica de domínio (logicas de sistema comuns a muitos sistemas) mas colocar a lógica do sistema nos objetos deve obedecer ao principio de separação de responsabilidade e isso significa que entulhar todas as logicas num objeto só tb não e´certo ( pro exemplo, colocar um metodo no usuário para validar o login e senha dele). É ai que entra a verdadeira OO , é ai que o desenvolvedor tem que mostrar porque tem esse papel e é ai que as coisas “acontecem”.
dividir as coisas entre “objetos com lógica” e “objetos sem lógica” ainda é deficiente. Isso leva à prática ( que vemos no GUJ ser referida ad naseum) de saturar o objeto com um mote de métodos de negocio. ie, um monte de responsabilidades que não lhes competem. É aqui que entra a separação clara de Entidades, Agregados, Valores e Serviços e demais objetos de aplicação com responsabilidades bem definidas. Isso é o Principio de Separação de Responsabilidade em ação.

Ora ai é que está. O uso de VO é legitimo. Mas como toda a legimitidade advém do consenso.
Quando à tempos atrás isso era papagaiado pela sun e todo o mundo aceitável era legitimo. Hoje com essa conversa de que objetos precisam ter lógicas ele é ilegitimo para quem pensa dessa forma.
Para mim é uma questão de contexto. Pense num webservice : nada é mais do que um grafo de VO colocado em XML e recontiuido do outro lado. Neste caso é legitimo. Imagine uma API e interface que o seu programa deixa livre para uso por scripts. Ai tb é legitimo pq vc precisa de isolamento. Quando vc trabalha em difernetes JVM mas a comunicação é interna ao ppr sistema ( por exemplo, swing acessando ejb noutr máquina) tb é legitimo. Existem muitos lugares e ocasiões em que é legitimo usar VO (atualemnte chamados TO- Transfer Objet).
Forçar que todos os objetos do seu sistema sejam “não-VO” ou “não-anémicos” também é um erro. A virtude está no meio, sendo alguns VO e outros não dependendo das suas responsabilidades.

Veja, no seu sistema de FP os seus VO têm qual responsabilidade ? Transferir dados.
Transferir dados é tão honrado quando manipular dados ou comunicar protocolos. Não ha nada de errado em que objetos tenham apenas uma responsabilidade. O desafio é que todos os objetos de todo o sistema tenham apenas uma responsabilidade.

Ficar gritando que les deveria ter mais responsabilidade sem saber qual ela seria é vazio.

Até poderia aceitar isso se todas as outras opções falhassem, mas a minha tendencia seria usar um Decorator para não ter que fazer isso. Mas apenas se fosse realmente muito importante. ( o exemplo do diametro é um bom exemplo, mas não parece muito importante… entende?)

[quote]

[quote=sergiotaborda]
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…)[/quote]

Eu não disse que todos os frameworks são burros. Eu disse que há muitos frameworks burros (e isso você tem que concordar).[/quote]

sim, concordo. Principalmente porque a maioria vai directo nos atributos e ignora os acessores/modificadores. (existe uma razão para se chamarem “acessores” … todo o acesso é feito por eles!)

  • O que leva as pessoas a criar VOs anêmicas?

A pergunta deveria ser

Quem lucra (e como) com pessoas que criam VOs anêmicas?

//