Dúvida em DDD, aonde ponho essa regra de negócio?

Daniel, leia o livro e tire suas conclusões. Mais de uma vez no GUJ os conceitos de Repository e outros padrões de Domain-Driven Design foram descritos como se fosse a maneira "certa"e um pequeno quote de um livro desmentiu isso. O livro em questão sequer fala em interfaces, qualquer conclusão do que é certo ou errado, seja lá o que isso signifique, é feita por alguém que não Eric Evans.

Na verdade, o livro não diz sequer como o Repositório interage com a base de dados. Ele cita alternativas mas na descrição mostra o Repositório interagindo diretamente com a base de dados. Porque isso? por que usar Repositorio não implica em usar DataMapper/DAO. Segundo o livro você deve adaptar o padrão (aliás, todos os padrões) à sua relidade tecnológica. Evans cita o uso de Entity Beans (EJB 2.x) como Aggregate Roots, por exemplo.

Um repositório é um conceito, como você modela o conceito depende da linguagem/plataforma em questão.

E Orientação a Objetos básica não fala de interfaces, interfaces existem apenas em algumas linguagens. Quando alguém depende de uma interface ele depende de algo que se comporta de uma maneira X, não importa quem. Suponha que você tenha uma interface:

interface A{

 void a1(String asdf);
 String a2()
}

E uma classe:

class B{
 public void a1(String asdf){/* ... */ }
 public  String a2(){/* ... */ }

}

É mais que claro que a classe B obedece o contrato exposto em A, logo não há porque criar uma classe C:

class C implements A{
 B b;

 public void a1(String asdf){b.a1(asdf); }
 public  String a2(){ return b.a2();}
}

Isso não é sequer purismo, é desconhecimento sobre o que é uma interface e onde ela encaixa no paradigma e, principalmente, sobre Domain-Driven Design.

Claro que se o repositório contiver regras você usará uma classe numa linguagem como Java, o que eu ainda não vi foi um motivo para um Repositório ter regras de negócio. É uma possibilidade, pode acontecer, mas eu nunca vi.

[quote=Paulo Silveira][quote=sergiotaborda]
Se Cliente e Produto forem interfaces eu posso ter um X que é cliente e produto. Isso é um absurdo. Para evitar isso a boas práticas de modelagem ensinam a utilizar classe nesses casos ( para limitar a herança)
[/quote]

Opa!!! Não é só porque criamos duas interfaces que estamos entao considerando que alguem pode implementa-las ao mesmo tempo. Set e List. Queue e Map. Comparable e Comparator. Faz sentido alguem implementar as duas? [/quote]

Faz. LinkedList implementa List e Queue. Facilmente poderia implementar um ListSet um objeto que permite utilizar get(i) mas não permite duplicados…
Esses seus exemplos são tirados de classes de infra e nesse dominio a abstração é maior. Logo, é natural utilizar interfaces porque ha um factor desconhecido e um factor de multiplas implementações possiveis. Criação de proxies (Collections.singletonXXX , Collections.syncronizedXXX , Collections,emptyXXX), etc… é o mesmo tipo de logica que se aplica no DAO ou num Service.

[quote=danielbussade]Olá Sérgio agora sim entendi o que quis dizer,a única coisa que nao ficou clara em relação aos DAO’s foi o seguinte vc citou isso

Isso eu não entendi, se eu precisar extender de uma classe de terceiros eu nao vou conseguir sendo o DAo uma interface já que um interface só pode extender outra interface, mas sendo o DAO uma classe abstrata eu consegueria poderia me explicar melhor??
[/quote]

Uma interface pode extender um qualquer numero de interfaces.
Imagine que vc precisa extender OODBManager de uma biblioteca de terceiros para implementar seu DAO.
vc faria assim (padrão adapter)

interface DAO

class OOBDDAO extends OODBManager implements DAO

Mas se o DAO já for uma classe vc não consegue utilizar directamente OODBManager

abstract class DAO

class OOBDDAO extends DAO , OODBManager // impossivel

Vc deve comentar isso no topico do outro post.

Obrigado pela ajuda, galera!

Sérgio,

Imagine que eu vá utilizar a sua estratégia número 2 (Service). Então eu tenho lá o meu TabelaService. A dúvida é aonde ele deve ser invocado? No meu Struts Action? Algo do tipo:

Tabela t = repositorio.pegaPorId(id);
t.fazAlgumaCoisaQueAltereMeuEstado();
TabelaService.alterar(t);

Consegui me explicar? Meu medo é ter que fazer o programador no final, sempre ter que chamar a persistência, ao invés de ser algo mais “automática”, dela ser feita dentro do próprio método do domínio!

Ah, aproveito aqui pra deixar o link de uma entrevista interessante com o Nilsson…

[]'s
Mauricio

[quote=MauricioAniche]Obrigado pela ajuda, galera!

Sérgio,

Imagine que eu vá utilizar a sua estratégia número 2 (Service). Então eu tenho lá o meu TabelaService. A dúvida é aonde ele deve ser invocado? No meu Struts Action? Algo do tipo:

Tabela t = repositorio.pegaPorId(id);
t.fazAlgumaCoisaQueAltereMeuEstado();
TabelaService.alterar(t);

[/quote]

Na estratégia usando Servide o action é apenas responsável por obter o objeto tabela.
Isso às vezes significa ler o formulário, outras vezes significa ler do banco.


class Action ... {
 
@Inject MySystem system;

// chamado quando o usuario invoca a ação X
 ActionForward 	executaActionX( ... ) {

   // obtém tabela do request ou do banco 

     Tabela t = ... 

   // invoca serviço

     system.doX(t) 

}
}

class MyServiceImpl implements MyService {

   @Inject TabelaDao dao;

    @Transaction
    public void doX(Tabela t){
       // faz Alguma Coisa Que Altere o estado de t conforme X
       dao.alterar(t);
   }

    @Transaction
    public void doY(Tabela t){
       // faz Alguma Coisa Que Altere o estado de t conforme Y
       dao.alterar(t);
   }

}

A ideia é que nenhuma logica existe no action excepto a que é relativa a manipular response e resquest.
A maior parte das vezes isso significa criar objetos com base no request e colocar alguma coisa no contextos ( session, sobretudo)

Tudo o resto é movido para uma classe intermediária o Service. O Service pode usar o DAO se necesário para perservar informações.

Um serviço pode conter vários métodos , um para cada acção. As acções do seviço devem ser relacionadas em algum contexto. Vários serviços podem ser usados conforme for necessário.
@Inject é apenas para indicar que o objeto real é injetado de alguma forma ( manualmente ou via lagum DI Container)
@Transaction é apenas para indicar que o método vai acontecer dentro de uma transação.

A action é só um porto ( coisas chegam e saiem) mas sem nenhum logica da aplicação. Tudo o testo está além do serviço. Se um dia vc tiver que usar essa logica numa aplicação que não use Action, não terá que reescrever a logica de negocio.

[quote=pcalcado]
Claro que se o repositório contiver regras você usará uma classe numa linguagem como Java, o que eu ainda não vi foi um motivo para um Repositório ter regras de negócio. É uma possibilidade, pode acontecer, mas eu nunca vi.[/quote]

Eu também não acho natural ter regras de negócio no repositorio. Por isso interface costuma ser de bom tamanho pra mim.

[quote=cmoscoso]
Eu também não acho natural ter regras de negócio no repositorio. Por isso apenas a interface costuma ser de bom tamanho.[/quote]

Se o objeto que vc chama de repositorio não contém regras de negocio ele não é uma implementação do padrão Repositorio. Vc pode chamar esse seu objeto de repositorio mas fica confuso… vc não chama seu DAO de Façade ou Mediator, pois não ?

“Regra de negocio” é algo muito vago. Um repositorio interage com um tipo especifico de regra de negocio: a estrutura de realções entre as entidades do modelo. Ele faz isso para simplificar a vida do resto dos objetos do dominio e para aumentar a eficiencia das consultas ao banco. Ou seja, se escrever SQL for considerado uma regra de negocio, então o repositorio tem obrigatoriamente que conter regras de negocio, mesmo que o SQL seja escrito indirectamente através de objetos (como os criteria do Hibernate).
Se escrever SQL não for considerado regra de negocio, suponho que a mesma frase possa ser usada em vários dominios … hummm… isso parece impossivel , ergo escrever SQL tem que ser considerado regra de negocio

[quote=pcalcado]Daniel, leia o livro e tire suas conclusões. Mais de uma vez no GUJ os conceitos de Repository e outros padrões de Domain-Driven Design foram descritos como se fosse a maneira "certa"e um pequeno quote de um livro desmentiu isso. O livro em questão sequer fala em interfaces, qualquer conclusão do que é certo ou errado, seja lá o que isso signifique, é feita por alguém que não Eric Evans.

Na verdade, o livro não diz sequer como o Repositório interage com a base de dados. Ele cita alternativas mas na descrição mostra o Repositório interagindo diretamente com a base de dados. Porque isso? por que usar Repositorio não implica em usar DataMapper/DAO. Segundo o livro você deve adaptar o padrão (aliás, todos os padrões) à sua relidade tecnológica. Evans cita o uso de Entity Beans (EJB 2.x) como Aggregate Roots, por exemplo.

Um repositório é um conceito, como você modela o conceito depende da linguagem/plataforma em questão.

E Orientação a Objetos básica não fala de interfaces, interfaces existem apenas em algumas linguagens. Quando alguém depende de uma interface ele depende de algo que se comporta de uma maneira X, não importa quem. Suponha que você tenha uma interface:

interface A{

 void a1(String asdf);
 String a2()
}

E uma classe:

class B{
 public void a1(String asdf){/* ... */ }
 public  String a2(){/* ... */ }

}

É mais que claro que a classe B obedece o contrato exposto em A, logo não há porque criar uma classe C:

class C implements A{
 B b;

 public void a1(String asdf){b.a1(asdf); }
 public  String a2(){ return b.a2();}
}

Isso não é sequer purismo, é desconhecimento sobre o que é uma interface e onde ela encaixa no paradigma e, principalmente, sobre Domain-Driven Design.

Claro que se o repositório contiver regras você usará uma classe numa linguagem como Java, o que eu ainda não vi foi um motivo para um Repositório ter regras de negócio. É uma possibilidade, pode acontecer, mas eu nunca vi.[/quote]

Ok philip, vou ler o livro e tirar minhas conclusões, estas discussões são interessantes, só que a divergência de conceitos está muito grande só mesmo o livro para esclarecer melhor.

Valeu

Nem imagino como você chegou a essa conclusao…

Escrever SQL não é regra de negocio (juro que tentei mas não entendi o resto).

Como já disse na primeira página, eu prefiro compor em um Repository um DAO, do que simplesmente implementar… justamente pq acho que o papel de um DAO é abstrair em que banco você persiste os dados e o de um repository é abstrair “persistir os dados”. Como as motivações são diferentes eu prefiro não misturar as coisas.

Contudo, mesmo assim tbm extraio uma interface deste repository (cuja implementação não é um DAO), para me dar flexibilidade quanto a possíveis estratégias (onde vou validar a autenticacao de um usuario, quem conhece o username e a password, um DAO, um LDAP ou um WebService?).

Esta é uma maneira que tem me atendido, mas não é regra. Em “Applying Domain-Driven Design and Patterns” Jimmy Nilson demonstra o repository como abstração simples por interface de um DAO implementado com NHibernate, talvez como muitos daqui tbm tem feito…

PS: A clausula “WHERE” de qualquer query é modelada em face a alguma restrição que o negócio deseja impor. Logo, pra mim tbm é regra de negócio. Não vejo mal em dizer que repo possa ter regras.

Tudo em um sistema é movido à regras de negócio, o ponto é onde a abstração modela o domínio e onde não. Quando você vai salvar um relatório em disco numa estrutura /home/pcalcado/reposts/<ano>/<mes>/relatorio-mensal.csv isso é uma regra de negócio, assim como o WHERE. O ponto é que isso não faz parte da abstração do domínio, como o WHERE não faz, logo de Domain-Driven Design nao tem nada.

Não disse que é isso é modelado pela abstração, disse que a implementação de uma cláusula é variável de acordo com o negócio, o que não deixa de ser.

Então você considera tb controles de interface do usuário como regra de negócio?

Depende, se você utiliza BPM no controller ou validadores sim.

Eu tava pensando em botões, textfields, tabelas; seguindo seu raciocionio a logica de interface também seria regra de negócio.

E qual seria esta regra?

Assim como SQL as telas são criadas de acordo com as regras de negócio, não sãi criadas aleatoriamente. Nem por isso GUIs são consideradas locais apropriados para regras de negócio.

Exato, esse é o meu ponto. TUdo é derivado de regra de negócio mas isso Não singinifica que regra de negócio está em tudo.

SQL é uma DSL que contém regras para recuperar e gerenciar dados de um SGBD, o que nada tem haver com UI, qualquer comparação com isso não faz o menor sentido. A linguagem específica indica para seu domínio condições para manipulaçoes destes dados.
Em um sistema que utiliza bancos de dados, restrições são desenvolvidas para recuperação estes dados. Tais restrições são fomentadas pela necessidade que o negócio impões, eles precisam ser codificados nesta DSL do SGBD.

Uma vez que a regra é mapeada para a linguagem do banco de dados relacional, ele contem esta regra. Isso é, se vocês considerarem que as assinaturas de um repositório são regras…

[quote=Lezinho]SQL é uma DSL que contém regras para recuperar e gerenciar dados de um SGBD, o que nada tem haver com UI, qualquer comparação com isso não faz o menor sentido. A linguagem específica indica para seu domínio condições para manipulaçoes destes dados.
Em um sistema que utiliza bancos de dados, restrições são desenvolvidas para recuperação estes dados. Tais restrições são fomentadas pela necessidade que o negócio impões, eles precisam ser codificados nesta DSL do SGBD.

Uma vez que a regra é mapeada para a linguagem do banco de dados relacional, ele contem esta regra. Isso é, se vocês considerarem que as assinaturas de um repositório são regras…[/quote]

HTML é uma DSL que contém regras para desenhar uma tela, o que nada tem a ver com SGBD, qualquer comapração com isso não faz o menor sentido. A linguagem indica para seu domínio condições apra manipulaçãod estes domínios. Em um sistema que utiliza front-end em HTML, restrições são desenvolvidas para exibição destes dados. Tais restrições são formentadas pela necessidade que o negócio impõe, eles precisam ser codificados nesta DSL do browser.


Resumo: o que você falou se aplica para ambos. Ninguém está comparando SQL com front-end, acho que é ingenuidade sequer cogitar isso, mas sim o fato que ambos são derivados de regras de negócio, não contenedores destas.