Injeção de Dependência em Domain Model (ServiceLayer+DomainModel+Repository)

98 respostas
A

Muito tem se falado no grupo sobre DDD, Repository, Domain Model, etc.
Contudo estou tendo muita dificuldade para tornar estes conceitos práticos, utilizando JavaEE.

Por exemplo:
Quem orquestra os objetos de domínio é uma ServiceLayer, no meu caso um Stateful ou Stateless do Seam.

Meu DomainModel é constituído de Entitys(Objetos com identidade) com lógicas de negócio além obviamente de seus atributos :arrow: no meu caso ele é uma classe JPA anotada com @Entity.

@Entity
@Name("user")
    public class User implements Serializable {
        ...
     }

Na maioria das vezes as lógicas neles contidas precisam de um acesso a banco, então eles levam um (ou varios) repository consigo… como atributo da classe ou dentro do próprio método.

@Entity
@Name("user")
public class User implements Serializable {
	@Transient	
	RepositoryUser repositoryUser;
	
	...
}

Então começam alguns problemas. Meu Entity deveria receber injeção deste repository… porém como o Entity é carregado por JPA, eu não consigo injetar nenhum objeto nem por @In do Seam nem mesmo por Spring.

@Entity
@Name("user")
public class User implements Serializable {
	
	//nao funciona a Injecao pq eh em entity
	@In
	@Transient	
	RepositoryUser repositoryUser;  
	
	...
}

Uma solução seria fazer com que a ServiceLayer enviasse por “set” um repository para o Entity. Mas o código do Service iria ficar poluido, tendo um repository que ele nem faz uso, só instancia para o entity. Toda vez que fosse utilizar uma lógica de negócio do entity que utiliza acesso a banco, teria que minha outra camada setar o repository pra ele.

/*A ServiceLayer*/
@Stateless
@Name("authenticator")
public class AuthenticatorService implements Authenticator{

	@In(create=true) 
	@Out 
	User user;

	@In
	private RepositoryUser repositoryuser;

	public boolean authenticate(){

	   //setando porcamente o repositorio	
           user.setRepository(repositoryuser);
           user.authByNameAndPass();	
           ...

         }				
}

Qual seria uma outra solução que poderia ser adotada? Mesmo com o advento do JavaEE 5 com tantos frameworks de D.I. vou ter que utilizar ServiceLocator para localizar Repository nos entitys?

[]´s

98 Respostas

E

… porém como o Entity é carregado por JPA, eu não consigo injetar nenhum objeto nem por @In do Seam nem mesmo por Spring.
Com Spring 2.0 vc pode injetar dependências em objetos criados fora do conteiner, vc tem até mesmo duas opções, por AOP ou por chamada explicita do BeanFactory, Urubatan corrija-me se estiver errado :wink:

A

Isso é mesmo possível? Impressionante!
Bom, acabei descobrindo tbm que consigo acessar qualquer componente do Seam através de Componente.getInstance(“nomeDoComponente”). Mesmo abstraindo este acesso nos objetos de entidade, não me parece uma coisa muito elegante, contudo ao que parece utilizando o Seam não tenho outra saida.

Ou Tenho?

P

No Hibernate (mesmo usando JPA) voce pode adicionar um Interceptor que toda vez que um bean sai do entity manager/session, o setXXXRepository é invocado.

F

Paulo,

Mas esses interceptors fazem parte da spec de JPA? Porque se não fizer, qual o sentido de utilizar JPA se o sistema só irá funcionar com a implementação do hibernate?

[]s

Ferry

F

Me falta tempo, mas eu tô tentando resolver justamente esses problemas no: http://sourceforge.net/projects/hinjector/

A

Bom, fiz algo que ficou bem interessante:

  • Um Aspecto que intercepta a instanciação de todas as classes do meu pacote com classes de entidades, injetando neste momento as dependências que forem necessárias. O legal é que fica completamente transparente para o desenvolvedor.

Com isso tanto faz se a instanciação for através de “new”, “jpa” ou qualquer outro framework, a injeção vai funcionar do mesmo jeito.

Veja o código usando AspectJ:

public aspect InjectEntity{

   //pointcut criado para interceptar na instanciacao de uma classe   
  // br.com.siq.entity é o pacote onde estao minhas entidades
  pointcut inject() : initialization(public br.com.siq.entity.*.new ());

 //execucao do aspecto apos concluida (advice after) a instanciacao da classe
       after():inject(){
 //obtendo o objeto em questao (joinpoint)
               Object obj = thisJoinPoint.getThis();
              
//variaveis que injetarao em um determinado atributo
               String valueOfContextVariable = null;
               Boolean createContextVariable=false;


//Procurando anotacao de injecao na classe, no caso do Seam o "In.class"
               for(Field field:obj.getClass().getDeclaredFields()){
                       if(field.isAnnotationPresent(In.class)){
                               In in = field.getAnnotation(In.class);

//se a anotacao nao tem o atributo value setado, utilizar o nome do campo
                               if(in.value().equals("")){
                                       valueOfContextVariable = field.getName();
//caso contrario utilizar o atributo value
                               }else{
                                       valueOfContextVariable = in.value();
                               }

 //verificar se esta anotado como create
                               if(in.create())
                                       createContextVariable = true;
        
//tornando acessivel o atributo caso ele seja private, para ser possivel fazer a injecao 
                               field.setAccessible(true);

                               try {
//injetando no atributo, como uso  JBossSeam obtenho a referencia atraves do
//Component.getInstance() , mas poderia ser qualquer coisa,
//como um applicationContext do Spring
                                       field.set(obj, Component.getInstance(valueOfContextVariable, createContextVariable));
                               } catch (Exception e) {
//escrever  aqui rotina de excecao
                               }
                       }
               }
       }

Na entidade, basta anotar:

@In
 private Repository repository;

O Código do Aspecto pode ser melhorado, como incluir suporte para injecao pelo método “set”, mas esse foi apenas um esboço de como pode ser feito.

[]'s

A

Hmmm… lógica de acesso a banco nos Entitys… estranho isso…

A

Lógica de acesso a banco? Onde?

A entidade tem acesso ao “repositório”, que de nada tem haver com “Lógica de acesso ao banco”. O repositório tem “intimidade” com a lógica de negócio, faz parte dela, nada mais justo que estar no modelo de domínio.

A

Mas concordo que fui infeliz na minha afirmação do primeiro post " precisam de um acesso a banco", o q queria dizer foi:
precisam de um acesso ao repositório”.

A

Lezinho:
Mas concordo que fui infeliz na minha afirmação do primeiro post " precisam de um acesso a banco", o q queria dizer foi:
precisam de um acesso ao repositório”.

Continua estranho, Entitys dependendo de Repositories…

A

A dependencia é injetada, entao nao vejo problema. O fato de ser um repository dentro de um entity tbm não encontro nada de errado, ambos fazem parte da lógica de negócio… mais uma vez… REPOSITÓRIO É NEGÓCIO…

P

Correto. A falta de entendimento das pessoas sobre Repositories x DAOs causa este tipo de confusão mas basta ler a bibliografia para entender que um Repositório é parte do domínio e por isso não há qualquer problemas em relacionar entidades à ele.

A

A questão é a forma como ela é injetada (lembre-se do princípio do KIS). :wink:

Os Repositories - e os DAOs dos quais eles dependem, já que vc prefere assim - dependem do Service e não dos Entitys.

Dê um olhada no caveatemptor (aplicação de referência para uso de Hibernate).

A

Taz, vc pde injetar por “set” sendo enviado pelo Service, como mostrei no primeiro post, gerando o problema que tbm já mostrei.

O que fiz, via annotation, faz a injeção pelo SEAM (por debaixo dos panos do aspecto), não a nada de errado nisso… a dependencia foi invertida.

Você não esta sendo claro, ou não esta entendendo.

A

Esqueceu de levantar a possibilidade de que vc não esteja entendendo. Dê uma olhada na aplicação de referência que te falei e nos exemplos de JBoss Seam (que não são poucos). Depois discutimos…

A

De fato não olhei estes codigos, assim como também não sei pq deveria. Não tenho dúvidas de como usar “repository”, e sim “tinha” de como injeta-los no load de algum framework de persistencia (o que foi resolvido via Aspect).

Portanto Taz, dispenso a discussão, o foco desta thread não foi este. Quem achou estranho usar repository em entity foi você (o que o Shoes desmistificou muito bem).

Se você esta com dificuldade de entender repositories em entities, abra uma thread sobre isso.

Boa Sorte.

A

Belez…

“O pior cego é aquele que não quer ver” (ditado popular)

Abraço e boa sorte (vc vai precisar se não estudar os exemplos) :wink:

A

Taz, eu sei como o Hibernate trabalha com interceptors, tbm sei como delegar isso para service.

Contudo não quero dependencia dos interceptors Hibernate (eu posso instanciar minha entidade atraves de “new”, nesta caso o Interceptor do hibernate não me ajudaria) e tbm não quero associar metodos de negocios do repositorio na ServiceLayer, mas sim na minha entidade de domínio. Eu não preciso ler fontes dos exemplos do Hibernate para isso, sei o que quero ou não fazer, assim como não sei de nenhuma literatura mencionando que o que fiz esta quebrando algum conceito OO.

“O pior orador é aquele que se pronuncia sem necessidade alguma” :stuck_out_tongue:

F

Taz:

Belez…

“O pior cego é aquele que não quer ver” (ditado popular)

Abraço e boa sorte (vc vai precisar se não estudar os exemplos) :wink:

O problema é que as duvidas dele nao sao referentes ao Sean mas sim se tem como aplicar DDD com o Sean. Ai faz sentido ter repositorios dentro dos entities (entities do DDD).

]['s

A

Você entendeu Fabio, é isso mesmo a duvida que tinha quando criei o tópico.

A

fabio.patricio:
Taz:

Belez…

“O pior cego é aquele que não quer ver” (ditado popular)

Abraço e boa sorte (vc vai precisar se não estudar os exemplos) :wink:

O problema é que as duvidas dele nao sao referentes ao Sean mas sim se tem como aplicar DDD com o Sean. Ai faz sentido ter repositorios dentro dos entities (entities do DDD).

]['s

Ok, vamos falar em DDD.

Seguem trechos do capítulo “Repositories” do Livro do Eric Evans (Domain Driven Design Complexity In Software):

Onde ele fala que são os Entitys que acessam os malditos Repositories!? Todos os diagramas que ele desenha no livro mostram os “Clients” acessando os REPOSITORIES.

Evans:
Clients request objects from the REPOSITORY using query methods that select objects based on
criteria specified by the client, typically the value of certain attributes. The REPOSITORY retrieves
the requested object, encapsulating the machinery of database queries and metadata mapping.

(…)

Provide REPOSITORIES only for AGGREGATE roots
that actually need direct access. Keep the client focused on the model, delegating all
object storage and access to the REPOSITORIES.

Sabe o que são AGGREGATES!? Procure no mesmo livro que ele te explica.

Traduzindo: Vc não precisa criar um repositório para cada classe.

Traduzindo: Como ficaria o controle da transação se ele não fosse feito pelo cliente!?

E caso vc ainda acredite que esteja subvertendo seu modelo de domínio, o que é muito difícil quando se faz o uso correto do Hibernate…

Evans:
In general, don’t fight your frameworks. Seek ways to keep the fundamentals of domain-driven
design and let go of the specifics when the framework is antagonistic. Look for affinities between
the concepts of domain-driven design and the concepts in the framework

Por esses e outros motivos, repito…

P

Capacidade de abstração, ou neste caso a falta dela, é uma coisa muito interessante. É fácil perceber quando algum trecho foi pego sem entendimento do contexto (especialmente quando o contexto é composto por 500+ páginas de texto denso) pela forma como alguém se atem à trechos que sozinhos não têm qualquer significado.

Entity é um padrão, página 89. Repository é um padrão, página 147. Aggregate também, página 125. Não existe um padrão ‘client’. por que será? Porque o cliente de algo é simplesmente o que precisa de acesso a este, no caso específico cliente pode ser um Entity. Claro que poderiam haver diagramas mostrando cada uma das possibilidades, entity x repository, service x repository, specification x xrepository… só que haveriam algumas dezenas de páginas a mais a toa.

O texto não traz uma definição de ‘cliente’, talvez porque… uhm… seja bem obvio quando se tenta… uhm… ler o dito cujo. Por exemplo quando factories são definidas temos:

ou seja: o cliente pode ser Camada de Aplicação, mas não necessariamente.

Mas para entender mais profundamente o texto de Evans (coisa que só é necessária quando você está estudando DDD em um nível mais profundo ou quando precisa refutar uma desinformação, que é o caso) é necessário pesquisar no seu antecessor, amplamente referenciado por este: Fowler no seu POEAA. E uma das coisas mais legais do Fowler é que ele consegue responder este tipo de dúvida com um exemplo claro, como este retirado do livro (pagina 325, no capítulo sobre Repository):

public class Person { 
   public List dependents() {
      Repository repository = Registry.personRepository();
      Criteria criteria = new Criteria();
      criteria.equal(Person.BENEFACTOR, this);
      return repository.matching(criteria);
   }
}

Veja que curioso: uma entidade referenciando a seu próprio Repositório. Onde mesmo que havia visto isso? E veja só, ainda usa Registry.

F

Uma coisa que vem ficando cada vez mais frequente no GUJ é certos usuários acharem que só eles leram os livros/artigos/papers/coloque aqui sua fonte preferida. Essa resposta do Taz fazendo como se ele fosse o unico e ter lido esse livro me fez procurar o e-mail da primeira vez que eu ouvi falar dessa obra do Evans. Quem me falou disso a primeira vez foi o Marcos Pereira (usuario aqui do GUJ tb) la em 2004 acredito que pouco tempo depois do livro ter sido lancado.

Ps.: Desculpem o desabafo, mas esse tipo de coisa no GUJ vem se tornando frequente e enche um pouco o saco.

]['s

P

Eu tenho quase certeza que a pimeira referência que vi foi aqui no GUJ pelo cv (e vindod e quem vem não estranharia se fosse a primeira vez que isso apareceu num site em português :P). Infelizmente o grande apagamento dos posts de uns dois anos atrás levou a mensagem para o limbo.

A

Não deveria haver motivos para mágoas. Eu não disse que só eu havia lido… :wink:

Quanto ao outro rapaz, percebo certa rispidez em sua réplica, o que já é um comportamento histórico que pode ser ocasionado por uma certa insegurança… Por outro lado, o mesmo reclama de lidar com pessoas que não se atêm à bibliografias. Quando encontra alguém que lê, deveria ter uma postura mais aberta…

Uma pena que ele não percebe que o Hibernate converte aquilo que ele escreveu:

public class Person { public List dependents() { Repository repository = Registry.personRepository(); Criteria criteria = new Criteria(); criteria.equal(Person.BENEFACTOR, this); return repository.matching(criteria); } }

por isso (obviamente em um contexto “managed”)…

public class Person { public List getDependents() { return dependents; } }

Ou seja, o Hibernate contém o próprio Repositorio em si…

Lembrem-se:

Evans:
In general, don’t fight your frameworks. Seek ways to keep the fundamentals of domain-driven
design and let go of the specifics when the framework is antagonistic. Look for affinities between
the concepts of domain-driven design and the concepts in the framework

P

Após aquele post todo cheio de referências e autoridade completamente furado (e pedir ‘abertura’ para engolir sua presunção) colar um trecho de um livro que já mostrou que não entende (ou será ‘leu’?) é muita cara de pau.

Quem quiser entender melhor sobre Hibernate & Repositories é legal olhar a lista de DDD, o que a pessoa escreveu aí em cima (pra variar) não condiz com a realidade da técnica. O trecho que ele postou substitui Registry por algum meio automático (talvez IoC) de injeção, mas a tecnologia utilizada não tem nada a ver com a aplicação ou não do padrão. Repositories podem ser criados para lidar diretamente com Hibernate, JDBC, search engines ou não, provavelmente delegando seu trabalho à DAOs e DataMappers em geral. Mas nem adianta tentar refutar com argumentos ou até mesmo referências bibliográficas, como se pôde perceber. O bichinho não anda, simples assim.

O outro rapaz aqui (que você já chamou de desonesto neste fórum só por birra) não precisa ter insegurança, pelo menos não quanto à você. Seu histórico aqui já o condena (inclusive profissionalmente, mas tudo bem, você não revela seu nome exatamente para não te reconhecerem, certo?), isso sem contar o portal Java…

A

Apenas respondendo a sua pergunta Taz, sim eu conheço o que é Aggregate, assim como tbm sei que Repository não é um para cada classe. Agora o que não sei mesmo é o que isso tem haver com o que tenho postado ou oq já rolou neste tópico.

Alguma vez afirmei que iria construir repositorios a torto direito para cada entidade minha?

E que porcaria que você andou digitando sobre “Clients”?

Quanto aos “clients”, apenas completando o que Shoes já disse… vale comentar tbm que além de usar uma entidade (People), no livro de Fowler (POEAA) ele tbm usa duas classes “Strategy” com um Repository, o que nos mostra a flexibilidade do padrão.

Mas é claro, não espero que Taz concorde com estas afirmações… Já discordou de mim, do Fabio Kung, do Sergio, do Phillip, do fabio.patricio, não duvido que ele discorde de Fowler tbm…

P

Só é bom focarmos que discordar é ótimo. Eu discordo do Fowler bastante em DSLs, por exemplo. O ponto é ter um mínimo de respeito pelos outros e darmos base às nossas discordâncias, seja usando uma bibliografia ou argumentando. Pela minha experiência muitas discordâncias contra conceitos são na verdade falta de entendimento (desconfio que meu ponto de divergência com a coisa das DSLs seja exatamente porque ainda não as compreendo bem) e uma conversa e/ou debate ético e profissional são proveitosos para todos.

O que não dá é atirar pedra em todo mundo sem sequer entender o que fala.

A

O problema Phillip é quando o “discordar” parece ser mais importante do que “compreender”. Só depois de compreender um problema podemos “discordar” de alguma solução para tal, o que não ocorreu por aqui.

PS: Você não apóia o uso de DSLs ? Eu particularmente detestava, até conhecer o Drools e como fazer regras de segurança com ele (o ruim não eram as DSLs e sim como cria-las , IMHO).

P

Lezinho:

PS: Você não apóia o uso de DSLs ? Eu particularmente detestava, até conhecer o Drools e como fazer regras de segurança com ele (o ruim não eram as DSLs e sim como cria-las , IMHO).

Sim, apóio e minha linha de estudo atual é exatamente sobre os conceitos envolvidos em LOP e DSLs: http://fragmental.tw

Eu discordo de alguns conceitos do Fowler, por exemplo o conceito dele de LOP==DSL

A

Ataques pessoais!? Lamentável um moderador adotar essa postura.

Magina, acho que vc havia cometido um engano ao falar que havia bloqueado meus e-mails, apesar de nunca ter te enviado qualquer coisa. Não precisa forçar neh!?

Quanto à discussão, cada um faz suas escolhas e assume as consequências.

Assunto encerrado.

R

Só uma dúvida Lezinho…

Estou usando Seam e EJB 3 e não tenho tido a necessidade de injetar Repositories nos Entities e sim alguns Services. (tenho um exemplo para aplicação Desktop em http://www.aspercom.com.br/bitshop). Como são poucos casos, criei um Factoryzinho para injetar isso (se fosse muitos recorreria a AOP como vc fez).

Quais situações você está sentindo a necessidade de injetar repositories? Seria para navegar numa associação derivada? Ou para “simular” uma associação n-aria?

Abraços!

A

Olá Rodrigo …

O repositório na entidade deve executar métodos de negócio a fim de recuperar elementos relevantes ao comportamento desta Entity, não precisa necessariamente ter uma ordem de relacionamento com a entidade.

Agora uma Service, é um padrão que encapsula seu Domain MOdel. Ele antecede as Entidades e controla o fluxo das execuções. O comportamento da entidade (seus métodos de negócio) possui lógica, um service apenas opera como uma fachada. Sendo assim, uma entidade não deve invocar um service, e sim ser invocada por um.

Para você visualizar o modelo de camadas proposto por Fowler e descrito no POEEA, veja uma breve descrição e um diagrama que aponta isso aqui:

http://martinfowler.com/eaaCatalog/serviceLayer.html

PS: Veja que “DataSource Layer”, que deve ser abstraída pelo Repository, esta encapsulada no Domain.

[]´s

B

Veja,

Digamos que tenho repositórios de entidades diferentes (PessoaRepository e ContaRepository, por exemplo). Aih desejo que um mesmo DAO genérico implemente esses repositórios ( ao menos nos métodos que equivalem a operações CRUD ).

Que estratégia devo tomar para conseguir isso? Dá pra usar interfaces e spring? Devo usar fachada? Como se daria isso?

A

rodrigoy:
Só uma dúvida Lezinho…

Estou usando Seam e EJB 3 e não tenho tido a necessidade de injetar Repositories nos Entities e sim alguns Services. (tenho um exemplo para aplicação Desktop em http://www.aspercom.com.br/bitshop). Como são poucos casos, criei um Factoryzinho para injetar isso (se fosse muitos recorreria a AOP como vc fez).

Quais situações você está sentindo a necessidade de injetar repositories? Seria para navegar numa associação derivada? Ou para “simular” uma associação n-aria?

Abraços!

Essa história de Repositories tá confundindo a cabeça do pessoal… :wink:

B

É verdade. No meu caso, como estou acostumado a utilizar um DAO genérico com hibernate e somente criar DAO’s específicos quando desejo uma consulta mais específica, estou pensando como se daria para as interfaces de Repositório do DomainModel serem implementadas pelo DAO genérico (ao menos nas funcionalidades que equivalem a CRUD) e só serem implementadas por DAO’s específicos em caso de consultas específicas.

Como poderia fazer isso?

S
BiraBoy:
Como poderia fazer isso?

Herança?

Repository
public void store(Object obj){
   dao.save(obj);
}

ContaRepository extends Repository
PessoRepository extends Repository
B

Beleza, e como faço para desacoplar o repositório da implementação com DAO’s?

A

A estratégia que eu uso é realmente utilizar Strategy :wink:

Eu tenho uma interface DAO expondo métodos como do tipo (exemplificando):

  • read(String stringQuery);
  • read(String stringQuery, Object[] params);
  • read(String stringQuery, Map<String, Object> params);
  • getAll(Class clazz);
  • getById(Object id);
  • save(Object obj);
  • delete(Object obj);
    (etc)

A implementação do DAO faz uso de JPA, Hibernate, Prevayler, ou seja lá o que for …

Tenho interfaces Repositories do tipo (RepositoryUser):

  • findUserByNameAndPassword(String name, String password);
  • addUsersWithValidRegisters(List<User> users);
    (etc)

A implementação do repositório possui como atributo minha interface DAO definida anteriormente, e utilizo D.I.P. (no momento Seam) da implementação DAO desejada.

Quando o repositório precisa realizar acesso ao framework de persistencia (ou outro recurso de persistencia) ele faz o uso do seu Dao injetado como Strategy.

Assim o DAO continua com seu encapsulamento de acesso a dados, o repositório continua com a lógica, e a leitura do programa fica coesa.

A

… o DAO esta desacoplado.

A

Prefira composição a herança:

http://javaboutique.internet.com/tutorials/Inherit_Compose/


S

Prefira composição a herança:

http://javaboutique.internet.com/tutorials/Inherit_Compose/



Eu não concordo que isso se aplique aqui, mas se vc tem uma ideia de como composição pode resolver o problema do reaproveitamento de codigo que o BiraBoy explicou, venha ela …

A

… composição resolve neste caso, conforme descrevi a uns 4 posts acima.

S
Lezinho:
... composição resolve neste caso, conforme descrevi a uns 4 posts acima.

???

Usar Strategy não é composição, é Strategy. Ter um objeto DAO injetado não resolve o problema exposto que é : não reimplementar funcções simples de CRUD para cada Repository. Então vc faria

abstract class Repository {
 
    protected DAO dao = DAOFactory.getDAO();


    public void store (Object obj){
         dao.save(obj);
    }

    public void remove(Object obj){
         dao.delete(obj);
    }

}

//e depois 

class ClientRepository extends Repository {

         public List&lt;Client&gt; clientesComPagamentoEmAtrazo(Date date){
                   // monta uma query e envia ao dao
                   // o dao é o mesmo que no pai. 
                   return dao.list (Client.class,query);
         }

       // não é necessário implementar nem remove, nem save, nem nada que  exista no Repository  pai.
}

Como ClientRepository poderia reaproveitar o codigo de repository sem herança ?
Bom poderia ser assim (com composição)

Repository é uma interface

class GenericRepository implements Repository {

     private DAO dao = DAOFactory.getDAO();  

         public &lt;T&gt; List&lt;T&gt; list(Class&lt;T&gt; c , Query query ){
                 return dao.list(c,query);
         }

   public void store (Object obj){
         dao.save(obj);
    }

    public void remove(Object obj){
         dao.delete(obj);
    }
}

class ClientRepository  implements Repository {
 
         private final Repository generico = new GenericRepository();

         public List&lt;Client&gt; clientesComPagamentoEmAtrazo(Date date){
                   // monta uma query e envia ao dao
                   // o dao é o mesmo que no pai. 
                   return generico.list(Client.class,query);
         }

      // repetição dos métodos da interfac Repository, que é exactemtne
// o que não se quer fazer
   public void store (Object obj){
         generico.store (obj);
    }

    public void remove(Object obj){
         generico.remove(obj);
    }

}

Qual é a vantagem ? Herança não é mais simples ?
Afinal ClientRepository É-UM Repository e mais do que isso ele SÓ-PODE-SER-UM reposiotry, que é a condição para que Repository seja uma classe abstract e ClientRepository a herde. Se Repository é uma interface eu poderia fazer

XPTO extends HashMap implements Repository

que não faz nenhum sentido. Então, não vejo como composição se encaixe melhor do que herança.

A

BiraBoy:
É verdade. No meu caso, como estou acostumado a utilizar um DAO genérico com hibernate e somente criar DAO’s específicos quando desejo uma consulta mais específica, estou pensando como se daria para as interfaces de Repositório do DomainModel serem implementadas pelo DAO genérico (ao menos nas funcionalidades que equivalem a CRUD) e só serem implementadas por DAO’s específicos em caso de consultas específicas.

Como poderia fazer isso?

Eu tb uso DAOs genéricos, do jeito que os caras da Hibernate recomendam. Quando preciso de uma consulta mais específica, eu coloco no ObjetoDeDominioDAO (que extende a GenericDAO).

Nunca precisei usar Repositories (pelo menos classes com o nome ObjetoDeDominioRepository) e consigo ter um modelo arquitetural bastante enxuto com o uso dos recursos do Hibernate.

A

Sergio, não é um erro você utilizar herança caso o controle do código esta em sua mão. O perigo é quando você tem uma grande equipe e decide usar componentes com base em sua implementação e o resto do desenvolvimento necessita herdar de seu componente sem a garantia que a implementação dos métodos ganhos lhe satisfazem

O repositório é específico da regra do domínio, assim como sua persistência.
Não existe garantia que o RepositórioUsuario utilize o mesmo DAO para persistência que o RepositórioFornecedor (isso pq sabemos da famosa afirmação, Repository é negócio, DAO é serviço de persistência). Ao afirmar que os DAOs podem ser diferentes, não apenas afirmo que um pode usar JDBC e outro JPA, mas principalmente que um pode persistir no Servidor X Oracle e outro no servidor Y MySql. Herdar a forma de que um repositório faz acesso a dados é engessar a abstração Repository (a não ser que você tenha garantias da forma de persitencia, incluindo a localização física).

Então alguém pode dizer: “Simples, sobreescrevo o método CRUD se necessário”. Se pensar assim, você tem conhecimento dos detalhes da implementação da classe pai (caso contrário você não teria métrica para tomar tal decisão). Obrigar este tipo de conhecimento, é justamente o que condena os links que postei.

Outra situação é de que um userRepository.store() pode fazer muitas outras coisas do que simplesmente invocar um dao.save. Aqui tbm poderia ser dado overhide e depois invocado um super.store, contudo qual é a garantia que o método store do “pai” não anule as alterações do filho?

No exemplo que você postou, eu não utilizo "Repository generico = new GenericRepository(); " nos Repositories como objeto composto, e sim a interface DAO como atributo. Isso permite que injete diferentes DAOs dependendo que Repository estou e garanta a forma como vou acessar os dados.

E como eu não posso utilizar de composição + interface para implementar Strategy?

Utilizo Strategy para resolver meu acesso a dados do repository. O repositorio não sabe como fazer isso, quem sabe é seu atributo DAO (que é a interface “estratégica”).

A

Ah, claro, lembre-se tbm que você não deve ter um repository para cada Entidade, e sim apenas para Agreggate roots. Sendo assim o repositório tem que fazer CRUD tbm nos agregados. Neste caso a herança tbm não ajudaria.

Quando eu mencionei que tinha respondido em 4 mensagens anteriores, com o uso de composição, não queria dizer que escrevi algo genérico, pq em minha opinião isso não casa com tudo que estamos discutindo com o que o Repository deve prover. Apenas descrevi a maneira de desacoplar o dao do repository.

R

Lezinho:
Olá Rodrigo …

Agora uma Service, é um padrão que encapsula seu Domain MOdel. Ele antecede as Entidades e controla o fluxo das execuções. O comportamento da entidade (seus métodos de negócio) possui lógica, um service apenas opera como uma fachada. Sendo assim, uma entidade não deve invocar um service, e sim ser invocada por um.

Lezinho, não confunda o Service Layer do Fowler com o Service do Evans. É uma confusão bem comum. O Service do Evans é um elemento do domínio que encapsula comportamentos que você não consegue alocar naturalmente a um entity. O Evans chama Service Layer de Application Layer (não sei porque esses caras são tão amigos e não usam a mesma terminologia). Service != Façade.

Eu injeto Services nos Entities para encapsular processamentos complexos ou que podem variar (Strategy).

S

Lezinho:
Sergio, não é um erro você utilizar herança caso o controle do código esta em sua mão. O perigo é quando você tem uma grande equipe e decide usar componentes com base em sua implementação e o resto do desenvolvimento necessita herdar de seu componente sem a garantia que a implementação dos métodos ganhos lhe satisfazem

Isso pode até ser verdade. Mas se tivesse medo disso não usaria as classes abstractas do java.
Ou as classes abstractas são bem implementadas ou não são. Cabe a quem as faz prover que sejam boas.

O que eu não entendi é o codigo que vc propõe que se use se não quisermos usar herança. Vamos pensar por um momento que é proibido usar herança. Então, como é que, com composição, resolveriamos o problema proposto de não reescrever métodos CRUD simples? Ou vc acha que tais métodos não existem ? Que todos os métodos do Repositorio são complexos por tratarem de agregados ? Vc mesmo me lembrou que nem todos os entitty são agregados complexos…

Parece que é ha uma dicotomia: por um lado vc aceita que existem entities simples o suficiente que não precisam de repository. Por outro vc aceita que o cliente de um dao deve sempre ser um repository.
Ora, se para comunica com o dao preciso sempre de um repository, então preciso de um mesmo quando o codigo é simples o suficiente para ser igual para todas as entidades. Não ?
Agora vc me diz que nem todas as entities tem repository… bem, vc tem que escolher. Afinal como é?

Tudo bem que vc pode querer dao de locais fisicos diferentes, mas ai vc simplesmente parametiza a fabrica.
Nada disso impede que o algoritmo que procura e seta o dao do repositorio seja comum a todos os repositorios. Tb nada impede que existam métodos simples no repositorio que eu herde e reimplemente quando precisar.

Se formos levar esta arquitectura às ultimas consequencias rápidamente vc descobre que vc vai precisar de um registro de repositorios, porque essa é a forma correta de declarar os repositorios de forma independente do codigo que os usa (mesmo quando o registro for implicito). No outro extremo vc vai descobrir que se usar um dao do tipo hibernate e todas as entidades forem simples, então vc vai precisar de apenas 1 repositorio generico que delega tudo para 1 dao. E isso automática transforma o " 1 repositorio + 1 dao hibernate " num anti-pattern.

Eu só tentei apresentar um solução para o colega de como reaproveitar os métodos. Vc levantou a questão de usar composição em vez de herança. Como é que composição resolve o problema de não ter que reescrever os métodos ? Foi isso que não entendi.

Eu até entendi que “composição” se referia a usar os DAO/Strategy , mas não entendo o que isso tem a haver com herança da classe repositorio.

Não é necessáriamente verdade. Desde que a super classe esteja bem documentada é perfeitamente natural usá-la. Vai-me dizer que nunca usou AbstractAction do swing ? ou AbstractTableModel ? Então! classes abstractas são boas. Acho que é bastante simples um contrato que usa um default e vc é livre de redefinir o default quando quiser. E reimplementar store() parece-me bastante intuitivo se vc quiser alterar o algoritmo que guarda o objeto.
Agora vc vai argumentar que o DAO é uma coisa interna do repositorio e portanto teria que saber que o repositorio tem um dao para que ao reimplementar store() o possa usar. Ora, isso é bem simples de conseguir. Faça o dao ser privado e crie um metodo protegido para o acessar. Desta forma classes da hierarquia têm toda a informação que precisam e classes clientes nem sonham que existe um dao.
Enfim, se vc quiser fazer bem feito e sem esse temor sobre como o próximo vai reimplementar sua classe abstrata, ha como fazer.

Vc está partindo do pressuposto errado de que se chamaria super.store(). Se o seu objetivo é redefinir o algoritmo, não ha porque usar o algoritmo velho dentro do novo. Não faz sentido, até porque vc não sabe qual era o velho.

Eu sei. Eu entendi isso. O que não consigo ver é onde isso substitui herança.
(veja que usei o DAO dentro do GenericRepository)

[/quote]

Releia os links que passou antes. O dilema não é entre herdar ou compor. O dilema é saber usar as diretivas É-UM e TEM-UM corretamente. Quando vc usa strategy, vc claramente sabe que a classe não é-uma estratégia, a classe tem-uma estratégia (de entre várias posssiveis). Foi isso que quiz dizer com “strategy não composição” referindo-me ao facto de ao vc usar DAO como estratégia não está escolhendo entre se o repositorio É-UM DAO ou ele TEM-UM DAO. Vc já escolheu que ele TEM-UM DAO ao escolher o padrão Strategy. Agora, isso, não tem nada a haver com eu poder ou não extender o repositorio. Por isso que eu sigo sem entender o isto tem a ver com herança. Se houve alguma duvida quanto a se um repositorio é-um dao eu entenderia o seu comentário, mas não é o caso. O que estava em causa era os vários tipos de repositorio compatilharem codigo. A composição não é um meio deles fazerem isso… pelos menos não a composição de DAO/Strategy.

A

Domain Driven Design Quickly:
A service is not about the object performing
the service, but is related to the objects the operations are
performed on/for. In this manner, a Service usually becomes a
point of connection for many objects
.

rodrigoy, como você pode ver na citação acima, um service do DDD é um ponto de conexão de vários outros objetos, afim de fornecer uma determinada operação. Muita semelhança com o padrão descrito por Fowler, não concorda?

Quanto a nele conter os objetos de domínio ou os objetos de domínio conter eles:

A execução da operação do Service é referenciada para outros objetos no domínio.

A

Lezinho:

A execução da operação do Service é referenciada para outros objetos no domínio.

A tradução correta seria:

“A execução da operação do Service refere-se a/aponta para/depende de outros objetos no domínio.”

A

sergiotaborda:
Isso pode até ser verdade. Mas se tivesse medo disso não usaria as classes abstractas do java.
Ou as classes abstractas são bem implementadas ou não são. Cabe a quem as faz prover que sejam boas.

A questão não é ser classe abstrata, e sim as funcionalidades herdadas e seu uso. A própria classe Repository do seu pseudo-código não tem característica de classe abstrata, é uma classe convencional, que não exige nenhum método a ser implementado pela classe filha.

É válido uso de classes abstratas quando seus filhos assumem como “seus”, os métodos implementados do pai, apenas especializando os métodos abstratos que justificam a existencia de "N"classes filhas. As classes filhas não sobreescrevem os métodos do pai, pois pela modelagem é assumida tal coesão.

No seu exemplo não existe tais métodos abstratos logo não se justifica a herança de classe abstrata. As operações de CRUD nos repositórios não recebem necessariamente o mesmo tratamento (não existe conceituamente esta garantia) , logo isso tbm desmotiva o uso da Herança para os repositórios.

Parece intuitivo pra você que criou o método. E se o store da classe pai escreve em log a operação e dispara um email além de persistir? Você acabou de perder funcionalidades. Herdar e sobreescrever quebra o encapsulamento, pois você tem que conhecer os detalhes da implementação do pai.

Para evitar herança se usa composição (quando a herança não se qualifica como um subtipo). Herança não serve para deixar de digitar código, serve para qualificar um subtipo. Não existe um objeto de negócio “Repository” com CRUDs na definição de negócio, e sim CustomerRepository, ProductRepository e etc, isso é, a não ser que de fato Repository fosse abstrata, mas como você definiu, ela é concreta, pelo menos lógicamente. Portanto não faz sentido o ancestral em comum, tbm não faz sentido tais subtipos, pelo menos para os motivos expostos.

Contudo o q sugeri foi simplesmente desacoplar o DAO, não foi fazer “A Repository Genérica”, mesmo em CRUD. Como venho dizendo não vejo sentido nisso.

Quem disse que não são todas as entidades que precisam de repositories não sou eu, é a literatura:

Domain Driven design Q.:
Provide
repositories only for Aggregate roots (…)

Os agregados que não possuem Repositories são reportados ao Repository da Entity root do Agreggate. Tal repositório é cliente de um DAO, simples assim. Nesta caso o “benefício” da herança do CRUD pode não ser utilizado.

Nunca disse que todos os métodos são agregados ou que todos são complexos. Mas só por saber que vão existir agregados e vão existir CRUDs que não vão simplesmente chamar um DAO diretamente (o negócio possibilita isso), ja me faz crer que o possível ancestral comum seria apenas por conveniência e não por um bom Design, e isso não me agrada.

Pelo contrário, pra mim quem tinha que ter o DAO é o MinhaClasseRepository, pois OutraClasseRepository pode ter um DAO diferente… Uma classe “genérica” com a implementação do DAO toda sua não acho uma boa sugestão. No mínimo isso deveria ser setado pelos filhos, para quem quer utilizar este tipo de arquitetura …

Claro que pode fazer sentido. Você pode apenas somar uma regra, como disparar uma thread de geração de relatório, e continuar com a outra definição do super.store. Mas a questão é se isso seria uma boa idéia. Eu acho que não, mas tem gente que faz (principalmente se usou a herança só por conveniencia).

sergiotaborda:

Se formos levar esta arquitectura às ultimas consequencias rápidamente vc descobre que vc vai precisar de um registro de repositorios, porque essa é a forma correta de declarar os repositorios de forma independente do codigo que os usa (mesmo quando o registro for implicito).

Que exagero… eu só usaria Regyster se hoje em dia ainda não existisse tantos frameworks com D.I.P.

Estamos de fato discutindo coisas diferente. Meus posts foram em relação a pergunta “Como desacoplar o DAO?”. Justamente pq acho uma péssima idéia os Repositórios compartilharem CRUD… (ja disse, operações do repositório são operações de negócio, não existe garantia que todos os CRUDs deverão ter o mesmo comportamento de negócio).

Mas tá, nada disso é regra e ninguém vai chegar a lugar algum, gosto é gosto. Particularmente, eu não aprovo Herança por conveniência, não acho uma boa prática.

A

Apenas transcrevi a idéia … no caso use então:
A execução da operação do Service aponta para outros objetos no domínio(…) dá na mesma.
Em DDD Service continua sendo um workflow para os objetos de negócio.

C

Lezinho:
Domain Driven Design Quickly:
A service is not about the object performing
the service, but is related to the objects the operations are
performed on/for. In this manner, a Service usually becomes a
point of connection for many objects
.

rodrigoy, como você pode ver na citação acima, um service do DDD é um ponto de conexão de vários outros objetos, afim de fornecer uma determinada operação. Muita semelhança com o padrão descrito por Fowler, não concorda?

Quanto a nele conter os objetos de domínio ou os objetos de domínio conter eles:

A execução da operação do Service é referenciada para outros objetos no domínio.

O que Fowler descreve não é um padrão, mas uma camada… No DDD, services são conceitos do domínio, assim como repositórios e entities.

Services Layer (também conhecido como Application Layer) não deve ter regras de negócio (apesar de que do ponto de vista do cliente é indiferente). O papel do services como camada é a coordenação de fluxos e responder às solicitações, eventualmente entrando na camada de domínio.

Ou seja, de semelhante só tem o nome… Por isso prefiro o termo Application Layer.

A

Se não é um padrão, então tente dizer isso a Randy Sttaford, que descreve no POAA a literal diferença entre o “PATTERN” Session Façade e o “PATTERN” Service Layer, exatamente com estas palavras. Neste mesmo capítulo é mencionada a Application Layer, tendo como a ServiceLayer uma ponte entre esta (AppLayer) e a modelo de domínio.

O Domain Driven Design diz que:
“A Service usually becomes a point of connection for many objects”
… exatamente como um objeto da ServiceLayer, onde que não tendo lógica de negócio, delega essa aos objetos do domínio.

C

Se não é um padrão, então tente dizer isso a Randy Sttaford, que descreve a no POAA a literal diferença entre o “PATTERN” Session Façade e o “PATTERN” Service Layer, exatamente com estas palavras. Neste mesmo capítulo é mencionada a Application Layer, tendo como a ServiceLayer a ponte entre esta e a modelo de domínio.

Você quer dizer então que Application Layer é a Client Layer? Sério, não entendo sua interpretação de Application Layer.

No link da minha resposta anterior tem uma citação desse cara sobre Services Layer: “Defines an application’s boundary with a layer of services that establishes a set of available operations and coordinates the application’s response in each operation.”

Lezinho:
O Domain Driven Design diz que:
“A Service usually becomes a point of connection for many objects”
… exatamente como um objeto da ServiceLayer, onde que não tendo lógica de negócio, delega essa aos objetos do domínio.

Uma definição mais clara seria: Um Service (DDD) é um ponto de conexão para vários objetos (de domínio) que compartilham de uma mesma regra de negócio. Observe que não saímos do domain layer aqui.

A diferença fica evidente se dissermos que um Service (DDD) poderia ser chamado da Service/Applcation Layer, mas o contrário não deveria ser permitido se você considerar uma premissa básica da separação em camadas: Dependência apenas de camadas abaixo.

Services e Repositorios pertecem ao domínio
Service/Application Layer NÃO pertece ao domínio (apesar de fazer uso do mesmo)

A

“Client Layer”?

Client Layer é qualquer camada que faça uso de outra camada, ou seja, uma camada cliente da outra… isto sim não é Padrão. Praticamente todos diagramas DDD envolve "Client"s que representam tais camadas.

Um repositório pode ser client de um DAo, uma Entity pode ser cliente de um VO, um Aggregate pode ser client de um Entity …

“Camada de aplicação” é aquela relevante ao contexto da aplicação (ManagedBeans, Actions) ou aquelas que server como uma Supercamada para a de Serviços, oferecendo suporte como de email, ftp, etc (de nada tem haver com o negócio).
No livro de Fowler você vê Service direcionados ao negócio, que faz o workflow aos entities e VOs, e aqueles definidos como seu supertipo para suporte a serviços da aplicação.

Na própia citação que você coloca, é definido o Service como uma fronteira entre a aplicação e o Domínio.

No DDD isso não muda, podendo existir tanto Service voltado a negócio como para Aplicação:

Domain Driven Design:
“While using Services, is important to keep the domain layer
isolated. It is easy to get confused between services which
belong to the domain layer, and those belonging to the
infrastructure. There can also be services in the application layer
which adds a supplementary level of complexity.

O texto em negrito do DDD é praticamente o mesmo do PoEAA.

C

Lezinho:
“Client Layer”?

Client Layer é qualquer camada que faça uso de outra camada…

Quem disse o contrário?

Estamos falando de camadas; repositório não é camada, entity não é camada, aggregate não é camada… Isso sim é padrão :wink:

Aqui deu a entender que seus Actions poderiam estar na camada de aplicação. O que não é o caso certo?

Lezinho:
Domain Driven Design:
“While using Services, is important to keep the domain layer
isolated. It is easy to get confused between services which
belong to the domain layer, and those belonging to the
infrastructure. There can also be services in the application layer
which adds a supplementary level of complexity.

Quem está dizendo que os Services são os mesmos é você. Agora já temos 3 services. Sua citação confirma que Services do DDD não é o Service Layer. Ou seja, nada impede que tenhamos entities chamando repositorioes ou entities chamando services ja que estamos falando estritamente de services “which belong to the domain layer”.

P

Eu já estou achando a discussão confusa demais para entender mas só um pontinho:

Camadas (Layers) é um padrão sim

C

Eu quis dizer que fowler não define Service Layer como um padrão de domain model (ou um “building block” como Evans define seus padrões)

Services de DDD pertencem ao domínio do problema e por isso podem existir entities que dependam de tais Services.

A

Aiaiai …

Services são Services. Existem de aplicação e de negócio, não sei onde esta a complicação disso. Tanto o DDD quanto o PoEAA comentam dos dois.

De fato Phillip, a discussão era de Manga e já estamos falando de Banana.

C

Lezinho:
Aiaiai …

Services são Services. Existem de aplicação e de negócio, não sei onde esta a complicação disso. Tanto o DDD quanto o PoEAA comentam dos dois.

De fato Phillip, a discussão era de Manga e já estamos falando de Banana.

Desnecessário seus gemidos… Inclusive, é lamentável a atitude de desdém das pessoas quando questionadas quanto a sua interpretação sobre os textos mencionados.

Você não percebe mas a complicação está no fato de você não conseguir explicar com clareza a diferença entre a camada Service e Application. Talvez porque não haja. Você cita duas fontes que definem a mesma coisa com 2 nomes, reconhecidamente um conflito na nomenclatura atual senão, vamos lá, precisamos ter claro as responsabilidades de cada camada, mas esse não parece ser o caso, pelo contraráio, você parece ignorar princípios importantes como YAGNI e KISS e se justifica colando citações sem contexto do seu autor preferido.

Talvez o tamanho dessa thread tenha feito você perder o foco mas eu vou tentar ser ainda mais claro:
Eu considero as camadas Service e Application como a mesma e não sinto falta de outra camada.

Pense que existem pessoas que estão interessadas em comecar a aplicar práticas mais modernas para o seu projeto de software OO e precisam competir com as tais arquiteturas de “referência” estabelecidas. Eu não vejo como essa camada adicional pode ajudar essas pessoas a melhor organizar sua arquitetura usando apenas o seu argumento de que tem que ser assim porque o mestre mandou.

A

Bom, deixando suas observações pessoais de canto (pq em meu pé quem pega é a minha namorada), vamos lá:

Talvez VOCÊ não percebeu que não sou eu que menciona sobre as diferenças, mas sim os próprios autores, como no texto que citei no post anterior. Aliás vale repetir a citação:

… pra mim esta bem clara e nítida a existência entre Services de infraestrutura, pertencentes a camada de aplicação, e os services pertencentes a camada de domínio, aqueles que se relacionam com um caso de uso. Detalhe, o trecho acima trata de Services no capítulo destinado a Services em um livro de DDD, portanto são Services do DDD. Não há falta de contextualização.

Com base no trecho acima, olhe no diagrama de classe que Fowler colocou no PoEAA (a qualidade ficou péssima, mas acho que você vai conseguir visualizar as classes), que esta anexada com este post. Lá esta descrito um modelo exatamente como na citação, um service para o negócio e um para a infraestrutura da aplicação.

cmoscoso:

(…) e vc se justifica colando citações sem contexto do seu autor preferido.

Fora do contexto? São trechos totalmente pertinentes a suas colocações, vindas de autores como Martin Fowler, Eric Vans, Floyd Marinescu… Se estas pessoas não são boas referências, então realmente estou mal embasado.

Se você não sente falta, não utiliza. Nenhum destes autores citados dizem que você DEVE usar um Service voltado para os serviços de aplicação, ou um como ponte para os objetos de domínio. Você usa conforme sua necessidade. Toda camada é “adicional”, você usa se sente necessidade de usá-la.


R

[lugar errado]

R

pcalcado:

Só é bom focarmos que discordar é ótimo. Eu discordo do Fowler bastante em DSLs, por exemplo. O ponto é ter um mínimo de respeito pelos outros e darmos base às nossas discordâncias, seja usando uma bibliografia ou argumentando. …

Eu coleciono essas discordâncias com autores famosos… não dá pra concordar com tudo. Eu discordo com a visão do Philipe Krunchten sobre Análise e Design. Discordo com a visão do Ambler sobre MDA. Discordo com a visão do Ivar Yacobson sobre as maravilhas de um Use Case ser um Classifier.

Lezinho, vc tem algum paper sobre essas regras de segurança com o Drools? (creio que vc tenha aplicado isso na sua aplicação SEAM).

P

Eu estive com o Krunchten num workshop do SPIN em porto alegre e pesar da fantastca sacada dos pontos de vsta arquiteturais eu discordo bastante dele tambem. Ele nsiste em BDUF sem parar muito para debater.

C

Aspecto só dever ser utilizado para tratar dos interesses transversais ou sistemicos e não na sua lógica de negócio.

P

Por que?

Uma regra de negócio ode se comportar como aspecto, validações são um exemplo.

R

Injetar um repositorio ou um service numa entidade é um interesse transversal. Mesmo que não fosse, se uma determinada regra de negócio fosse melhor implemetada com aspectos, na minha opinião, não teria problemas. Desde que exista boas razões para tal.

P

Acho que a confusão este caso é o que é regra de negócio. Um Domain Model contem regras de negócio mas provavelmente não é o único lugar onde estas ficam. Dificilmente as relações dentro de um domain model seria tratadas com aspectos mas as outras regras isoladas poderiam.

W

E realmente não há. :wink:

O proprio Fowler explica em um post no seu bliki, esta confusão (normal) sobre a salada de termos que os autores criam.

Vejam que ele precisa explicar isso, porque esta falta de entendimento que causa o “Anemic Domain Model”. Vejam: é normal existir esta confusão.

E a explicação pra isso é a mais clara possível: pessoas agem e pensam de formas diferentes. E dão “nome aos bois” de formas diferentes. E autores são pessoas!

Estas pessoas (Fowler, Evans, Booch, Rockford Lotha, etc…) tem idéias/soluções e as publicam em formas de livros e artigos. E sempre encontram os que concordam e discordam.

Eles não formam um grupo para debater e formalizar estas idéias/soluções e nomes. E mesmo assim elas são compartilhadas.

Estas idéias/soluções existem para nos ajudar, “iluminar nosso caminho”, mas normalmente cada uma delas foi concebida em um “caminho” distinto. Não devemos tomar como verdade ou como padrão o que um ou outro autor apresenta sem definir o contexto, o caminho que nós estamos pisando.

A propósito, a diferença entre uma solução e uma idéia seria um bom assunto pra outro post. Normalmente soluções nos ajudam na prática, e idéias quebram paradigmas, ajudam a vender livros e palestras, mas não há garantia de que vão resolver um problema e ainda deixam a cabeça dos arquitetos pegando fogo! (DSL?).

  • (Como toda regra tem uma exceção, o Manifesto Ágil partiu de uma reunião entre os autores)

PS.: Este é meu primeiro post. Espero poder contribuir e aprender muito por aqui.

C

Por que?

Uma regra de negócio ode se comportar como aspecto, validações são um exemplo.

Aspecto é um assunto bastante interessante, e um bom livro sobre aspecto é Aspectj Programação Orientada a Aspectos com Java, editora Novatec. O aspecto veio para ajudar onde a OO falha, separar os interesses funcionais dos interesses sistêmicos.

A incapacidade da OO de modularizar os interesses sistêmicos ocasiona os problemas resultantes da descentralização do código:

.Replicação do código;

.Dificuldade de manutenção;

.Redução da capacidade de reutilização de código;

.Aumento da dificuldade de compreensão;” (Diogo Vinícius Winck e Vicente Goetten Jr)

Entenda funcional como sua lógica de negócios e sistêmicos o restante como exceções.

P

Você não me respondeu. Porque eu não posso tratar minhas regras de negócos como aspectos?

Eu não li este livro mas acredito que possa ter passado alguma confusão. AOP diz como implementar os conceitos mas não diz quais são (tanto que os exemplos sempre recaem nos mesmos de sempre: log, segurança, transação), regras de negócio podem ser implementadas como conceitos ortogonais se for interessante. Um exemplo que já citei é validação, outro é segurança. Ambos geralmente são regras de negócio e não uma necessidade não-funcional (o que você chamou de ‘sistemico’). Recomendo que leia o livro de Ramnivas Laddad , AspecJ in Action. Não sei se tem em português.

Um artigo do autor cita:

At the system level, security, transaction management, and thread-safety concerns are commonly implemented using AOP. Many business logic problems (also known as domain-specific concerns) also exhibit crosscutting concerns upon close examination and lend themselves to modularization using aspects. On the other side, units such as classes and packages show code tangling and code scattering at a smaller scale (what I call local or micro crosscutting concerns). Aspect-oriented refactoring can help resolve these kinds of concerns by using aspects to improve the code structure. (See Resources to learn more about aspect-oriented refactoring techniques.)

C
<blockquote><div class="quote-author">pcalcado:</div><blockquote><div class="quote-author">Cobracan:</div>

Aspecto é um assunto bastante interessante, e um bom livro sobre aspecto é Aspectj Programação Orientada a Aspectos com Java, editora Novatec. O aspecto veio para ajudar onde a OO falha, separar os interesses funcionais dos interesses sistêmicos.

“A incapacidade da OO de modularizar os interesses sistêmicos ocasiona os problemas resultantes da descentralização do código:

.Replicação do código;

.Dificuldade de manutenção;

.Redução da capacidade de reutilização de código;

.Aumento da dificuldade de compreensão;” (Diogo Vinícius Winck e Vicente Goetten Jr)

Entenda funcional como sua lógica de negócios e sistêmicos o restante como exceções.

Você não me respondeu. Porque eu não posso tratar minhas regras de negócos como aspectos?

Eu não li este livro mas acredito que possa ter passado alguma confusão. AOP diz como implementar os conceitos mas não diz quais são (tanto que os exemplos sempre recaem nos mesmos de sempre: log, segurança, transação), regras de negócio podem ser implementadas como conceitos ortogonais se for interessante. Um exemplo que já citei é validação, outro é segurança. Ambos geralmente são regras de negócio e não uma necessidade não-funcional (o que você chamou de ‘sistemico’). Recomendo que leia o livro de Ramnivas Laddad , AspecJ in Action. Não sei se tem em português.

Um artigo do autor cita:

At the system level, security, transaction management, and thread-safety concerns are commonly implemented using AOP. Many business logic problems (also known as domain-specific concerns) also exhibit crosscutting concerns upon close examination and lend themselves to modularization using aspects. On the other side, units such as classes and packages show code tangling and code scattering at a smaller scale (what I call local or micro crosscutting concerns). Aspect-oriented refactoring can help resolve these kinds of concerns by using aspects to improve the code structure. (See Resources to learn more about aspect-oriented refactoring techniques.)

A questão em sí é que aspecto veio para completar a OO, onde a OO falha ou deixa a desejar. Você pode usar aspectos para sua lógica de negócio mas me parece muito estranho um SOO usar aspecto em sua camada de negócios e particularmente tenho minhas dúvidas. Esse assunto é muito interessante e polêmico. Não sou um especialista para afirmar o que deve ser ou não, mas a minha opinião é que devemos separar as responsabilidades.

T

IMHO, colocar aspectos referente a negócios é meio estranho, não que seja errado, mas estranho. A validações por exemplo ficariam melhores usando o padrão Specification, que é uma forma elegante de executar as validações dentro do domain.

Acho aspectos muito bem vindo quando o assunto é injeção de dependências. Um bom exemplo é o @Configurable do spring, ou melhor ainda, inventar uma macumba para seu domain não depender de container de DI nenhum, e isso é possível com AOP.

P

Thiago Senna:
IMHO, colocar aspectos referente a negócios é meio estranho, não que seja errado, mas estranho. A validações por exemplo ficariam melhores usando o padrão Specification, que é uma forma elegante de executar as validações dentro do domain.

Thiago, Specfication não serve para isso. Specification serve para verificar s um objeto é condizente com um dado critério, não se ele é válido. Você não precisaria de uma spec ara dizer se um triângulo de dois vértices é válido, o objeto deve se verificar. Como todos nós sabemos um problema deste tipo de coisa é que validação geralmente resulta em código duplicado porque você ode querer verificar isso em outros lugares antes de formar o objeto em si.

C

pcalcado:

Thiago, Specfication não serve para isso. Specification serve para verificar s um objeto é condizente com um dado critério, não se ele é válido. Você não precisaria de uma spec ara dizer se um triângulo de dois vértices é válido, o objeto deve se verificar. Como todos nós sabemos um problema deste tipo de coisa é que validação geralmente resulta em código duplicado porque você ode querer verificar isso em outros lugares antes de formar o objeto em si.

Hmmm… Vc ta falando de validações basicas, tipo aquelas comum em construtores de VOs que procuram por nulls e illegal exceptions. Acho que seria uma boa mesmo, nem que seja posteriormente com o modelo numa situacao mais estavel com relação a refactoring.

P

VOs? COmo assim?

S

Thiago Senna:
IMHO, colocar aspectos referente a negócios é meio estranho, não que seja errado, mas estranho. A validações por exemplo ficariam melhores usando o padrão Specification, que é uma forma elegante de executar as validações dentro do domain.

Sim, o Specification é o padrão para validação, mas AOP pode ser util para manter a consistencia sem grande trabalho. Em vez de vc escrever aquele código chato que verifica se os paramentos são null ou fora de range vc pode simplesmente anotar e deixar alguem fazer o trabalho. Ok, isto é feitos com alguns frameworks de anotations que usam algo anterior ao AOP : bytecode rewrite. Afinal é a capacidade que o java tem de poder alterar o bytecode em runtime que habilite as ferramentas AOP que são apenas uma forma de implementar inceptações do codigo normal. As implementações de AOP são apenas um frameowrk simples de bytecode rewrite. Existem outras formas de bytecode rewrite que alcançam os mesmo objetivos. No fim, tlv seja mais facil usar um framework baseado em anotations para fazer a consistencia dos objetos do que escrever uma monte de cutting concerns repetidos.


Acho aspectos muito bem vindo quando o assunto é injeção de dependências. Um bom exemplo é o @Configurable do spring, ou melhor ainda, inventar uma macumba para seu domain não depender de container de DI nenhum, e isso é possível com AOP.

A injeção é feita pelo mesmo mecanismo de bytecode rewrite. Os frameworks que fazem isso não usam AOP.
E se vc for escrever o seu proprio DI container tb não vai usar AOP. Porque AOP é baseado em bytecode rewrite, então é muito mais eficaz usar bytecode rewrite logo de base.
AOP é bytecode rewrite para regras genericas que os frameworks de butecode não podem antever.E por isso são ideiais para injetar regras de aplicação (log, transação, etc)

E

Sobre Specification e validação, o q eu penso sobre, num exemplo simples. Validação verifica se tres numeros formam um triangulo (se nenhum é nulo, negativo, valores minimos e máximos), enquanto eu teria uma Specification (que recebe um objeto triangulo) para determinar se o triangulo é um triangulo retangulo.

P

Especification é para validar um objeto contra um critério relevante ao negócio. Geralmente este conceito é único e não faz sentido ter exposto na forma de um comportamento em si. Dois cenários:

  • Ser um triângulo retêngulo ou não é algo que é usado em vária partes do sistema para coisas diferente: O objetod eve ter uma propriedade que indique se é retângulo ou não, não uma Specification. A Specification não serve para checar oe stado interno do objeto, validação quem faz é o objeto

  • Existe uma situação onde apenas triângulos retângulos são aceitos. Nenhum outro lugar (ou pouquíssimos outros) utilizam esta informação então não vale a pena criar um atributo que informe se o triângulo é retângulo. Neste caso cria-se uma verificação que recebe um triângulo e informa se é um retângulo ou não, se não for ela o rejetia. Esta e a especificação.

O importante é notar que o objeto é quem se valida. Se você possui um critério para rejeitar ou aceitar objetos de acordo com um critério qualquer pode criar uma especificação apra isso mas não é uma validação. Um objeto pdoe ser válido e não ser aceito por uma especificação.

C

A minha opinião sobre Aspecto é de que só devemos utiliza-lo para os interesses sistêmicos onde o OO falha ou deixa a desejar, como foi dito antes, se utilizarmos Aspectos na camada de negócios então sua aplicação deixa de ser puramente OO.

P

Ahm? O que é uma aplicação ser puramente OO?

Para começar teríamos que ter uma linguagem puramente OO, não? Então já podemos excluir Java. Outra coisa importante seria que tudo no programa fosse jeito com objetos, talvez? Então podemos excluir aspectos (especialmente os com AspectJ, com Spring AOP, JBoss AOP e essas coisas ainda dá pra engolir). Acredite em mim: você não precisa de e não quer um programa 100% OO.

C

DDD

public class Intervalo {
    ...

    public Intervalo(int inicio, int quantidade) {
        this.inicio = inicio;
        
        if (quantidade &lt; 1) {
            throw new IllegalArgumentException("Quantidade no intervalo deve " + 
                    "ser maior que zero");
        }

    ...
}

Eu tenho várias validações assim, não só nos Value Object claro, por isso talvez fosse uma boa usar AOP.

Estou lembrandode um outro tópico que vc falou que linguagens dinâmicas como ruby não precisam de AOP, sei que tem algo a ver com o conceito de open classes, mas nao estou muito por dentro de como isso é implementado.

A cada dia que passa eu tenho mais vontade de aprofundar nessa linguagem…

N

Acho que há uma confusão aqui.

Value Object é um pattern criado por motivos bizzaros e muito utilizados em arquiteturas antiquadas. Veja referência sobre Value Object para ver a diferença deste e Pojo.

P

Ufa! :slight_smile:

Essas validações, pode definição ficam nos objetos. Dá uma olhada no que escrevi acima nesse exemplo do triângulo.

cmoscoso:

Estou lembrandode um outro tópico que vc falou que linguagens dinâmicas como ruby não precisam de AOP, sei que tem algo a ver com o conceito de open classes, mas nao estou muito por dentro de como isso é implementado.

A cada dia que passa eu tenho mais vontade de aprofundar nessa linguagem…

Você pode utilizar o conceito de AOP em linguagens dinâmicas mas não precisa. Um exemplo é o ActiveRecord do Rails, ele identifica que um método no formato find_by_ALGUMACOISA ele intercepta essa chamada e toma as medidas necessárias. Isso é feito com a meta-programação, procure na internet sobre method_missing e seus amigos :wink:

P

nbluis:
Acho que há uma confusão aqui.

Value Object é um pattern criado por motivos bizzaros e muito utilizados em arquiteturas antiquadas. Veja referência sobre Value Object que vai entender a diferença deste e Pojo.

Você está falando sobre Transfer Object, qe antigamente era chamado de Value Object. O Value Object referido neste tópico é outro padrão, vem de Domain Driven Design.

T

Opa… valeu pelas correções. Deixe-me bolar um exemplo que veio em minha cabeça.

public class Infrator {

  String nome;
  String idade;

  // getters and setters omitidos ;)

}
public class MenorInfratorSpecification {

  public boolean isSatisfiedBy(Infrator infrator) {
    return infrator.getIdade() < 18;
  }

}
public class FEBEM {

  public void addMenorInfrator(Infrator infrator) {
    MenorInfratorSpecification spec = new MenorInfratorSpecification();
    if (spec.isSatisfiedBy(infrator)) {
      // prende o menor infrator
    } else {
      throw new RuntimeException("Este infrator não é de menor");
    }
  }

}

Este seria um bom exemplo de validação (de regra de negócio) utilizando uma Specification?

Quanto ao AOP o que vocês defendem é que aspectos seriam interessantes para aquelas validações repetitivas como tamanho de campo, se um atributo é nulo, se uma dada String realmente é um e-mail, por exemplo?

P

Pode ser que sim, depende Qual o domínio do seu sistema? Onde os ‘menores infratores’ são utlizados? O sistema é sobre eles, é sobre infratores em geral? A linha tênue que define se você vai ter uma specification ou simplesmente um isMenorDeIdade()só e definida pelao negócio.

Thiago Senna:

Quanto ao AOP o que vocês defendem é que aspectos seriam interessantes para aquelas validações repetitivas como tamanho de campo, se um atributo é nulo, se uma dada String realmente é um e-mail, por exemplo?

É mais amplo que isso: apsectos podem ser utilizados sempre que forem interessantes, não apenas para requisitos não funcionais.

T

Por exemplo: se opto por utilizar AOP + compile-time weaving (ou mesmo load-time weaving) eu estaria mesmo assim utilizando bytecode rewrite, certo? O AOP entraria apenas como um facilitador de bytecode rewrite? Ou você estaria falando de algo bem mais punk que isso? rsrs…

Pensei em um domínio que atendesse e exemplificasse esta citação que você fez: “Um objeto pdoe ser válido e não ser aceito por uma especificação.” Mas compreendi como a solução pode variar dependendo do domínio. Um método isMenorDeIdade() no objeto Infrator poderia ser suficiente ao invés de uma Specification. Aff… é confuso, mas tá valendo… :slight_smile:

S

Por exemplo: se opto por utilizar AOP + compile-time weaving (ou mesmo load-time weaving) eu estaria mesmo assim utilizando bytecode rewrite, certo? O AOP entraria apenas como um facilitador de bytecode rewrite? Ou você estaria falando de algo bem mais punk que isso? rsrs…

Vc pode usar qq tipo de weaving com AOP. Vc estaria usando bytecode rewrite (instrumentatilização acho que se chama) O AOP é um framewordk generico para fazer bytecode rewrite. Com ele vc faz qq coisa que quiser. Interfere em qualquer coisa que quiser. É generico. Por ser generico é bom para regras desconhecidas à priori ou regras cuja definição é uma condição (cut-point) e não uma interface ou coisa simples. Por isso AOP é bom para incluir transações etc… Agora, se vc sabe à priori onde estão seus cut-points vc não usa AOP, usa um framework de bytecode rewrite (tou lembrando do Javasssit da JBoss ). Aqui vc não precisa se algo generico, precisa de algo eficiente. No fim vai dar ao mesmo, mas é um equilibrio entre ser generico vs eficiente.

Por exemplo, no JPA todos os objetos @entity têm que ser instrumentalizados para que sejam interceptadas chamadas ao métodos modificadores, para que o estado do objeto passe para dirty. O programador não vê isso.
Quando faz uma query e obtem os objetos , se vc fizer instanceof e comparar com a sua classe de negocio vai retornar true. Mas internamente o drive JPA pode usar outra classe , digamos Persistable para controlar o objeto.
Ele pode fazer isso criando um proxy da classe de negocio : veja bem o proxy herda a classe de negocio e por isso o instanceof funciona. Essa herança é feita com bytecode rewrite. Mas ao mesmo tempo o proxy tb herda de Persistable. Não é só herança “a quente” é "herança multipla a quente’. bytecode rewrite é tão poderoso quanto isso. Normalmente vc não precisa violar as regras do java , e não o pode fazer em programação normal, mas com bytecode rewrite é o dia a dia. AOP é uma forma mais evoluida (generica) de construir bytecode rewrite
mas menos eficaz no sentido que ao aumentar a genericidade diminui o poder de transformação oferecido pelo bytecode rewrite.

Enfim , AOP é um facilitador , mas para coisas simples como interceptar métodos. É ideal para os cuting-concerns . Mas tudo o que é feito com AOP pode ser feito diretamente com bytecode rewrite de forma mais eficaz. Nem tudo o que se faz com bytecode rewrite se pode fazer com AOP , como herança “a quente” por exemplo.
Portanto, num framework vc usa bytecode rewrite. Para implementar uma logica de negocios só sua, vc usa AOP.

G

Ressucitando tópico :),

Mas não é para continuar essa discussão, e sim perguntar ao autor da soluçao:

Voce conseguiu fazer isso funcionar sem ter que alterar esse aspecto?

Estou tentando reproduzir aqui e estou obtendo erros, ao menos em meu ambiente de testes.

A exception diz: No application context active

Alguma luz ?

Obrigado

A

Em que momento vc tem essa Exception? Quando o Application Server inicia ou quando sua aplicação faz uso efetivo da injeção?

G

Oi alessandro,

Estou fazendo testes com o TestNG + Maven.

Uso um jboss embedded, isso está acontecendo no momento em que o hibernate sobe, depois de carregar os persistence.xml.

Eu ACREDITO que esse problema seja pelo fato do Hibernate subir antes do Core do Seam, por isso a inexistência dos contextos.

Gostaria de alguma forma de deixar o hibernate subir apenas depois do Seam, é possível isso ?

Que ambiente de testes vc usou para esse caso ?

Grato

A

Vc esta tendo este problema pq no código que exemplifiquei aqui, é utilizado um pointcut em “inicialization”.
Quando o persistence.xml levanta o mapeamento das crianças, o aspecto já entra em execução, mas de fato nem o Seam nem os contextos JSFs estão prontos.

Se você mudar o pointcut para “get” esse problema não ocorre e de quebra terá lazy-load para estes atributos. Ou seja, um atributo anotado pelo mapeamento do AOP, só entrará em ação quando um método invocar este mesmo atributo, assim como os ORMs fazem com seus atributos em Lazy.

O código ficaria parecido com isso:

public aspect InjectEntity{
	pointcut inject(Object s) :target(s) && (get(@In * br.com.siq.eqm.entity..*.*));

	before(Object obj):inject(obj){

		try {

			String valueOfContextVariable = null;

			Boolean createContextVariable=false;			

			Field field = obj.getClass().getDeclaredField(thisJoinPoint.getSignature().getName());

			field.setAccessible(true);

			Object objIn = field.get(obj);


			if(objIn == null){

				if(field.isAnnotationPresent(In.class)){

					In in = field.getAnnotation(In.class);

					if(in.value().equals("")){

						valueOfContextVariable = field.getName();

					}else{

						valueOfContextVariable = in.value();

					}	

					if(in.create())

						createContextVariable = true;


					field.setAccessible(true);

					try {

							field.set(obj, Component.getInstance(valueOfContextVariable, createContextVariable));

					} catch (IllegalStateException e) {

//TODO fazer aqui seu mecanismo de Log

					}catch(Exception e){

//TODO fazer aqui seu mecanismo de Log
					}

				}

			}
	

		} catch (Exception e) {

 //TODO fazer aqui seu mecanismo de Log	

			throw new RuntimeException(e);

		}				

	}	


}

[]'s

G

Alessandro,

Era justamente isso, testei esse novo código e funcionou perfeitamente.

Muito Obrigado!

PS: Postei esse tópico no forum do Seam, voce se importa se eu postar esse código lá ?Acredito que tenha mais gente querendo fazer isso.

[]'s

A

Claro, pode postar sim (com os devidos créditos :wink: )
Como lhe disse em off, estou passando estes códigos para javassist, e fará parte oficial do projeto ou irá para o X-Seam.
[]'s

R

Alessandro… li as primeiras partes do seu post e consegui tirar minha dúvida, que por sinal era a mesma da sua. (é, eu sei que isso aqui é antigo mas sou meio novato no quesito arquitetura).
Agora queria saber de vc como vc tá usando o Repository, por exemplo, são só interfaces ou há classes que possuem acesso a um DAO?

Aqui no trabalho estamos fazendo os sistemas com base no Spring e precisaremos injetar, em algum momento, o repositório em classes do domínio. Vc conhece o load time weaver do Spring. Seria parecido com o seu aspecto. O que eu queria saber era se seria viável, se eu não perderia performance, essas coisas.

Por último, queríamos meio que isolar a camada de negócio da parte mais de infraestrutura (acesso aos dados). Então pensamos em criar interfaces “Repository” que seriam implementadas por DAOs. Mas vi aqui que eu não precisaria de um Repository pra cada classe… qual seria a forma de fazer nesse caso?

Mencionei Alessandro no início mas vale aí pra todo mundo
Valeu

Criado 27 de setembro de 2007
Ultima resposta 24 de jul. de 2009
Respostas 98
Participantes 19