Esta classe seria um modelo anêmico?

74 respostas
danielbussade

Olá a todos do GUJ, há um tempo atrás estava desenvolvendo em conjunto com um amigo, um sistema de E-commerce, percebi que em muitas classes tinha um “que” de modelos anêmicos, por exemplo a classe PedidoVenda abaixo.

public class PedidoVenda {
	private KeyPedidoVenda keyPedidoVenda;
	private Date dataPedido;
	private String observacao;
	private String status;
	private Float total;
	private Boolean entregueAoCliente;
	private Boolean montagem;
	private Double totalBruto;
	private Double valorDesconto;
	private Boolean entregaDomicilio;
	private Float valorFrete;
	private CondicaoPagamentoVenda condicaoPagamentoVenda;
	private Cliente cliente;
	private Endereco endereco;
	private String keyBoleto;
	private List<ItemPedidoVenda> itens;
	private String ipCompra;
	private Date da;
	private String obsCancelamento;
	private String nomeFormaDeEnvio;
	private Integer qItem;
	private String idVendedor;
	private String tid;

}

A maioria dos campos, são inseridos diretamente pelo construtor, ou seja como os pedidos nao podem ser editados, esta classe eh uma classe imutável, eu nao precisarei de getters e setters, não só esta classe mas algumas outras são definidas assim.
Este tipo de classe seria um “modelo anêmico”, é correto este tipo de programação??

Gostaria de opiniões sobre o assunto!

Att

74 Respostas

victorwss

danielbussade:
Olá a todos do GUJ, há um tempo atrás estava desenvolvendo em conjunto com um amigo, um sistema de E-commerce, percebi que em muitas classes tinha um “que” de modelos anêmicos, por exemplo a classe PedidoVenda abaixo.

public class PedidoVenda {
	private KeyPedidoVenda keyPedidoVenda;
	private Date dataPedido;
	private String observacao;
	private String status;
	private Float total;
	private Boolean entregueAoCliente;
	private Boolean montagem;
	private Double totalBruto;
	private Double valorDesconto;
	private Boolean entregaDomicilio;
	private Float valorFrete;
	private CondicaoPagamentoVenda condicaoPagamentoVenda;
	private Cliente cliente;
	private Endereco endereco;
	private String keyBoleto;
	private List<ItemPedidoVenda> itens;
	private String ipCompra;
	private Date da;
	private String obsCancelamento;
	private String nomeFormaDeEnvio;
	private Integer qItem;
	private String idVendedor;
	private String tid;

}

A maioria dos campos, são inseridos diretamente pelo construtor, ou seja como os pedidos nao podem ser editados, esta classe eh uma classe imutável, eu nao precisarei de getters e setters, não só esta classe mas algumas outras são definidas assim.
Este tipo de classe seria um “modelo anêmico”, é correto este tipo de programação??

Gostaria de opiniões sobre o assunto!

Att

Pelo que você descreveu, não, não é anêmica. Saber se é o jeito correto? Seria necessário você descrever mais a fundo o sistema. Mas só o fato de você ter pensado em imutabilidade já mostra que possivelmente você está fazendo a coisa certa.

Mas, me faz lembrar de uma outra questão bem diferente… Quem foi que inventou a idéia (ao meu ver absurda, mas posso estar errado), de que classes de entidades não podem ter atributos de tipos primitivos?

danielbussade

Então vitor, obrigado pela resposta, antigamente quando comecei a programar em java, a primeira coisa que fazia nas classes depois de definir os atributos era o Eclipse mandar gerar todos getters e setters, só que como você mesmo observou em outro tópico , isso apenas cria um falso encapsulamento, já que o getter e setters nao fazem nada mais, não há nenhuma regra de negócio envolvida.

Então hoje so defino getter e setter no que realmente há necessidade, quando não há regra nehuma, coloco ele direto no construtor, não sei se isso é correto se não for queria saber outra forma de fazer.

Valeu

C

victorwss:

Mas, me faz lembrar de uma outra questão bem diferente… Quem foi que inventou a idéia (ao meu ver absurda, mas posso estar errado), de que classes de entidades não podem ter atributos de tipos primitivos?

Pq tipo primitivo não pode ser null, e para certos sistemas, null é diferente de 0.

rafaelglauber

chicobento:
victorwss:

Mas, me faz lembrar de uma outra questão bem diferente… Quem foi que inventou a idéia (ao meu ver absurda, mas posso estar errado), de que classes de entidades não podem ter atributos de tipos primitivos?

Pq tipo primitivo não pode ser null, e para certos sistemas, null é diferente de 0.

http://www.hibernate.org/116.html:

Hibernate throws a PropertyAccessException or NullPointerException when I load or query an object!

A PropertyAccessException often occurs when the object being passed to the setter method is of the wrong type. Check your type mappings for the offending property. (To see exactly which property was the problem, you might need to disable the CGLIB reflection optimizer.) However, the most common cause of this problem is that Hibernate attempted to assign null to a property of primitive type.

If your object has a primitive-type property mapped to a nullable database column then you will need to use a Hibernate custom type to assign a sensible default (primitive) value for the case of a null column value. A better solution is usually to use a wrapper type for the Java property.

Como muita gente usa Hibernate…

danielbussade

rafaelglauber:
chicobento:
victorwss:

Mas, me faz lembrar de uma outra questão bem diferente… Quem foi que inventou a idéia (ao meu ver absurda, mas posso estar errado), de que classes de entidades não podem ter atributos de tipos primitivos?

Pq tipo primitivo não pode ser null, e para certos sistemas, null é diferente de 0.

http://www.hibernate.org/116.html:

Hibernate throws a PropertyAccessException or NullPointerException when I load or query an object!

A PropertyAccessException often occurs when the object being passed to the setter method is of the wrong type. Check your type mappings for the offending property. (To see exactly which property was the problem, you might need to disable the CGLIB reflection optimizer.) However, the most common cause of this problem is that Hibernate attempted to assign null to a property of primitive type.

If your object has a primitive-type property mapped to a nullable database column then you will need to use a Hibernate custom type to assign a sensible default (primitive) value for the case of a null column value. A better solution is usually to use a wrapper type for the Java property.

Como muita gente usa Hibernate…

Concordo com você, mas também não podemos transforma isso em regra neh , porque tem muita gente que ainda usa JDBC na mão!!

victorwss

E se a coluna para a qual ela mapeia for NotNull? E se for intencional o comportamento 0 = null?

Uma coisa que eu acho particularmente irritante é o uso do Boolean no lugar de boolean. Isso porque Boolean tem 3 estados e não 2 (true, false e null). E 95% das vezes que aparece o valor null, eu gostaria que ele fosse tratado como false, mas quando vem o Boolean eu sou obrigado a trabalhar com uma lógica booleana de três estados e ficar cabreiro com NullPointerExceptions.

EDIT: E não é certo (em um modelo de orientação a objetos pura e perfeita) quebrar a modelagem de suas classes por conta de limitações de frameworks.

C

Com JDBC vc ainda tem o mesmo problema…

victorwss

chicobento:
Com JDBC vc ainda tem o mesmo problema…

Não.
Leia isso

rafaelglauber

regra não é…só dei um exemplo por que o povo fala tanto isso… :smiley:

EDIT: já esculhambamos a thread…foi mau!

danielbussade

regra não é…só dei um exemplo por que o povo fala tanto isso… :smiley:

EDIT: já esculhambamos a thread…foi mau!

É verdade a thread começou com uma pergunta e depois partimos para outra dúvida, mas isso é normal

Att

C

Tudo bem, parabéns, vc conseguiu descobrir que essa coluna erra null e populou seu atributo como 0. Agora, imagina que na tela por exemplo, vc precisa diferenciar se era 0 ou null. Ou você usa a regra da inferência de que 0 == null, ou você adiciona outro atributo na sua classe dizendo que o valor daquele campo era null.
Não vamos desvirtuar, acho que você já entendeu que essa idéia não é tão absurda assim como vc pensava anteriormente.

victorwss

chicobento:
victorwss:

Não.
Leia isso

Tudo bem, parabéns, vc conseguiu descobrir que essa coluna erra null e populou seu atributo como 0. Agora, imagina que na tela por exemplo, vc precisa diferenciar se era 0 ou null. Ou você usa a regra da inferência de que 0 == null, ou você adiciona outro atributo na sua classe dizendo que o valor daquele campo era null.
Não vamos desvirtuar, acho que você já entendeu que essa idéia não é tão absurda assim como vc pensava anteriormente.

int x = rs.getInt(1);
minhaEntidade.setValorInteger(rs.wasNull() ? null : x);

Onde você precisa saber se era nulo usa uma classe empacotadora. Onde nulos não fazem sentido, usa primitivo. Eu não disse para usar primitivo sempre, apenas não concordo com a idéia de usar empacotadoras sempre.

victorwss

regra não é…só dei um exemplo por que o povo fala tanto isso… :smiley:

EDIT: já esculhambamos a thread…foi mau!

É verdade a thread começou com uma pergunta e depois partimos para outra dúvida, mas isso é normal

Att

Isso é fácil. Quando um tópico desvirtua para uma coisa, basta desvirtuar esta outra coisa novamente de volta para a pergunta original. :smiley:

B

victorwss:
chicobento:
Com JDBC vc ainda tem o mesmo problema…

Não.
Leia isso

Gambiarra.

Fora que SQL já é uma gambiarra.

Andre_Fonseca

Bruno Laturner:
victorwss:
chicobento:
Com JDBC vc ainda tem o mesmo problema…

Não.
Leia isso

Gambiarra.

Fora que SQL já é uma gambiarra.

Porque SQL é gambiarra??

qmx

Porque ainda tem gente que acha que SGBD’s são uma tecnologia não-madura, que nunca vai emplacar e acreditam no coelhinho da páscoa.

Sinceramente, acredito mais na possibilidade de ORM ser uma gambiarra do que SQL (Eu amo ORM, diga-se de passagem).

Não dá pra simplesmente jogar fora anos de pesquisa e maturação. Algumas coisas vc usa (Query’s malucas pra tirar o relatório que o chefe pediu pra ontem), outras vc coloca na prateleira e diz o quanto já te foi útil (Struts 1.x)

:mrgreen:

Desculpem o tom irônico, aprendi essa lição da pior forma possível… Não desprezar o que o mercado usa… Não desprezar o que o mercado usa…
e principalmente, não cuspa em uma tecnologia, pode ser que ela encha sua orelha de grana amanhã.

Alessandro_Lazarotti

Voltando a pergunta inicial sobre o modelo anêmico.

Não dá para afirmar se sua classe é anêmica ou não uma vez que os métodos estão omitidos. O que faz uma classe anêmica é definir na classe seus dados mas não seu comportamento:

Fowler:

“The fundamental horror of this anti-pattern is that it’s so contrary to the basic idea of object-oriented design; which is to combine data and process together. The anemic domain model is really just a procedural style design, exactly the kind of thing that object bigots like me (and Eric) have been fighting since our early days in Smalltalk. What’s worse, many people think that anemic objects are real objects, and thus completely miss the point of what object-oriented design is all about.” http://www.martinfowler.com/bliki/AnemicDomainModel.html

Algumas classes são anêmicas por natureza, isso não é probelma, o anti-pattern mora no coração daquelas que possuem comportamentos mas estes não são refletidos em sua implementação.

B

qmx:
Porque ainda tem gente que acha que SGBD’s são uma tecnologia não-madura, que nunca vai emplacar e acreditam no coelhinho da páscoa.

Sinceramente, acredito mais na possibilidade de ORM ser uma gambiarra do que SQL (Eu amo ORM, diga-se de passagem).

Não dá pra simplesmente jogar fora anos de pesquisa e maturação. Algumas coisas vc usa (Query’s malucas pra tirar o relatório que o chefe pediu pra ontem), outras vc coloca na prateleira e diz o quanto já te foi útil (Struts 1.x)

:mrgreen:

Desculpem o tom irônico, aprendi essa lição da pior forma possível… Não desprezar o que o mercado usa… Não desprezar o que o mercado usa…
e principalmente, não cuspa em uma tecnologia, pode ser que ela encha sua orelha de grana amanhã.

Não tenho nada contra SGBDs, aliás a teoria dos conjuntos e a relacional são umas das mais úteis no campo da matemática aplicada. Tem lugar garantido.

Só tenho muita coisa contra SQL(e DDL):

[list][<em>] é a linguagem padronizada com mais implementações não-padrão que existe;

[</em>]qualquer coisa fora de CRUD de uma tabela  é um horror para montar;

[*] e que ela é uma linguagem humanizada demais, sendo que seus clientes principais são programas de computador, e -lhe horas gastas traduzindo um modelo p/ outro.[/list]

[size=7](Off: este software jforum tb é outra porc…)[/size]

danielbussade

Alessandro Lazarotti:
Voltando a pergunta inicial sobre o modelo anêmico.

Não dá para afirmar se sua classe é anêmica ou não uma vez que os métodos estão omitidos. O que faz uma classe anêmica é definir na classe seus dados mas não seu comportamento:

Então lezinho eu perguntei justamente se ela se caracteriza uma classe anêmica porque só tem um metodo que tenha regra de negócio que o metodo getTotalPedido(), os outros são todos definidos no construtor.

Gostaria de saber se essa eh uma abordagem correta, se não quais são as outras alternativas, e se isso faz dessa classe um modelo anêmico.

Valeu

danielbussade

Bruno Laturner:
qmx:
Porque ainda tem gente que acha que SGBD’s são uma tecnologia não-madura, que nunca vai emplacar e acreditam no coelhinho da páscoa.

Sinceramente, acredito mais na possibilidade de ORM ser uma gambiarra do que SQL (Eu amo ORM, diga-se de passagem).

Não dá pra simplesmente jogar fora anos de pesquisa e maturação. Algumas coisas vc usa (Query’s malucas pra tirar o relatório que o chefe pediu pra ontem), outras vc coloca na prateleira e diz o quanto já te foi útil (Struts 1.x)

:mrgreen:

Desculpem o tom irônico, aprendi essa lição da pior forma possível… Não desprezar o que o mercado usa… Não desprezar o que o mercado usa…
e principalmente, não cuspa em uma tecnologia, pode ser que ela encha sua orelha de grana amanhã.

Não tenho nada contra SGBDs, aliás a teoria dos conjuntos e a relacional são umas das mais úteis no campo da matemática aplicada. Tem lugar garantido.

Só tenho muita coisa contra SQL(e DDL):

[list][<em>] é a linguagem padronizada com mais implementações não-padrão que existe;

[</em>]qualquer coisa fora de CRUD de uma tabela  é um horror para montar;

[*] e que ela é uma linguagem humanizada demais, sendo que seus clientes principais são programas de computador, e -lhe horas gastas traduzindo um modelo p/ outro.[/list]

[size=7](Off: este software jforum tb é outra porc…)[/size]

Tudo bem se você acha SQL uma porcaria, agora então quais seriam as alternativas para se fazer uma query onde eu precise juntar dados de duas ou mais tabelas??

pcalcado

Como disseram antes, não se pode afirmar que seu modelo é anêmico porque você não postou sequer a classe toda.

Mas, anêmica ou não, me parece que sua classe tem ums problemas de modelagem. 23 atributos?

danielbussade

pcalcado:
Como disseram antes, não se pode afirmar que seu modelo é anêmico porque você não postou sequer a classe toda.

Mas, anêmica ou não, me parece que sua classe tem ums problemas de modelagem. 23 atributos?

Philip eh que o E-commerce foi feito com um banco de dados legado, onde já funcionava um sistema assim com todos estes controles no PedidoDeVenda, somente segui o que a empresa ja tinha.

Quanto a classe toda, a minha duvida toda eh justamente essa, visto que a classe isso ai + os getters porque eu nao preciso de um set, pois ela imutavel tudo eh setado no construtor, entao ela possue um construtor gigante. Queria saber se isso caracteriza um modelo anêmico eh se ha outras alternativas?

Att

pcalcado

danielbussade:

Quanto a classe toda, a minha duvida toda eh justamente essa, visto que a classe isso ai + os getters porque eu nao preciso de um set, pois ela imutavel tudo eh setado no construtor, entao ela possue um construtor gigante. Queria saber se isso caracteriza um modelo anêmico eh se ha outras alternativas?

Att

Isso não tem muito a ver com modelo anêmico mas tem a ver com modelagem ruim. Não é porque sua tabela etá modelada de uma maneira estranha que seus objetos precisam estar, você pode ter vários objetos sendo populados por uma tabela. Aliás, criar modelos 1-para-1 entre classes e tabelas com bases de dados legads quase sempre é um péssimo negócio.

danielbussade

pcalcado:
danielbussade:

Quanto a classe toda, a minha duvida toda eh justamente essa, visto que a classe isso ai + os getters porque eu nao preciso de um set, pois ela imutavel tudo eh setado no construtor, entao ela possue um construtor gigante. Queria saber se isso caracteriza um modelo anêmico eh se ha outras alternativas?

Att

Isso não tem muito a ver com modelo anêmico mas tem a ver com modelagem ruim. Não é porque sua tabela etá modelada de uma maneira estranha que seus objetos precisam estar, você pode ter vários objetos sendo populados por uma tabela. Aliás, criar modelos 1-para-1 entre classes e tabelas com bases de dados legads quase sempre é um péssimo negócio.

Então philip mas nao vejo quase nada par ser retirado da classse e colocada em outra, mas mesmo se colocasse alguns atributos em outro objeto qual vantagem eu teria, visto que os mesmos tbm nao possuiriam regras de negócio?
O que estou tentando entender eh se uma classe onde quase todos seus atributos são definidos no construtor eh um modelo anêmico , ou o modelo anêmico eh somente quando se separa atributos de metodos(VO e BO)?

Obrigado

pcalcado

Será que não teriam? É difícil falar sem conhecer o domínio mas eu acho muito difícil.

Creio que você não consegue pensar nas regras de negócio sobre estes objetos porque estas regras de negócio estão espalhadas por outros lugares. Dê uma olhada em quem usa estes atributos e pense se quem os maniula deveria estar fazendo isso ou se esta deveria ser uma reponsabilidade do objeto.

Fora uns relacionamentos estranhos. Pedido tem um endereço e um cliente. Será que na verdade não seria o Cliente que tem um endereço?

Outro ponto interessante é o ‘idVendedor’. Objetos não possuem o ID de outros objetos, eles possuem relação com estes. Me parece que você simplesmente pgou o conteúdo do campi na tabela (que é uma chave estrangeira pelo que parece) e colocou no seu objeto. Para ter um domínio mais coerente você deveria ter uma relação entre Pedido e Vendedor, e não seu ID.

Além disso, o que é o total bruto? Será que ele é uma tributo mesmo ou será que é um valor derivado?

Nem um nem outro. Como já dissemos aqui algumas vezes não dá para dizer se sua classe é anêmica ou não. Uma classe anêmica não vai conter regras de negócio dentro dela, vai ser apenas um agrupamento de dados. Onde ficam as regras de negócio do pedido no seu sistema?

danielbussade

Isso realmente foi um erro, o correto seria criar uma classe Vendedor e Pedido ter um Vendedor.

Philip este endereço do Pedido eh o endereço de entrega que muitas vezes pode ser diferente do endereço do cliente que está fazendo o pedido, e pode mudar em cada pedido, por isso coloquei ele no pedido.

O total bruto eh o total do pedido + o juros que será aplicado de acordo com a condição de pagamento que escolher e do grupo do produto a ser comprado, cada grupo de produto junto com uma condição de uma certa quantia de juros aplicada.

Segue em anexo o diagrama de classe do projeto.

Obrigado


danielbussade

Aproveitando o tópico entre esses dois livros sore DDD qual seria mais apropriado para começar

http://domaindrivendesign.org/books/#DDD
http://domaindrivendesign.org/books/#DDD_apply

Att

pcalcado

Pois é, a falta de coesão na classe não te deixa ver isso. Veja só, você tem entregueAoCliente, entregaDomicilio, valorFrete, endereco e certamente outros atributos nesta classe que estão relacionados não ao pedido em si mas sim com sua entrega (e a entrega está relacionada ao produto). Será que esta modelagem não deixou escapar um objeto que modela a entrega?

Se você tem todos estes dados guardados porque você precisa guardar o resultado da comutação e não apenas calcular isso quando precisar? Não é porque algo é um atributo de um objeto que ele precisa ser implementado como um atributo.

Não dá para entender muito do seu sistema baseado nele (diagramas de classe -ou qualquer outro- não são exatamente a melhor maneira de se passar uma idéia). Como falei, sem saber o que você está fazendo é bem difícil dar palpite.

Edito: Sobre livros: o primeiro, de Eric Evans

danielbussade

Pois é Philip agora realmente eu começo a enxergar os benefícios de se criar outras classes e nao ter uma classe faz tudo, acabei de ler um artigo no seu blog sobre ojetos Fantoche e percebi que muitas classes no meu sistema se comportam assim.
A minha dificuldade de migrar para uma Orientação a Objeto eh que eu sempre penso no SGDB, porque venho de um programação procedural.

Mas obrigado pelas dicas, e parabéns pelos artigos do blog.

Esse livro do Eric Evans, poderia me ajudar a migrar para um pensamento Orientado a Objeto se não teria alguma indicação de livro que possa me passar.

Obrigado !

Emerson_Macedo

Para migrar para um pensamento OO, Page Jones é bem legal.

C

danielbussade:

Esse livro do Eric Evans, poderia me ajudar a migrar para um pensamento Orientado a Objeto se não teria alguma indicação de livro que possa me passar.

Obrigado !

Domain-driven design e OO sao coisas bem diferentes. Se eu fosse vc nao me preocuparia com DDD num primeiro momento.

De uma lida sobre SRP e principios e padroes de software OO.

danielbussade

Emerson Macedo:
Para migrar para um pensamento OO, Page Jones é bem legal.

Valeu pela indicação, estou dando uma olhada nele. Eu nunca comprei livro internacional, o inglês deste livro eh bem puxado ou eh tranquilo de entender?

Obrigado

Emerson_Macedo

Precisa ter um bom inglês em nível de leitura.

danielbussade

Ok philip mas agora veio uma questao na cabeça; E seu precisar persistir este dado no banco, já que uso o Hibernate pra isso, como vou persistir este atributo visto que ele nao faz parte do objeto?

Obrigado

pcalcado

Não entendi, se ele é derivado e se os que o originam são persistidos por que você o precisaria persistir? Talvez não tenha ficado claro mas o que eu sugrei inclui uma mudança também no modelo de dados. Se isto não é possível então é outra história.

Como ponto relevante, se fosse o caso você poderia fazer o Hibernate utilizar métodos get/set (ou talvez métodos anotados, não conheço Hibernate Annotations) ao invés de atributos.

danielbussade
Desculpe eu expliquei mal, é que esse sistema e dependente de outro desktop que eh oque fatura os pedidos e usa este campo para recuperar o valor bruto, e nao tenho acesso a esse sistema entao nao posso mudá-lo por isso preciso persitir o campo tbm.

Agora voltando a questão do modelo anêmico, em uma classe simples Philip como essa:

public class User {
 
private Integer id;
private String login;
private String senha;
private Date dataCadastro;

}

Nesta classe onde nao tenho regra de negocio, eh um simples CRUD, acaba se tornando anêmica, porque o que acontece eh que recupero os valores que o usuario digitou com input.getParameter(“qualquerCoisa”), vindo de HttpRequest e passo todos os valores no construtor.
Quase todas as classes são assim, ou seja a minha dúvida eh se uma classe eh um simples cadastro ou seja nao tem regra de negocio envolvida acaba se tornando um agrupamento de dados, isso faz dela uma classe anêmica??

C

danielbussade:
Desculpe eu expliquei mal, é que esse sistema e dependente de outro desktop que eh oque fatura os pedidos e usa este campo para recuperar o valor bruto, e nao tenho acesso a esse sistema entao nao posso mudá-lo por isso preciso persitir o campo tbm.

Agora voltando a questão do modelo anêmico, em uma classe simples Philip como essa:

public class User {
 
private Integer id;
private String login;
private String senha;
private Date dataCadastro;

}

Nesta classe onde nao tenho regra de negocio, eh um simples CRUD, acaba se tornando anêmica, porque o que acontece eh que recupero os valores que o usuario digitou com input.getParameter(“qualquerCoisa”), vindo de HttpRequest e passo todos os valores no construtor.
Quase todas as classes são assim, ou seja a minha dúvida eh se uma classe eh um simples cadastro ou seja nao tem regra de negocio envolvida acaba se tornando um agrupamento de dados, isso faz dela uma classe anêmica??

Mais ou menos.

Seu usuário pode alterar a senha ? Sendo assim, vc poderia colocar um método do tipo:

boolean changePassword(oldPass, new);

Seu sistema tem alguma regra forte para o password ?
Seu usuário tem permissão de acesso somente a determinadas funcionalidades ?
Vc pode adicionar esses comportamentos na classe User também.

Se vc for enxergar somente o CRUD, a classe deve ser simples, mas qdo vc começa a visualizar o relacionamento dessa entidade com o resto do sistema, você começa a evoluir o seu modelo.

[]'s

danielbussade

Interessante as dicas. O que eu tava falando e que acho uma programação “feia” tipo tira da tela, passa tudo no construtor e da um em.persist(objeto) pro banco, fica uma coisa sem lógica nenhuma.
Mas nao tinha pensando no que você falou quando começa a interagir com o resto do sistema eh que a classe vai ganhando vida;

O maior problema disso tudo eh o seguinte, na maioria das vezes eu utilizo frameworks que fazem controle de acesso definidos por grupo, validação dos dados tipo CPF, CNPJ, Datas, etc… o que acaba deixando a classe anêmica, por isso que to querendo começar a estudar DDD, pelo que sei as regras em DDD ficam no model,(me corrijam se eu estiver errado), então em DDD, as o papel de um framework WEB por exemplo acaba nao sendo tao importante, certo? Ou to falando besteira!

Valeu

T

danielbussade:
Interessante as dicas. O que eu tava falando e que acho uma programação “feia” tipo tira da tela, passa tudo no construtor e da um em.persist(objeto) pro banco, fica uma coisa sem lógica nenhuma.
Mas nao tinha pensando no que você falou quando começa a interagir com o resto do sistema eh que a classe vai ganhando vida;

O maior problema disso tudo eh o seguinte, na maioria das vezes eu utilizo frameworks que fazem controle de acesso definidos por grupo, validação dos dados tipo CPF, CNPJ, Datas, etc… o que acaba deixando a classe anêmica, por isso que to querendo começar a estudar DDD, pelo que sei as regras em DDD ficam no model,(me corrijam se eu estiver errado), então em DDD, as o papel de um framework WEB por exemplo acaba nao sendo tao importante, certo? Ou to falando besteira!

Valeu

Daniel,

acredito que se você já utiliza frameworks que atendem seu cenário, te garantem qualidade (com ou sem testes automatizados) e mantenham teu projeto fácil de manter você não precisa aprender DDD só porque é a moda do momento.

Geralmente nós temos o impulso automático de pichar o que não é DDD ou é orientado a banco de dados. O importante nisso tudo, antes de sair pichando, é verificar se, independente de modelagem e arquitetura, as práticas utilizadas atendem ao negócio e trazem a produtividade e qualidade esperada. Se meus clientes estão felizes e tudo vai bem (de verdade) pouco importa as práticas de engenharia utilizadas.

danielbussade

Olá eu nao estou querendo aprender DDD só porque e moda do momento, quero aprender porque acho que com DDD a coisa se torna mais OO, além disso o cliente participa mais dando sugestões e contribuindo para o software, além do que acho muito interessante outras coisa pregadas em DDD como o padrão Repository por exemplo.

Quando a questão da satisfação dos cliente eu concordo com você, mais tbm construir sistemas mais OO que permitem mais escalabilidade em conjunto com a satisfação dos cliente nao faz mal nenhum.

Valeu

T

Daniel, me desculpe se pareceu rude meu comentário.

O que eu quis dizer é que o fato de você querer aprender DDD é totalmente legítimo. O único ponto que vale pesar é se é uma boa aplicar DDD neste projeto onde você já trabalha com todos esses frameworks que já funcionam.

Uma dica interessante que li, se não me engano no livro a respeito de DDD do Jimmy Nilsson, é “Don’t fight your framework”. Se você tem frameworks para alguma tarefa e seu framework a tornou simples não vale a pena brigar com o framework ou até remove-lo só pra ter um modelo mais DDD.

Neste caso, só o fato de você ter separação de classes e nomenclatura de acordo com seus Domain Experts é um grande benefício.

danielbussade

Nada que isso de forma alguma :slight_smile:

Neste projeto e praticamente impossivel mexer visto que teria que mudar o sistema quase todo, e isso eh inviavel, mas penso em usar DDD nos proximos projetos, resta saber realmente se vale a pena. Mas valeu pelas dicas.

Abraço

C

No caso da validação, pra vc evitar overhead, vc pode deixar isso com o seu framework web, mas vc ñ deve generalizar.
No exemplo que eu citei anteriormente, vamos supor que o usuário possa alterar a senha (e obviamente, o sistema pede a senha atual e a nova senha), caso a senha atual não esteja correta, vc não pode deixar que a alteração ocorra.

Sendo assim, vc poderia fazer:

class User {
     public void chancePassword(String currentPass, String newPass) throws InvalidPasswordException {
          if (!password.equals(currentPass)) {
                throw new InvalidPasswordException();
          } else {
              password = newPass;
          }
     }
}

Entendeu ?

danielbussade

chicobento:
No caso da validação, pra vc evitar overhead, vc pode deixar isso com o seu framework web, mas vc ñ deve generalizar.
No exemplo que eu citei anteriormente, vamos supor que o usuário possa alterar a senha (e obviamente, o sistema pede a senha atual e a nova senha), caso a senha atual não esteja correta, vc não pode deixar que a alteração ocorra.

Sendo assim, vc poderia fazer:

class User {
     public void chancePassword(String currentPass, String newPass) throws InvalidPasswordException {
          if (!password.equals(currentPass)) {
                throw new InvalidPasswordException();
          } else {
              password = newPass;
          }
     }
}

Entendeu ?

Entendi, então o que vou fazer agora e deixar a validação de documentos para o framework como CPF, CNPJ e etc…, e as outras vou colocar todos no model.

Valeu

pcalcado

O problema não é uma ou outra classe no sistema ser assim, isso acontece. O problema é você dizer que a maioria das classes são assim. Creio que você não está conseguindo enxergar suas regras porque elas estão diluídas em muitos lugares, algo bem comum. Dê uma olhada na sua validação de formulário, consultas SQL e outro suspeitos. Procure classes com ifs e iterações. Provavelmente suas regras de negócio que deveriam estar nos objetos de negócio estão espalhadas nestes.

wariows

pcalcado:
danielbussade:

Ok philip mas agora veio uma questao na cabeça; E seu precisar persistir este dado no banco, já que uso o Hibernate pra isso, como vou persistir este atributo visto que ele nao faz parte do objeto?

Não entendi, se ele é derivado e se os que o originam são persistidos por que você o precisaria persistir? Talvez não tenha ficado claro mas o que eu sugrei inclui uma mudança também no modelo de dados. Se isto não é possível então é outra história.

Como ponto relevante, se fosse o caso você poderia fazer o Hibernate utilizar métodos get/set (ou talvez métodos anotados, não conheço Hibernate Annotations) ao invés de atributos.

Se realmente você precisar persistir esses dados calculados… Você pode anotar o método com @Column(name=“meuatributo”).

Mas se é um valor calculado, é bem estranho que ele seja persistido…

[]´s

danielbussade

pcalcado:
danielbussade:

Nesta classe onde nao tenho regra de negocio, eh um simples CRUD, acaba se tornando anêmica, porque o que acontece eh que recupero os valores que o usuario digitou com input.getParameter(“qualquerCoisa”), vindo de HttpRequest e passo todos os valores no construtor.
Quase todas as classes são assim, ou seja a minha dúvida eh se uma classe eh um simples cadastro ou seja nao tem regra de negocio envolvida acaba se tornando um agrupamento de dados, isso faz dela uma classe anêmica??

O problema não é uma ou outra classe no sistema ser assim, isso acontece. O problema é você dizer que a maioria das classes são assim. Creio que você não está conseguindo enxergar suas regras porque elas estão diluídas em muitos lugares, algo bem comum. Dê uma olhada na sua validação de formulário, consultas SQL e outro suspeitos. Procure classes com ifs e iterações. Provavelmente suas regras de negócio que deveriam estar nos objetos de negócio estão espalhadas nestes.

Olá Philip analisando o sistema percebi que minhas regras de negócio se encontrava no Controller, ou seja meus objetos eram apenas agrupamento de dados, estou modificando o sistema para ter as regras no model. E então me surgiu umas duvidas uma delas eh o seguinte:

Tenho uma classe Usuario e Administrador, onde uma area no sistema somente Administradores tem acesso porque eh uma area de configuracao do sistema, ai na minha action eu recupera via getParameter o que ele digitou chamo o Repository e recupero o Usuario ai na action eu faço um if desta forma:

if(usuario instanceof Administrador) {
  //permiti acesso
}else{
 //Acesso negado
}

Acho que esta abordagem esta incorreta porque se amanha ou depois eu precisar dar acesso ao Diretor por exemplo vou ter que mudar o if, isso cheira “gambiarra”, porem nao vejo outra forma de fazer

Alguem poderia me dar uma ideia??

Obrigado

B
if (usuario.possuiAcesso(funcionalidade)) {
  //permiti acesso
} else {
 //Acesso negado
}
pcalcado

Boa idéia a do Bruno. Se você está usando Domain-Driven Design (que eu assumo já que usou a palavra “Repositório”, apesar de muita gente tem chamado seus DAOs de Repositório por um motivo que eu ainda não entendo) uma Specification pode ajudar neste caso.

peerless

Não entende mesmo ?

pcalcado

peerless:

Não entende mesmo ?

As vezes as pessoas acham que estao fazendo Domain-Driven Design, que é o tema do post, mas eu tenho visto muita gente que nem ouviu falar de DDD e está passando a chamar DAOs de Repositórios como se fosse um novo nome para uma coisa velha.

B

Tem dias que acho que as pessoas tem medo de se orientarem à objetos.

Nem é questão de entrar em mérito se é DDD ou não, mas acho que muita gente está afundada em código de baixo nível (no mesmo sentido de linguagens de baixo/alto nível), preferem uma sintaxe rápida(?!?) e burra a uma inteligente, mais humana.

Falo isso por que vejo, todo santo dia, pessoas (também me incluo) comparando suas estruturas com nulo, com variável igual a tal, se os estado deles é igual a xpto, se é maior, menor blah blah. Tudo bem que é isso que acontece mesmo, você é obrigado a trabalhar com essas construções se quiser ter algum resultado, porém esse código não deveria estar no teu negócio. Código de baixo nível deve ser encapsulado.

Existe uma [color=white]doença^W tendência^W[/color] mania de descobrir quem é objeto, o que tem guardado nele, qual é a relação dele com outro. Se quiser saber alguma coisa do objeto, pergunte ao próprio. Se quiser fazer alguma coisa, mande ele fazer.

Outra mania é usar nulos para expressar alguma coisa. Nulos não expressam coisa alguma!

Caso você procurar por um cliente, e o método de procura retornar um Cliente, retorne o objeto nulo ClienteNãoCadastrado caso você não o achar, depois pergunte ao objeto “cliente.estaCadastrado() ?”. Esqueça de comparar (cliente != null), ou pior, gerar uma ClienteNãoCadastradoException.

Não tema objetos (de verdade)! Aliás, não tema programação limpa, ou Dijkstra vai te pegar!

sergiotaborda
Bruno Laturner:
Outra mania é usar nulos para expressar alguma coisa. Nulos não expressam coisa alguma!

claro que expressa. Expressa "ausência de objeto"

Caso você procurar por um cliente, e o método de procura retornar um Cliente, retorne o objeto nulo ClienteNãoCadastrado caso você não o achar, depois pergunte ao objeto "cliente.estaCadastrado() ?". Esqueça de comparar (cliente != null), ou pior, gerar uma ClienteNãoCadastradoException.

Putz, isso é a maior gambiarra que eu já vi.
Existe um padrão chamado NullObject que cria um objeto especial quando o objeto normal não pode ser criado.
Vc poderia até criar um NullObject que seria esse seu ClienteNãoCadastrado contudo, ele não tem o método "estaCadastrado" por duas razões : 1) se o NullObjet tem esse método o objeto normal tb te que ter o que significa, basicamente , o uso de parametros em vez de OO. 2) estarCadastrado é um conceito que depende do que alguem ( a aplicação) fez com o objeto e não do objeto em si. Logo, um parâmetro que faça isso é uma violação declarada de encapsulamento. Programação orientada a parametros tb não é OO ;)

Vc pode retornar o NulObject, blz, mas depois vc tem que compara assim:

if ( !(obj instanceof ClienteNãoCadastrado)){

}

convenhamos que é muito mais simples e eficiente

if ( obj !=null )){

}

O padrão NullObject é usado em circunstanciais particulares especialmente quando vc vai invocar métodos sobre o objeto, mas nunca como opção ao if de null. (aliás o fato de retornar NullObject ainda não garante que não possa vir null )

O uso correto seria não verificar o null e não comprar o parametro , simplesmente assim:

Cliente cliente  = .. // procura cliente retorna NullCliente se não encontrado

cliente.fazalgumacoisa(); // o metodo de NullCliente simplesmente não faz nada.

Isto funciona quando o objeto usa o padrão Strategy por baixo dos panos, mas se vc tentar usar o objeto como um PropertyBag
vc vai ter problemas para encontrar valores default para o NullObject. Sobretudo em cálculos complexos. (mas vai dai vc provavelmente deveria usar Strategy nesse caso... )

B

Desculpem-me, padrão errado. NullObject é para comportamento padrão. Não chego a esse ponto, ainda estou vários atrás.

O que estou pensando mesmo é que o teu cliente não se importa com “ausência de objetos”, isso não é conceito de domínio; “cliente não cadastrado”, “produto não encontrado” são.

cliente.estaCadastrado() diz mais coisas que cliente == null, que precisa que estar dentro de um contexto para ser entendido. Questão de manutenabilidade.

sergiotaborda

Bruno Laturner:
Desculpem-me, padrão errado. NullObject é para comportamento padrão. Não chego a esse ponto, ainda estou vários atrás.

O que estou pensando mesmo é que o teu cliente não se importa com “ausência de objetos”, isso não é conceito de domínio; “cliente não cadastrado”, “produto não encontrado” são.

cliente.estaCadastrado() diz mais coisas que cliente == null, que precisa que estar dentro de um contexto para ser entendido. Questão de manutenabilidade.

não concordo com essa visão, mas tudo bem…

B

Estou viajando demais quando eu deveria seguir o principio KISS?

sergiotaborda

Estou viajando demais quando eu deveria seguir o principio KISS?

Existe uma razão para que o ultimo S significa Stupid. É para levá-lo a usar o principio. se o não seguir, ele já lhe chama estupido.
O ponto é que “simples” é uma questão de conhecimento , proeficiencia na linguagem, na plataforma e em API de terceiros.
Basicamente o KISS é um não-principio porque é subjetivo.

O principio é muito comparado com a Navalha de Occam, que é um principio da epistemologia da ciencia que dita que se duas teorias
conduzem aos mesmo resultados, a que for mais simples deve ser preferida. Mas aqui “simples” é objetivo, significa a teoria que contiver menos axiomas ou permissas. Não significa, por exemplo, a que for matematicamente mais simples.
Se entendermos o KISS como a Navalha de Occam aplicada ao mundo da programação, então o programa mais simples não é aquele que tem menos código ou menos classes e sim aquele que é mais intelegivel, aquele que parte de menos permissas( tem menos ifs)

Ou seja, usar NullObject é mais simples que comparar com null a toda a hora, embora significa criar um classe a mais.
quanto ao “estaCadastrado” eu não compartilho do seu gosto por esse método porque viola o encapsulamento, como já expliquei.
Preferiria algo como repositorio.contains(cliente). Se certa este codigo parte de menos permissas que o “estaCadastrado” exactamente por não violar o encapsulamento, mas como disse… tudo bem com o seu estilo se funciona para si. Para mim não funciona.

danielbussade

Olá, voltando a idéia inicial do post sobre classes anêmicas, me surgiu outra dúvida, quando não se usa DDD ou seja o seu modelo não fala a mesma língua do cliente, e suas regras de negócio não estão no Domain, e sim espalhadas entre Controller, Façades, etc. As classes acabam se tornando anêmicas não?? Qual seria um alternativa OO em relação ao DDD, sem deixar as classes anêmicas??

Obrigado

C

danielbussade:
Olá, voltando a idéia inicial do post sobre classes anêmicas, me surgiu outra dúvida, quando não se usa DDD ou seja o seu modelo não fala a mesma língua do cliente, e suas regras de negócio não estão no Domain, e sim espalhadas entre Controller, Façades, etc. As classes acabam se tornando anêmicas não?? Qual seria um alternativa OO em relação ao DDD, sem deixar as classes anêmicas??

Obrigado

Sim, vc usa OO, mas não em sua plenitude.
Por exemplo, vc pode utilizar fábricas, interfaces e etc para seus Façades. Sendo assim vc estará usando OO, mas não estará usando OO na parte que mais importa que é o domínio.

danielbussade

Olá, então como havia pensado mesmo usando OO + Design Patterns sem DDD seu Domain seria pobre e acabaria atuando como puppet(fantoche), sendo manipulado por outros objetos, o que caracteriza um modelo anêmico visto que o comportamento esta separado dos estados do objeto.

Obrigado pela resposta!

danielbussade

Fugindo um pouco do assunto, falando do padrão façade, de acordo com esta definição:

Fonte:

http://www.allapplabs.com/java_design_patterns/facade_pattern.htm

O padrão Façade esconde a complexidade atraves de uma interface, certo? Então quando eu tenho um setQualquer coisa, que realiza varias operacoes, para setar um valor, seria um tipo de Façade?
Ou seja a implementação esta escondida eu so disponibilizei a “interface”, se amanha eu quiser mudar o metodo isso nao afetaria meu cliente;
Isso seria uma Façade ou viajei d+.

Valeu

B

GOF sobre Façades:
Intenção:
Fornecer uma interface unificada para um conjunto de interfaces em um subsistema. Façade define uma interface de nível mais alto que torna o subsistema mais fácil de ser usado.

Basicamente ao invés dos teu sistema chamar várias classes de um subsistema, ele chama somente uma classe, e essa encarrega de distribuir os comandos para os responsáveis. É um encapsulamento como você mesmo diz, mas de mais alto nível.

danielbussade

Obrigado pela explicação deixa ver se eu entendi, digamos que tenha duas classes com varios metodos diferentes mas que tenha relação uma com outra, tipo PessoaFisica, e PessoaJuridica cada uma com seus metodos, seria uma Façade eu criar um interface por exemplo Pessoa, e de acordo com o parametro que receber eu invocar metodos em PessoaFisica ou em Juridica?

Valeu

B

O teu exemplo parece mais uma deficiência de uso de polimorfismo que uma Façade.

Façade é uma painel de controle unificado de várias máquinas complexas que fazem parte de um mesmo sistema/fábrica/etc específico.

É beeem alto nível.

danielbussade

Realmente o exemplo foi péssimo. Mas agora deu pra entender.

Att

pcalcado

danielbussade:
Olá, voltando a idéia inicial do post sobre classes anêmicas, me surgiu outra dúvida, quando não se usa DDD ou seja o seu modelo não fala a mesma língua do cliente, e suas regras de negócio não estão no Domain, e sim espalhadas entre Controller, Façades, etc. As classes acabam se tornando anêmicas não?? Qual seria um alternativa OO em relação ao DDD, sem deixar as classes anêmicas??

É perfeitamente possível ter um software completamente baseado em ‘objetos de verdade’ sem correta divisão de camadas, sem domain-driven design e um péssimo design de alto nível. Você pode ter um bom micro-design e um péssimo macro-design.

danielbussade

Olá Philip, poderia me dar um exemplo. Não consigo visualizar um software totalmente OO sem domain driven design ou sem camadas.
Poderia explicar melhor micro-design e macro-design.

Valeu

peerless

danielbussade:
Olá Philip, poderia me dar um exemplo. Não consigo visualizar um software totalmente OO sem domain driven design ou sem camadas.
Poderia explicar melhor micro-design e macro-design.

Valeu

Seus OBJETOS se relacionam, possuem estado, comportamentos, etc.? Sim? Ok, você está usando orientação a objeto. A questão então é: seus objetos possuem um QI a mais voltado ao mundo real?

pcalcado

peerless:

Seus OBJETOS se relacionam, possuem estado, comportamentos, etc.? Sim? Ok, você está usando orientação a objeto. A questão então é: seus objetos possuem um QI a mais voltado ao mundo real?

Exato.

Domain-Driven Design é sobre linguagem. Se você não usa no código a mesma linguagem que seus usuário você ainda pode ter objetos.

Exemplo:

Seu usuário diz: “Um carro estaciona em uma vaga”. Mas no seu código você tem:

class Estacionável{
   List<Posicao> vagasPossiveis;
   String id;
    
   public void estacionar(String idDaPosicao){
      for(Posicao p: vagasPossiveis){
         if(p.getId().equals(idDaPosicao){
           p.ocupadaPor(this);
         }
      }
   }
}

Contra uma alternativa Domain-Driven Design:

class Carro{
 String placa;
 
 public void estacionarEm(Vaga v){
  v.ocupadaPor(this);
 } 
}

Qual a diferença? Em um exemplo isolado pode parecer apenas nomenclatura mas é bem mais que isso, é o fato de que o segundo exemplo tenta implementar o domínio com suas relações, sem “inventar” nenhuma relação que não existe no mundo real (como a de Estacionavel com lista de posicoes no segundo exemplo).

Este texto pode ajudar: http://fragmental.tw/2008/09/23/object-oriented-design-which-how-and-what/

danielbussade

pcalcado:

Exato.
[…]
Este texto pode ajudar: http://fragmental.tw/2008/09/23/object-oriented-design-which-how-and-what/

Ok, philip a questão então eu posso ter um software totalmente OO ou seja com meus objetos possuindo estado se relacionando, mas mesmo assim não ter DDD, porque meu modelo não fala a mesma “língua” do meu cliente ou do mundo real.
Isso eu entendi , agora o que me pergunto eh o seguinte se meu modelo não modela o mundo real, minhas classes acabam tendo um "que " de anemica visto que elas serao manipuladas por outras, o que deveria ser de responsabilidade delas.

Neste exemplo mesmo que você deu, estacionar eh uma responsabilidade do Carro , ou seja tendo uma vaga disponivel ele deve saber estacionar e não da classe Estacionável, o que faria do minha classe apenas um agrupamento de dados.
Então o que pergunto eh seguinte, sem DDD minhas classes não vão ter um “QI” alto sendo assim, irão acabar sendo anêmicas, então que alternativas teria e relação a DDD, para não deixar minhas classes tão “burras” assim?

Obrigado

pcalcado

Entendo o que você quer dizer mas acho que o problema é que você não está conseguindo distinguir o que é Orientação a Objetos e modelagem de domínio. Quem tem que estacionar é o carro… por quê? A única coisa que te diz isso é o domínio, não Orientação a Objetos. A classe do exemplo acima etá de acordo com o que se espera de um bom design OO (creio) mas não está de acordo com o domínio.

danielbussade

Ah táa acho que agora entendi. Então o simples fato de ter regras de negócio no Domain, não implica o uso do DDD ou seja minhas classes podem não ser anemicas, tendo varios metodos de negocio nela e mesmo assim eu nao usar DDD, ou seja eu posso usar um Domain Model Pattern sem usar DDD,mas nunca posso ter DDD sem ter um Domain Pattern certo?
Então eu poderia dizer que DDD está mais ligado a linguagem de negócios do que orientação a objetos em si??

Valeu

pcalcado

Isso.

danielbussade

Valeu philip pela ajuda!

Criado 18 de setembro de 2008
Ultima resposta 13 de out. de 2008
Respostas 74
Participantes 15