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

52 respostas
MauricioAniche

Pessoal,

Estou começando agora no DDD, e esse é meu primeiro projeto tentando usar os conceitos… Talvez a dúvida seja boba, mas, vamos ver! :slight_smile:

Bom, eu tenho a seguinte regra de negócios… Tenho TABELAS DE PREÇO que variam mensalmente, ou seja tenho a tabela1 do mês 01/2008, 02/2008, e assim por diante…

Minha dúvida é: Como devo carregar essa tabela? Se pensarmos em banco de dados, tenho 2 tabelas relacionadas… TabelaDePreco e ValoresDaTabela.

Minhas classes estão mais ou menos assim:

public interface TabelaRepository {

Tabela pegaPorId(int id) throws SQLException;

List pegaValores(int tabela, int mes, int ano) throws SQLException;

}
public class Tabela {

private String nome;

private List valores;

// getters and setters!

public Tabela() { valores =new LinkedList(); }

public void carregaValores(int mes, int ano) {

setValores(repositorio.pegaValores(getId(), mes, ano));

}

}

E aí no meu Struts Action, eu faço algo do tipo:

Tabela t = repositorioTabelas.pegaPorId(id);
t.carregaValores(01,2008); // para carregar janeiro!

Estou pensando corretamente?

O que vocês sugerem?

Acabou de me vir na cabeça, que o cliente da loja nunca abre uma tabela sem mês ou ano definido (afinal pra ele, tabelas sem mês ou ano não existem, correto?). Então minha busca de tabelas, além do ID, eu devo passar mes e ano obrigatoriamente?

Conseguiram entender? :wink:

Grato,
Mauricio

52 Respostas

sergiotaborda
  1. Repositorios não lançam SQLException!
  2. Repositorios não são interfaces!

O que vc quer é trabalhar com dados que dependem da data. Isso é algo comum e para resolve isso vc cria um método passando a data.

Simplesmente faça assim

public class TabelaRepository {

  Tabela pegaPorId(int id) {
          
         //  executa SQL
         Tabela  t = ...
         t.valores = pegaValores(t, new Date()); // pega os mais atuais
         return t
           
  }

  List<ValorTabela> pegaValores(Tabela tabela,  Date date){
           // executa SQL

  }
}

public class Tabela {
  private String nome;
  List<ValorTabela> valores;

  // getters and setters!

  public Tabela() {  }

  private Tabela(Tabela other) {  
   // construtor de copia. 
  // copia todos os atributos da tabela other para uma nova tabela
  }

  public Tabela valueAt(Date date) {
    Tabela t =  new Tabela(this) ;
    t.valores = repositorio.pegaValores(this, date);
    return t; 
  }
}

Desta forma vc obtem a tabela com os preços atuais por default. Se em algum ponto vc precisa das tabelas anteriores vc pode fazer isso executando valueAt()
Use Date ou um outro objeto ( No seu caso um MonthOfYear seria melhor mas pode usar Date com o dia setado em 1). Isso aumenta a segurança do seu codigo e a legibilidade.

MauricioAniche

Oi Sérgio,

Eu coloquei meu Repositorio como interface, pois pelo que vi em todas as discussões aqui, um DAO deve implementar um Repositorio…

Então eu tenho um iBatisDAO que extende meu Repositório… Não usei injeção de dependência pq o projeto é muito simples, acabei usando um factoryzinho básico…

Entendi que não posso fazer ele lançar SQLException já que a exceção está ligada à um banco de dados… Mas posso fazer ele lançar um RepositorioException, certo? Afinal, falhas podem ocorrer, eu devo tratá-las!

Entendi sua abordagem, foi o que coloquei no final da minha msg!

Acrescentando mais uma dúvida:

Eu preciso deletar um item ali na lista de itens… É um projeto web, e você sabe que o máximo que eu posso fazer é passar o ID do item a ser excluido… Minha solução, veja se você concorda:

class Tabela {

public ItemTabela deletaItem(int id) {

for(ValorTabela it : getValores()) {

if(it.getId()==id) {

getValores().remove(it);

// exclui do repositorio

repositorio.deletaItem(it);

}

}

}

}

Repare que eu chamei a função de deletar do repositório dentro da função. Como o pcalcado disse em outros posts, e não me recordo exatamente das palavras, mas a idéia era que ter que pedir pro repositório excluir é uma ‘falha’, mas somos obrigados a excluir de alguma forma o item do banco de dados…

Vocês concordam com o código acima?

Desculpem pelas perguntas tão ignorantes, mas é só pondo a mão na massa que se aprende! :slight_smile:

[]'s
Mauricio

Alessandro_Lazarotti

Um DAO deve abstrair em qual banco de dados vc guarda os dados, esta é a motivação do padrão. Ele não precisa necessariamente implementar um repositório, embora possa tbm ser implementado desta forma. Particularmente eu prefiro compor um Repositório com um DAO, do que implementa-lo com um.

MauricioAniche

Alessandro,

Então seu repositório é algo parecido com:

class Repositorio {
private Dao dao;

public Elemento pegaPorId(id) { return dao.pegaPorId(id); }
}

Você assim não acaba apenas repassando o comando pro teu DAO? Qual a vantagem de compor o repositório com o DAO?

[]'s
Mauricio

Alessandro_Lazarotti

Qual a API uso para persistir ou consultar meus dados abaixo?

class RepositorioX{

	@In
	DAO dao;	

	public void adiciona(X objetoX){
	    dao.persist(x);	
	}

	public X buscaXPorNome(String nome){
		
		dao.query.buscar(X.class,new Restricao[]{"nome",nome})	
	}

}
sergiotaborda

MauricioAniche:
Oi Sérgio,
Eu coloquei meu Repositorio como interface, pois pelo que vi em todas as discussões aqui, um DAO deve implementar um Repositorio…

hum… procurar no guj é legal, mas procure tb fora dele …

Repare na contradição logica : um DAO extend um Repositorio.
“Extend” significa “é um”. Vc está dizendo que “DAO é um Repositorio” … humm meio inutil ter dois nomes para a mesma coisa… Se é um DAO deve extender DAO , se é um Repositorio deve extender Repositorio

O que é mais logico

class iBatisDAO  extends Repository

// ou

class iBatisDAO  extends DAO

E como eu disse antes, Repositorio não é uma interface. É uma classe.
Vc faz um e usa sempre o mesmo
DAO é uma interface. Vc faz um, mas no futuro pode fazer outro e ter dois.

certo. Pode ser algo mais geral como PersistenceException.

cof cof… isso é minimo, não o máximo. Vc pode passar o objeto a ser excluido

Esse código está meio confuso. Porque eu gostaria de remover um Valor da tabela ?
E porque eu gostaria que isso se refletisse automáticamente no banco ? E se eu quiser me arrepender ?

uma opção

class Tabela {
  public ItemTabela remove(ItemTabela item) {
        return valores.remove(item);
  }
}

class DAO {

   public void altera (Tabela tabela){}

}
MauricioAniche

Oi Sérgio,

Eu não procuro apenas no guj… O GUJ aliás, comecei a ler há alguns dias quando um amigo me disse que haviam bastante pessoas de DDD discutindo lá! :slight_smile:

Eu usei a palavra errada. No meu caso meu DAO implementa Repositorio (já que ele é uma interface)… Mas entendi e concordo com vc!

Sim, é o mínimo (de novo me expressei mal), mas o usual é mesmo passar o id do elemento que você quer apagar. Não sei como fazer em Java, para que de uma forma fácil ele guarde o objeto e recupere na hora do post. Em .NET (na qual eu conheço um pouco mais) eu usaria ViewState ou até mesmo o framework MindLib para isso.

Pq eu apagaria o objeto naquele momento? Não sei, regra do cliente… A minha dúvida era se eu poderia chamar o repositório para operações de altera(), deleta(), etc, de dentro do domínio, do jeito que eu fiz!

[]'s
Mauricio

sergiotaborda

“poder” vc pode. “dever” vc não deve.
Alterações do estado do sistema devem estar dentro de uma transação , de um processo. Senão vira uma zona…

MauricioAniche

Sérgio,

Entendi, na teoria. Na prática, como implemento esse processo?

[]'s
Mauricio

sergiotaborda

MauricioAniche:
Sérgio,

Entendi, na teoria. Na prática, como implemento esse processo?

Existem várias formas.

)chamar o DAO directamente (TabelaDAO.alterar(tabela)). Este é o mais usual. Parte-se do principio
de que quem executa este codigo está dentro de uma transação. Se não estiver usa-se outro método

) chamar um método em um serviço especial
(TabelaService.altera(tabela)) isso é normalmente usado quando a lateração da tabela tem outras impliações.
Por exemplo quando vc guarda uma conta bancária vc quer inicializar o saldo dela criando um registro em outra tabela. O facto de usar um serviço ( na realidade um método) vc pode injetar o controle transacional dentro dele ou (em ambiente JEE) em torno dele.

) seguir o padrão UnitOfWork. Aqui vc cria uma classe (unidade de trabalho) que tem um método execute() por exemplo. Vc inicializa essa classe com os parametros necessários ao funcionamento. No caso a tabela. Ai vc envia para um executor de trabalho (WorkExecutor). Esse objeto irá iniciar a transação, executar a sua unidade de trabalho e finalizar a transação. Em opção ele pode ainda controlar concorrencia ( não pode executar duas unidades de trabalho da mesma classe ao mesmo tempo). Exemplo

class TabelaUnitOfWork extends UnitOfWork
Tabela tabela;
public TabelaUnitOfWork(Tabela tabela){
  this.tabela = tabela;
}

public void execute(){

   TabelaDao dao = .. 
   dao.alterar(tabela);
}

Os dois ultimos mecanismo são especialmente utilizados onde ha mais coisas a fazer que simplesmente gravar no banco. Nesses casos utiliza-se o primeiro. Mas sempre tendo em atenção que o codigo é chamado dentro de uma transação.

Não sei se respondi a pergunta…

pcalcado

Cuidado com os “certos” e “errados”.

Não existe QUALQUER problema em um Repositório ser apenas uma interface se ele não possuir lógica. Uma interface é um contrato, implementar uma interface diz que o objeto implementa o contrato. Interfaces não são hierarquias.

rodrigoy

Tirou palavras da minha boca. (essa thread pode ficar ferrenha)

danielbussade

Olá galera, cada vez que leio um tópico sobre DDD fico mais confuso, uns falam que pode ser uma interface caso não tem lógica de negócios nenhguma, o que concordo totalmente, mas dizem também que no máximo pode ser uma classe abstrata, mas nunca uma concreta. Mas de acordo com a definição do sergiotaborda Repository, seria uma classe concreta, então no Padrão Repository criado por MartinFowler o Repository seria o que afinal??

Att

dreampeppers99

Gostei desse modo, assim ainda tira a “preocupação” de como instânciar o repositório…

:smiley:

sergiotaborda

danielbussade:
Olá galera, cada vez que leio um tópico sobre DDD fico mais confuso, uns falam que pode ser uma interface caso não tem lógica de negócios nenhguma, o que concordo totalmente, mas dizem também que no máximo pode ser uma classe abstrata, mas nunca uma concreta. Mas de acordo com a definição do sergiotaborda Repository, seria uma classe concreta, então no Padrão Repository criado por MartinFowler o Repository seria o que afinal??

Eu não defini nada. Eu segui a definição do Fowler ( http://www.martinfowler.com/eaaCatalog/repository.html )
Se a página não é suficiente, leia o livro. (lá tem assim “the repository” = “o repositorio” , “o” é diferente de “um”. Por outro lado “the repository” não chama nenhum “repository implementation”)

Como se sabe se algo tem que ser interface ou classe ? Algo é uma classe quando outros do mesmo tipo não possa ser outras classes. Ou seja, se a classe X é um Cliente ele não pode ser um Produto.
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)
Utiliza-se interface quando algo pode ser aquela coisa mas tb outras. Por exemplo, Comparable , Serializable.
A classe X pode ser comparable E serializable, não ha obrigação em só um dos dois.

Isto é POO básico. Não é nenhuma filosofia esotérica…

danielbussade

Então sérgio porque o DAO poderia ser uma interface, mas o repository não??? Se eu digo que o DAO á uma interface eu estou dizendo qualquer classe pode ser DAO mas também ser outras coisas, como vc mesmo disse.

sergiotaborda

danielbussade:
Então sérgio porque o DAO poderia ser uma interface, mas o repository não???

O objetivo do DAO é vc poder criar vários um para cada mecanismo de persistencia que vc quiser.Mas vc não sabe à partida como fará a integração com esse mecanismo. Portanto, em tese, vc pode precisar extender uma classe de um API de terceiros para poder criar seu DAO. Dai o DAO ser normalmente uma interface. É uma questão relacionada à implementação desse padrão em particular. O normal seria ser uma classe abstracta já que uma classe que é DAO não é mais coisas nennhuma (salvo a exceção que já expliquei).
No caso do repositório, ele contém regras de negocio. E uma classe repositório é isso mesmo, um repositório. Não é mais coisa alguma. Como é uma classe de domínio com certeza não precisa herdar de nenhuma classe especial de terceiros. Como ela contém regras de negocio não existirão dois repositórios seria como ter duas regras diferentes para a mesma coisa… é tudo uma questão de lógica…

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??

Outra coisa em outro post você citou que a ordem correta de uma requisição WEB até o banco seria a seguinte:

Poderia explicar melhor este padrão Façade/Service, e este Factory?? Pra que eles servem?? além disso porque num processo de listagem é diferente de save?

Desculpa pelas muitas dúvidas!!

Paulo_Silveira

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? Meio estranho… mas vai saber. Pelo menos voce nao fechou portas, ou usou heranca, que seria bem pior… Se o cara diz que é uma Queue e um Map ao mesmo tempo, e realmente cumpre os dois contratos, bom pra ele…

Tem gente que vai falar que POO basico é voce programar sempre voltado a interface, mesmo no sentido Java da palavra. Muita gente é xiita e interfaceia simplesmente TODAS as classes. Pra ser sincero nao sou muito contra isso. Enfim, existem centenas de ideias, conceitos e praticas que algumas pessoas discordam, outras concordam.

Eu nao vejo problema algum em interfacear um repositorio, mas entendo o argumento do Sergio.

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.

sergiotaborda

Paulo Silveira:
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)

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?

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.

sergiotaborda

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??

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.

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);

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

sergiotaborda

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);

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.

C

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.

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

sergiotaborda

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.

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

danielbussade

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.

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

C

Nem imagino como você chegou a essa conclusao…

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

Alessandro_Lazarotti

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.

pcalcado

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.

Alessandro_Lazarotti

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.

C

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

Alessandro_Lazarotti

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

C

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

Alessandro_Lazarotti

E qual seria esta regra?

C

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.

pcalcado

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.

Alessandro_Lazarotti

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…

pcalcado

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…

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.

Alessandro_Lazarotti

Exibição de dados não são regras de negócio, são de aplicação. Existe algum pattern na camada de negócio para abstração do front-end? Uma solicitação a um repositório(camada de negócio) como “obterContasAtivas” exige uma implementação que atisfaça esta regra do negócio.


Posts acima um foi comparado com outro para chegar a conclusão de quem ambos seriam “derivados” e não contentores.

Alessandro_Lazarotti

Mas gostaria de saber Shoes, sobre a pergunta que fiz:

eu:

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…

Você considera as assinaturas do repositorio como regras pertinentes ao dominio?

pcalcado

Voce esta confundindo dominio com regras de negocio. A Camada de Aplciacao, assim como a Camada de Dominio, possui suas regras de negocio aplicadas de alguma forma. Uma interface com o usuario tem que obedecer regras de negocio da mesma maneira, o fato de nao existir uma abstracao de negocios para interface eh mera consequencia de uma arqutietura de camadas.

Na verdade, no idioma do usuario -o que vem escrito nas user stories- nao existe “obter contas ativas”, existe eh " exibir contas ativas".

Quanto a sua pergunta, pense dessa forma: java.util.List nao eh parte do meu dominio e ainda assim eu o uso para implementar minhas regras de negocio. Da mesma forma SQL nao faz aprte do meu dominio mas eu o uso para implementar minhas regras de negocio.

pcalcado

Tentando resumir: um DAO nao implementa regras de negocio, ele implementa mecanismos que as classes que implementam regras de negocio usam. 'E parte da infra-estrutura da aplicacao. Obviamente que o codigo que gera um WHERE vai estar vinculado a uma regra de engocio mas TUDO num sistema esta vinculado a regras de negocio. A criacao de uma clausula WHERE nao eh implementacao de regra de negocio, eh consequencia desta.

Alessandro_Lazarotti

No exemplo que citei a user case pode implicar em “obterContasAtivas()” para efetuar lançamento de malas diretas sobre estas. A primeira tarefa é requisito do domínio. A interface List não possui métodos para lhe retornar este requisito do domínio, mas um repositório pode ter.

Logo, se na implementação de um repository, você utiliza SQLs, EJBQLs, QueryObjects para implementar esta regra de negócio, seu repositório possui regras, conforme seu quote.

PS: [preferenciaPessoal] DAOs não implementam regras de negócio mesmo, eles apenas se comunicam com o banco. Por isso que prefiro uma implementação de Repository onde as montagem de QueryObjects(implementação da regra para consulta) estão nelas e então este o repassa para um DAO executor em outra camada se comunicar com a infra.[/preferenciaPessoal]

Alessandro_Lazarotti

Relendo seu post Shoes, acho que entendi seu ponto de vista e talvez todos aqui estão dizendo a mesma coisa. O fato é que a afirmação de repositório não conter regras de negócio é muito relativa, pois depende do que o analista observa como “regra de negócio”. Todo o sistema tende a colaborar com o dominio, dado a isso a consequencia do comportamento é refletida em todo o sistema, juntamente com o domínio.

pcalcado

Sim, eu n~ao falie que repositorio nao temr egras, falei que eu nunca vi um caso.

rponte

Uma dúvida:

Quando algumas regras de negócio se encontram em procedures/functions no banco de dados, pode-se dizer que as regras estão contidas no repositório?

pcalcado

rponte:
Uma dúvida:

Quando algumas regras de negócio se encontram em procedures/functions no banco de dados, pode-se dizer que as regras estão contidas no repositório?

Não. Nesse caso as regras estão em um sistema externo e a melhor maneira é abstrair através de um Service de fachada, creio.

sergiotaborda

Botões, textfields e companhia não são regras de negocio, mas o seu comportamento e disposição são.
A expressão “regras de negocio” é tlv demasiado limitativa. Eu me referia a requesitos.
Os controles não são requisitos em si, mas eles cooperam para atender aos requisitos.
Os requisitos dividem-se em dois grupso: funcionais (RF) e não-funcionais (RNF). Os RNF são de segunrança, arquitetura, ergomia, etc… os controles em si caem nesta area. Os RF são normalmente o que se designa por dominio em DDD mas não é uma relação 1:1.

A ideia que os repositorios contêm logica de negocio porque são responsáveis por escrever pesquisas é simples de entender. As pesquias dependem do modelo: dependem da estrutura fisica do modelo e das estrutura abstracta do modelo ( as regras ). Se existem uma tabela pessoa com uma tabela endereço associada a pesquisa é feita de uma forma, se existe apenas uma tabela, a pesquisas é feita de forma diferente. A mudança de regras de negocio , aka RF , implica na alteração das regras de pesquisas e portanto na alteração do repositorio onde essas pesquisas são criadas. É por isso que o repositorio é um elemento do dominio e não de infra. Elementos de infra não se alteram conforme os RF, apenas com os RNF. Esta diferenciação é importante porque os RNF são o que os frameworks da praça resolvem. Nenhum framework pode resolver RF (embora existam padrões especiais para alguns RF chamados padrões de aplicação). clientes pagam para que RF sejam implementadas. Normalmente eles não enxergam RNF ou os veêm juntos com RF.

O modelo por detrás dos controles depende dos RF. A famosa “o combo X muda comforme o combo Y” é um RF.

“Regra de Negocio” é um termo especial que define RF especiais. São aquelas regras que mudam conforme se muda de cliente. Clientes diferentes têm um nucleo de regras diferentes e um nucleo de regras iguais. Todas são RF, mas a evolução delas é diferente. Regras que mudam conforme a area de atuação do cliente/sistema são Regras de Dominio e aquelas que mudam de cliente para cliente na mesma area são regras de negocio.
Por exemplo , todas os comercios emitem nota fiscal e quase todos trabalham com o conceito de pedido. Isso é uma regra de dominio. No dominio das empresas de serviços à uma ordem de serviço e não um pedido. No dominio de medicina não existe pedidos, nem no de bancos.
Médicos têm historicos dos pacientes. Isso é uma regra de dominio. Como eles têm acesso a esse historico e o que o historico contém é uma regra espcifica do cliente: Regra de Negocio.
Bancos têm clientes e estes têm contas. Isso é uma regra de dominio, mas as informações que eles contêm são regras de negocio.
Regras de Negocio evoluem muito mais depressa que as de dominio (bancos não deixarão de ter contas para clientes tão cedo).

Em DDD não ha uma distinção entre este dois tipos de regras. Existe o Dominio e ponto final. Todos os RF estão no dominio ou são abordados por ele em alguma medida. Tudo o resto é RNF e é resolvido com frameworks e/ou codigo de estrtutura.

A confusão que se sente é que as pessoas confudem “CRUD” com regra de negocio , como se o ato de gravar/alterar depende-se do negocio. Isso é falso. Ele depende na realidade do processo do dominio que necessita de entidades. CRUD é uma forma de alimentar as entidades para o dominio. (Outra seria importação de dados, por exemplo). Fazer um insert não é uma regra de negocio, mas o como se faz o insert para aquele sistema em particular é. Por isso que cada sistema tem os seus inserts e dificilmente (impossivelmente) uma frase SQL usada por um sistema pode ser utilizada por outro. Acho que isso mostra obviamente que o SQL depende e expressa regras de negocio: RF que mudam de cliente para cliente.
CRUD não é uma regra de negocio, mas a implementação dele depende das regras.

Se pensarmos bem, um sistema sempre é algo que se limita a alterar um estado através de um processo. ele pode ter vários processos alterando o estado, mas tem apenas um estado. Para que o altere ele precisa consultar esse estado antes. Isto é o arroz-com-feijão de qualquer software. O estado depende das regras dos processos que são RF. O estado tem que ser preservado porque ele detêm a identidade do sistema. A preservação do estado é decorrente da existencia do proprio estado tal como a preservação da vida é decorrente da própria vida. Preservar o estado, contudo, ainda é uma tarefa em que existem RNF e RF operando simultaneamente. Comunicar com o banco via JDBC é RNF , mas o quê comunicar é RF.
DAO é o cara que se comunica, ele é um RNF e por isso ele pode ser reaproveitado. Ele transfere SQL , mas ele não cria SQL.
Repositorio contém vários RF e por isso ele não pode ser aproveitado e depende de alterações nos RF.
Exactamente por isto que existem 2 padrões e não apenas um. Exactamente por isto um pode ser definido como interface e outro não.

Tudo num sistema está vinculado a requisitos, mas nem tudo está vinculado a regras de negocio ( requisitos funcionais). É isso que diferencia arquitetura e design. Arquitetura preocupa-se apenas com requisitos não-funcionais e design preocupa-se em embutir requisitos funcionais em cima da arquitetura. Todos os frameworks que existem fazem muito, mas fazem apenas RNF. Sempre, em todos eles, existe uma ponta que o utilizador tem que extender para poder incluir RF. O DDD tem apenas a ideia de que os RF devem ser isolados completamente dos RNF de forma que possam ser reaproveitados entre várias arquiteturas. Se isso não pode acontecer, o modelo de dominio ficou “sujo” com regras de infra. Isso é errado em DDD. Aliás é errado em OO e em programação de uma forma geral. Contudo em casos reais nem sempre é possivel fazer isso. Na maiorias das vezes porque o dono do negocio não entende que ter um nucleo de dominio indepenente diminui custos em longo prazo. Ele só vê o aumento a curto prazo já que um modelo de dominio independente é muito ccomplexo de construir e essa complexidade aumenta proporcionalmente à distribuição do sistema. Pior, os desenvolvedores também ainda não entenderam este conceito.

Como saber se um objeto depende de regras de negocio ( requisitos funcionais) ?
Simples, sua implementação mudaria se as regras mudassem ?

Algums exemplos:
String : não depende
List : não depende
Comparator : depende
Entity : depende
Service : depende
RMI : não depende
Serialização : não depende, mas pode depende se necessário.
DAO: não depende. Ele apenas muda se a tecnologia de persistencia mudar.
Repositorio : depende.
Action do Struts : depende.
Servlet de Controle do Struts : não depende.
JTable : não depende
TableModel : depende.
QueryObject : não depende ( embora possa ser implementado para depender)
Specification : depende

Acho que é simples de aceitar que Repositorio contêm regras de negocio. E não depende de como se define regra de negocio já que o estado do sistema que o repositorio pesquisa é o reflexo dessas próprias regras; quaisquer que elas sejam.

rodrigoallemand

Tsc, tsc tsc… Resta saber se o Owner do tópico já entendeu a duvida ou se ele desistiu do ‘Chat’…

Paulo_Silveira

Excelente perguntinha!! Talvez eu nao concorde com alguns depende/nao-depende, mas o importante é a pergunta e o caso de cada um!!

MauricioAniche

Opa, não desisti do post não! Estou acompanhando tudo! As discussões estão me ajudando muito!

Estou terminando de ler o Nilsson, e já volto com mais dúvidas! :wink:

[]'s

Criado 24 de abril de 2008
Ultima resposta 28 de abr. de 2008
Respostas 52
Participantes 11