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

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.

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.

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.

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.

DDD

public class Intervalo {
    ...

    public Intervalo(int inicio, int quantidade) {
        this.inicio = inicio;
        
        if (quantidade < 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…

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.

Ufa! :slight_smile:

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

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

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:

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

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.

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?

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.

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

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

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:

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

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.

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

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

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

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

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

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

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