Desenvolvendo Sistemas OO Com Padrões de Negócio

From Fragmental Bliki

Artigo sobre o uso de POJOs e padrões de Domain Driven Design para modelar uma Camada de Negócios. Publicado na revista mundo Java número 17

Conteúdo

Trecho de Introdução

Comentários Comentados

POJOs garantem seu Estado?

Veja a thread no GUJ: http://www.guj.com.br/posts/list/33027.java

Primeira coisa gostaria de dar os parabéns ao Phillip pela matéria.

Mas como toda boa matéria ela também me deixou com algumas dúvidas:

- Um POJO precisa saber como ficar num estado consistente? Ou ele deve delegar isso a um outro objeto?

Somente exemplificando, em livros de O.O. é pregado que um objeto tem sempre que estar num estado válido e que o construtor dele 
deve se encarregar disso. Já pela convenção JavaBeans e até Pojos, vejo que existem brechas que *PODEm* deixar o objeto num estado 
inconsistente.

Pelo que entendi da matéria os objetos devem sempre estar num estado consistente e eles próprios devem se certificar de que isso 
aconteça.

Se sim, caso seja fornecido um argumento invalido para o construtor ou para um setter o melhor seria dar um throw numa 
IllegalArgumentException com uma mensagem bem animadora?

Pergunto isso, pois em vários lugares vi que POJOS praticamente não sabem o porquê vieram ao mundo, ja na matéria, pelo que entendi, 
os objetos sabem muito bem que espaço devem ocupar.

Desculpe se viajei muito e não entendi nada .

Oi,


>Primeira coisa gostaria de dar os parabéns ao Phillip pela matéria.

Obrigado

>- Um POJO precisa saber como ficar num estado consistente? Ou ele deve delegar isso a um outro objeto?
>
>Somente exemplificando, em livros de O.O. é pregado que um objeto tem sempre que estar num estado válido e que o construtor dele 
>deve se encarregar disso. Já pela convenção JavaBeans e até Pojos, vejo que existem brechas que *PODEm* deixar o objeto num estado 
>inconsistente.
>
>Pelo que entendi da matéria os objetos devem sempre estar num estado consistente e eles próprios devem se certificar de que isso 
>aconteça.
>...

Mais que POJOs, objetos de uma maneira geral devem garantir seu estado. Programar com contratos (DBC - Design by Contract) reforça isto através de algumas regras. Uma pequena introdução á DBC pode ser encontrado aqui:Contratos Nulos.

Note que mesmo numa linguagem totalmente integrada com DBC como Eiffel pdoe acontecer de um objeto não amnter consistência. O programador deve garantir a validade do estado do objeto. Linguagens como a citada Eiffel provêem recursos para facilitar esta verificação, em Java não tem muito jeito, é no braço mesmo.

>Pergunto isso, pois em vários lugares vi que POJOS praticamente não sabem o porquê vieram ao mundo, ja na matéria, pelo que entendi, 
>os objetos sabem muito bem que espaço devem ocupar.

O problema é que as pessoas costumam usar os chamados TO sem saber exatamente porque o fazem. Outro artigo que fala sobre isso pode ser encontrado aqui: Fantoches.


Repositórios e Invariantes

Olá "Shoes",

Trabalho no TCU em Brasília em sua Secretaria de Tecnologia. Minha função aqui é a definição e 
manutenção de uma arquitetura de referência para o desenvolvimento dos sistemas da casa.
Li seu excelente artigo na revista MundoJava. Por uma coincidência, também li o livro do Eric 
Evans e também o do Martin Fowler (PEAA - Patterns of Enterprise Application Archicteture). Estes 
livros foram realmente importantes para minha formação em OO.
Gostaria de começar uma discussão sobre algumas questões que surgiram quando tentei (estou 
tentando) implementar os conceitos dos livros na prática. São elas:
1. Existem regras de negócio que são difíceis de se implementar nos POJO´s e que não são métodos 
de Services. Por exemplo, em um objeto de negócio Beneficio, temos, entre outros atributos, 
dataInicio e dataFim. Para que uma instância seja válida a dataInicio deve ser imediatamente 
posterior a uma dataFim de uma outra instância. Onde esta regra ficaria localizada?
De forma geral, existem regras de negócio que precisam de acesso ao repositório para o seu  
cumprimento, o POJO pode acessar o repositório?
2. No caso de utilização dos POJOs de negócio para transporte de dados para a camada de 
apresentação, de modo a eliminar os DTOs ou TOs como fica a possibilidade da camada de 
apresentação chamar métodos de negócio? Ainda sobre este assunto, como fica a carga de valores dos 
POJOs, já que existe o lazy load, ou seja, a conexão deveria se fechada após a apresentação das 
informações. Vocês estão utilizando os filtros (web.xml) para isso?
3. Em relação ao Repositório. Existe uma classe repositório para cada POJO de negócio ou um  
repositório para um "conceito" (POJO principal e POJOs dependentes), algo como um repositório para 
cada Aggregate. Qual é o mais indicado?
4. Em seu artigo você coloca a possibilidade de chamadas ao repositório de um POJO de negócio. 
Como o repositório na verdade é uma interface para o DAO, como ficaria a criação desta interface  
de dentro do POJO de negócio. Vocês estão usando uma fábrica para a criação do repositório?
5. No livro do Eric Evans existe o conceito de Aggregates. Você não acha que recuperar todos os 
objetos de negócio pela raiz da agregação não é pouco "performático"?
6. Quanto a validação dos atributos de uma instância. O livro Hibernate in Action, só para citar 
um exemplo, recomenda que exista um método de negócio ou construtor que recebe todas os atributos 
do POJO e desta forma realiza as validações e regras de negócio envolvidas durante o processo de 
construção. Neste cenário, como fica a validação na alteração dos atributos, já que os métodos 
set, neste caso, são privados;
Bem, são algumas questões que tenho de imediato. Acho interessante abrir uma discussão a respeito 
do assunto. O que você acha?
Grande abraço!
Eldon Coutinho
TCU/SETEC/DISIN/SEQUAS



Oi, Eldon,

Antes de mais nada desculpa na demora, este mês não foi fácil...

On 5/19/06, Eldon Teixeira Coutinho  wrote:
> 1. Existem regras de negócio que são difíceis de se implementar nos POJO´s e que não são métodos 
de Services. Por exemplo, em um objeto de negócio Beneficio, temos, entre outros atributos, d
dataInicio e dataFim. Para que uma instância seja válida a dataInicio deve ser imediatamente 
posterior a uma dataFim de uma outra instância. Onde esta regra ficaria localizada?

Isso é uma invariante. Aproveitando que você já tem o costume de ler bons livros tente conseguir estes: Object-Oriented Software Construction - Bertrand Meyer Fundamentals of Object-Oriented Design Using UML - Meilir Page-Jones

Eu escrevi um textinho introdutório sobre invariantes e contratos aqui:

http://fragmental.com.br/wiki/index.php?title=Contratos_Nulos


> De forma geral, existem regras de negócio que precisam de acesso ao repositório para o seu 
cumprimento, o POJO pode acessar o repositório?

Sim. É importante semrpe notar que um Repositório é um objeto de negócio, utilizando DIP (mencionado no artigo) você consegue fazer um DAO (se o utilizar) implementando um repositório ´ser manipulado por objetos de domínio sem criar acoplamento/dependência entre negócio e infra-estrutura. Nesta discussão do GUJ falamos um pouco sobre isso:

http://www.guj.com.br/posts/list/33027.java

> 2. No caso de utilização dos POJOs de negócio para transporte de dados para a camada de 
apresentação, de modo a eliminar os DTOs ou TOs como fica a possibilidade da camada de 
apresentação chamar métodos de negócio? Ainda sobre este assunto, como fica a carga de valores dos 
POJOs, já que existe o lazy load, ou seja, a conexão deveria se fechada após a apresentação das 
informações. Vocês estão utilizando os filtros (web.xml) para isso?

Sobre métodos de negócio, é válido para uma Camada de Apresentação chamar métodos nos objetos que ela obteve legitimamente. Imagine por exemplo que temos um Service que retorna um objeto de negócio A.

interface Service{

public A obtemUm(){...}

}

E que A tenha um método de negócio qualquer:

class A{

public void metodoDeNegocio(){...}
public String getQualquerCoisa(){...}

}

Segundo os requisitos, a interface deve msotrar o conteúdo do objeto A na tela mas deve obtêr o A via Service, nunca pode instanciar o objeto.

Isso permite que a Interface chame o método de negócios em A, o que pode não ser desejado (em times grandes este tipo de confusão costuma causar um inferno de manutenção). O que fazer então?

A forma mais simples é adotar que a interface não pode nunca chamar métodos com efeitos colaterais, o que os limitaria a métodos tipo 'get' seguindo o padrão de nomenclatura de JavaBeans. Isto pode ser reforçado usando uma ferramenta de verificação como o macker (http://innig.net/macker/ - muito interessante, vale uma olhada...).

Outra abordagem, mais drástica (e eficaz em equipes indisciplinadas), é utilizar interfaces. Mudando um pouco, criamos uma interface APublico (nome horrível proposital):

interface APublico{

String getQualquerCoisa();

}

E fazemos A implementá-la: class A implements APublico{

public void metodoDeNegocio(){...}
public String getQualquerCoisa(){...}

}

Agora nosso Service pode retornar a interface apenas: interface Service{

public APublico obtemUm(){...}

}

Eliminando o problema. É drástico mas pode ser a única alternativa algumas vezes.

Quanto ao Lazy Loading sim, o padrão 'Open Session in View' é utilizado quando não existe um framework que dê suporte à Hibernate.

> 3. Em relação ao Repositório. Existe uma classe repositório para cada POJO de negócio ou um 
repositório para um "conceito" (POJO principal e POJOs dependentes), algo como um repositório para 
cada Aggregate. Qual é o mais indicado?

Não existe uma respsota fácil para essa pergunta, lembre-se sempre de criar classes e abstrações que agreguem valor. Você precisa de um Repositório de A? Sim, preciso porque preciso fazer consultas, listar, etc. Você precisa de um Repositório para B? Não porque eu nunca preciso lsitar nem fazer buscas por B. Uma arquitetura incremental e flexível é muito interessante.

> 4. Em seu artigo você coloca a possibilidade de chamadas ao repositório de um POJO de negócio. 
Como o repositório na verdade é uma interface para o DAO, como ficaria a criação desta interface 
de dentro do POJO de negócio. Vocês estão usando uma fábrica para a criação do repositório?

Sem um container apropriado eu utilizo Fábricas mas geralmente a melhor saída é utilizar um container de Dependency Injection como Spring, PicoContainer ou EJB3.

> 5. No livro do Eric Evans existe o conceito de Aggregates. Você não acha que recuperar todos os 
objetos de negócio pela raiz da agregação não é pouco "performático"?

Acho que depende do caso. Eu excluí aggregates do artigo para não confundir demais, mas na maioria dos casos que tenho visto no meu dia-a-dia um bom framework O-R como o Hibernate acaba aliviando bastante o processo. Geralmente no máximo eu rpeciso otimizar uma operação num repositório utilizando uma query em HQL mais otimizada.

Claro que relatórios são uma exceção. Relatórios realmente pesados devem ser implementados em apralelo com o Domain Model, utilizando tudo que o Banco pode proporcionar. È retrabalho, mas por enquanto não tem muito jeito...

> 6. Quanto a validação dos atributos de uma instância. O livro Hibernate in Action, só para citar 
um exemplo, recomenda que exista um método de negócio ou construtor que recebe todas os atributos 
do POJO e desta forma realiza as validações e regras de negócio envolvidas durante o processo de 
construção. Neste cenário, como fica a validação na alteração dos atributos, já que os métodos 
set, neste caso, são privados;

Novamente é uma questão de invariante. Um construtor deve garantir a invariante do objeto e os métodos também, além de suas pré e pós condições. Dê uma olhada na bibliografia que te passei.

> Bem, são algumas questões que tenho de imediato. Acho interessante abrir uma discussão a 
respeito do assunto. O que você acha?

Acho ótimo e se quiser a participação de mais interessados sugiro que coloque no http://www.guj.com.br

[]s

Referências

Revista Mundo Java

Domain Driven Design Quickly

Domain Driven Design

Maratona4Java2005: Arquitetura de Camadas em Java™ Enterprise Edition - Palestra que Originou a Matéria

Ferramentas pessoais