DAO/Repositorio dentro ou fora do objeto?

Por que vc diz que é gambiarra o código abaixo? (Pode até ser, a discussão é sobre isso mesmo)


usuário.pontua(outrousuario, nota);


// usuário 

public class Usuario {

   public void pontua ( Usuario outro, int nota){
          usuarioDao.pontua(this.id, outro.id, nota);
  }

}

Minhas opções são chamar o DAO diretamente na camada de serviço OU chamar o DAO indiretamente por dentro da entidade, o que vc diz ser gamb.

Atualmente eu faço a primeira, mas nesse tópico mesmo sugeriram a segunda porque fica mais OO.

[quote=saoj]Por que vc diz que é gambiarra o código abaixo? (Pode até ser, a discussão é sobre isso mesmo)


usuário.pontua(outrousuario, nota);


// usuário 

public class Usuario {

   public void pontua ( Usuario outro, int nota){
          usuarioDao.pontua(this.id, outro.id, nota);
  }

}

Minhas opções são chamar o DAO diretamente na camada de serviço OU chamar o DAO indiretamente por dentro da entidade, o que vc diz ser gamb.
[/quote]

são gambiarra no sentido de estarmos colocando responsabilidade no objeto usuário que não lhe pertence apenas para pode esconder a chamada a um outro método. O usuário acaba fazendo o papel de um Façade em vez de um Entity. Isso é gambiarra do ponto de vista de orientação ao dominio. Já tinhamos estabelecido que o seu problema é em um sistema orientado a banco de dados. Nesse caso não se aplica a regra da responsabilidade, mas acho que a do Façade se aplicaria. Ou seja, continua sendo gamb porque está atropelando o principio de separação de responsabilidade. Contudo, num sistema orientado a banco vc pode usar o ActiveRecord com DAO e desse ponto de vista é aceitável.

O objetivo não é criar uma interface fluente, o objetivo sempre é respeitar o SoC o máximo possivel.

[quote=tnaires][quote=sergiotaborda]O codigo abaixo é válido

Bacana isso aqui. Poderia ficar ainda mais bonitinho:

[/quote]

Não é a mesma coisa. Vc estaria criando um Builder para retornar de pontua() com o método comNota(). Não ha ganho nisso já que nenhum outro método existiria nesse builder.

É mais trabalho por nenhum proveito…

Se houvessem outras opções até que poderia ser mais interessante essa abordagem.

[quote=Gerson][quote=sergiotaborda]
Agora, no Value Object vc já está forçando a barra. O BigDecimal é um Value Object. Ele não contem nenhuma ação sobre o sistema. Um Value Objeto, por definição, só contém acções sobre si mesmo (add, multiply, etc… são acções sobre o proprio objeto)
[/quote]

Você leu alguma literatura sobre DDD mesmo?
[/quote]

Eu poderia responder a isso, mas a pergunta já insulta o meu esforço então é isso…
Quem entendeu entendeu e que não entendeu , pergunte a quem entendeu. Ou procure nos livros…

.oO( Se livros dissessem tudo não haveriam foruns nem inovação já que os livros so transcrevem o que já se sabe antes deles serem escritos… )

[quote=saoj]Por que vc diz que é gambiarra o código abaixo? (Pode até ser, a discussão é sobre isso mesmo)


usuário.pontua(outrousuario, nota);


// usuário 

public class Usuario {

   public void pontua ( Usuario outro, int nota){
          usuarioDao.pontua(this.id, outro.id, nota);
  }

}

Minhas opções são chamar o DAO diretamente na camada de serviço OU chamar o DAO indiretamente por dentro da entidade, o que vc diz ser gamb.

Atualmente eu faço a primeira, mas nesse tópico mesmo sugeriram a segunda porque fica mais OO.

[/quote]

Considerando que você não está falando de Repository (DDD), o problema em fazer o acesso direto ao DAO através de um Entity é que este não deve saber que, por uma limitação da tecnologia (memória), é necessário armazenar/recuperar os objetos em/a partir de um mecanismo de persistência como o banco de dados. É preciso lembrar que o banco de dados, idealmente, deve ser utilizado para suportar a persistencia de objetos, e não para complementar os dados que a sua aplicação usa e os objetos de domínio nem se quer tem conhecimento deles… um teste seria verificar quantos dados você armazena no banco que seus objetos do domínio não os conhecem.

Complementando com DDD, é por isso que o Repository, que deve ter um nome associado ao ubiquitous language, vem criar um certo tipo de indireção para dar a ilusão de que os objetos estão em algum ‘deposito’ de objetos em memória. A implementação do Repository, por sua vez, pode ser um DAO (diretamente, ou através de um strategy (GoF), por ex.). Nesse caso, um Entity, por ex., que é um dos responsáveis por expressar o modelo em DDD, poderia sim ter acesso ao repository para, por ex., buscar algo. Por isso, conceitualmente, Repository é bem diferente de DAO (as pessoas, normalmente, não querem saber de conceitos, e justificam que são iguais só porque a implementação é parecida… infelizmente).

[Editado:]
Como o Philip Calçado já disse algumas vezes aqui no fórum, embora seja possível um entity acessar o repository (= não viola DDD), normalmente o service costumar fazer isso. E, como já disse no inicio dessa thread, o service tem caracteristicas que facilitam bastante o acesso a um repository sem precisar tornar a aplicação muito complexa (ex. uso de AOP).

Num caso simples como esse, isso não viraria um jogo de empurra?

Alguém pede pro Usuário pontuar
Usuário pede pro serviço atualizar
serviço pede pro repositório atualizar
repositório pede pro DAO(?) atualizar
DAO(?) acessa o banco e atualiza.

A partir de que ponto/tamanho/requisito o sistema passa a colher as vantagens de ter um serviço e um repositório no meio?

Num caso simples como esse, isso não viraria um jogo de empurra?

Alguém pede pro Usuário pontuar
Usuário pede pro serviço atualizar
serviço pede pro repositório atualizar
repositório pede pro DAO(?) atualizar
DAO(?) acessa o banco e atualiza.

A partir de que ponto/tamanho/requisito o sistema passa a colher as vantagens de ter um serviço e um repositório no meio?[/quote]

Resumiu de forma excelente o problema. Deixar tudo separadinho é muito elegante, mas um pé no saco. Se amanhã o seu sistema virar distribuído, concordo que já vai estar tudo prontinho e certinho. Mas talvez eu prefira assumir o risco de que o meu serviço nunca será distribuído e quem quiser falar com ele terá que faze-lo via HTTP. Ou que se amanhã alguém quiser falar com ele via RPC eu codificarei essa parte, reaproveitando o código web ou não. Para uma aplicação web, um site por exemplo, acredito que assumir isso seja plenamente viável. Mas, como tudo na vida, é um risco que vc tem que estar disposto a assumir em prol da praticidade e falta de burocracia inicial. Como sempre tb, vai depender do projeto, do prazo, da equipe, do budget, blah, blah, blah, etc.

Desculpem-me: mas até agora não vi ninguém sugerindo a criação de uma camada de aplicação. O que foi sugerido é a utilização do padrão Service que é citado no livro do Evans (DDD). Então as sugestões dadas aqui não estariam adicionando este empurra empurra que vocês estão falando.

Resumidamente o padrão service é usado quando precisamos criar uma regra de negócio que não combina com nenhuma entidade ou que faz uso de várias entidades para resolvê-lo.

Num caso simples como esse, isso não viraria um jogo de empurra?

Alguém pede pro Usuário pontuar
Usuário pede pro serviço atualizar
serviço pede pro repositório atualizar
repositório pede pro DAO(?) atualizar
DAO(?) acessa o banco e atualiza.

A partir de que ponto/tamanho/requisito o sistema passa a colher as vantagens de ter um serviço e um repositório no meio?[/quote]

Esse fluxo não é bem assim…

Colocarei um outro exemplo aqui de um service. Esse domain service (que, como o nome diz, está no domain layer) pode ser chamado por qualquer objeto do application layer como um ‘application service’. A regra de autenticação está no domain service! Ótimo, pois ele não fica na camada de aplicação… aliás, essa camada existe exatamente para isolar o domínio.
Um application service serve apenas para coordenar tarefas… funciona como um façade, pois ele sabe para quem delegar, e sabe também a ordem em que as coisas são executadas. É que nem um gerente.

public class AutenticacaoServiceImpl implements AutenticacaoService {

    private MessageDigester messageDigester; // DI...
    private UsuarioRepository usuarioRepository; // DI...

    public Usuario autentica(String nomeLoginInformado, String senhaInformada) {
        Usuario usuario = buscaUsuarioPorEmail(nomeLoginInformado);
        validaSenhaInformada(nomeLoginInformado, senhaInformada, usuario);
        return usuario;
    }

    private void validaSenhaInformada(String nomeLoginInformado, String senhaInformada, Usuario usuario) {
        String hashSenhaInformada = messageDigester.hashDe(senhaInformada);

        if (!hashSenhaInformada.equals(usuario.getSenha())) {
            throw new ...;
        }
    }

    private Usuario buscaUsuarioPorEmail(String nomeLoginInformado) {
        return usuarioRepository.buscaPorEmail(nomeLoginInformado);
    }
}

Obs.: Lembre-se de que existem várias forma de implementação do domain layer que pode estar compatível com a prática de DDD… DDD não é um pattern de implementação… pra pratica-lo bem é necessário entender bem os conceitos, porque é isso que vai dizer se a sua implementação está dentro deles. Sem entender os conceitos e seus objetivos, naturalmente, não vai encontrar grandes vantagens e vai acabar se tornando um jogo de empurra mesmo. Uma outra coisa importante também é lembrar que ao redor de tudo isso está o ubiquitous language…

[quote=sergiotaborda]Não é a mesma coisa. Vc estaria criando um Builder para retornar de pontua() com o método comNota(). Não ha ganho nisso já que nenhum outro método existiria nesse builder.

É mais trabalho por nenhum proveito…

Se houvessem outras opções até que poderia ser mais interessante essa abordagem.[/quote]
O ganho aqui foi em expressividade do código. A sentença ficou mais natural que a primeira, e o trabalho extra não é tão grande assim… Além disso, outros métodos poderiam complementar o Builder ( a não ser, claro, que Pontuacao tivesse apenas os atributos pontuado e valor da nota ).

[EDIT]
Concordo que esse ganho é muito subjetivo. Não estou exatamente questionando sua opinião, estou apenas traçando um paralelo entre a linguagem Java e a língua portuguesa:

usuario.pontua(outroUsuario).comNota(10);

“Usuário pontua outro usuário com nota 10”.

[/EDIT]

Tudo bem.

O usuário logado no sistema seleciona um outro usuário a partir de uma lista, dá uma pontuação para ele, de zero à cinco estrelas, e clica no botão pontuar.

Servlet recebe a requisição, e chama o Model.

Model será representado por um serviço que valida os dados e chama um repositório?

Fluent Interfaces, pelo menos em Java, são um saco pra implementar. Expressividade tem um custo.

Tudo bem.

O usuário logado no sistema seleciona um outro usuário a partir de uma lista, dá uma pontuação para ele, de zero à cinco estrelas, e clica no botão pontuar.

Servlet recebe a requisição, e chama o Model.
[/quote]

O servlet (ou melhor, uma action/controller) chama um servico do application layer (‘service layer’, no PEAA). O application layer serve para você colocar o que o fowler chama de ‘lógica de aplicação / workflow logic’ (para diferenciar da lógica de domínio que deve ficar na camada de dominio, isto é, você isola a camada de domínio). Os serviços da ‘camada de aplicação’ funcionam como façades que você pode usar para representar os casos de usos do seu sistema. Além disso, é um ótimo lugar para demarcar o inicio e o fim de uma transação. Novamente, o importante é que nessa camada não tenha lógica de domínio, pois ela deve ficar totalmente na camada de domínio (que é aonde o DDD foca).

Sim, um conceito do domain model pode ser expresso atavés de um serviço que valida os dados (lógica de domínio) e, se necessário, poderia chamar um repositório para recuperar uma instância que representa o root de algum aggregate, por ex. É importante que todos esses conceitos estejam em torno do ubiquitous language, pois, sem isso, você está aplicando bons patterns apenas, mas não está praticando DDD.

[quote=Bruno Laturner]

Fluent Interfaces, pelo menos em Java, são um saco pra implementar. Expressividade tem um custo.[/quote]

Expressividade através de fluent interfaces tem um certo custo mesmo. Mas tem milhares de outras formas simples de tornar o código expressivo… recomendo um livro bacana chamado Clean Code (do conhecido Robert Martin), lançado recentemente… muito bom.

[editado:]
Costumo dizer que os serviços do application layer são como gerentes que não sabem como executar as atividades, mas sabem para quem delegar, e, também, sabem especificar a ordem em que essas atividades devem ser executadas.

É essa camada de façades (UserFacade, UserService ou UserLogic) que confesso que me incomoda um pouco. Entendo e concordo que é o mais certo a se fazer, pois separa bem a action e a parte web das regras de negócio. Sempre fui por esse caminho mas to meio que cansado e agora estou deixando a action fazer tudo. Se o framework for pouco intrusivo dá para testar e até distribuir depois se for o caso.

Mas isso não tem haver com o topico, que eu mesmo iniciei e disvirtuei um pouco para um assunto que me pareceu igualmente interessante. Quanto a questao do tópico, ainda não consegui chegar a uma conclusão, mas acho que por enquanto vou continuar acessando o DAO/Repositorio fora da entidade mesmo.

Tem um custo que na maioria das vezes eu estou disposto a pagar, em prol da expressividade :smiley:
Mas isso é uma opinião minha.

Uma coisa é certa, usuarioDAO não pontua (ou não deveria) pontuar ninguém…

Está bem confusa essa thread. Eu pensei que o Serviço fazia coisas que não fosse de responsabilidade especifica de ninguem do domain layer… mas utilizando os componentes dele para se chegar a um objetivo em comum

[quote=peerless]

Está bem confusa essa thread. Eu pensei que o Serviço fazia coisas que não fosse de responsabilidade especifica de ninguem do domain layer… mas utilizando os componentes dele para se chegar a um objetivo em comum[/quote]

Sim. Isso é o que um Service faz. Seja de que camada for. Ele não é um delegador de responsabilidade,ele tem a responsabilidade
de orquestrar os outros objetos da sua camada. Em particular , no dominio, ele orquestra entidades, repositorios, e/ou outros serviços.

[quote=Gerson]Defina-o… é muito fácil decidir usar isso como um critério só porque você quer. Aliás, um entity "tem uma ação sobre si mesmo" (usando seu termo vago), então o sistema não é alterado? Confuso, não acha?

Bom, quando você definir melhor o que inventou, aí podemos conversar sobre isso.

[/quote]
:arrow:Entidade(entity) :arrow: Beans de sessão sem informações de estado “tem uma ação sobre si mesmo”

[quote=sergiotaborda][quote=peerless]

Está bem confusa essa thread. Eu pensei que o Serviço fazia coisas que não fosse de responsabilidade especifica de ninguem do domain layer… mas utilizando os componentes dele para se chegar a um objetivo em comum[/quote]

Sim. Isso é o que um Service faz. Seja de que camada for. Ele não é um delegador de responsabilidade,ele tem a responsabilidade
de orquestrar os outros objetos da sua camada. Em particular , no dominio, ele orquestra entidades, repositorios, e/ou outros serviços.[/quote]

Serviços de qual camada? Como eu já disse anteriormente, os serviços da camada da aplicação (Application Layer / ServiceLayer) não devem conhecer lógica de domínio. Agora, os serviços da camada de domínio sim, devem conhecer. A camada de aplicação existe principalmente para isolar a camada de domínio, de forma que fique bastante claro aquilo que realmente tem a ver com lógica de domínio e lógica de aplicação/workflow.

Sobre a analogia que eu fiz dos gerentes, como eu já disse também, ela se aplica aos serviços da camada de aplicação. É uma forma de pensar para que fique claro que lógica de domínio deve ficar na camada de domínio (Domain Layer), em outras palavras, os serviços da camada de aplicação devem delegar tudo que estiver relacionado com lógica do domínio para a camada de domínio.

[Editado:]
Tinha esrcito ‘Application Service’ no lugar de ‘Service Layer’ (PEAA)…

Senhores,

estou estudando e lendo o livro do Evans. Acompanhei essa thread desde o início e aproveitando o gancho que esta mudou um pouco o foco da discussão gostaria de confirmar algumas coisas. Está certo, dentro do contexto do DDD, a responsabilidade das camadas abaixo?

Responsabilidades:

1) Application Layer:

  • Gerenciamento do fluxo da aplicação
  • Demarcação de transação
  • Logging
    [b]
  1. Domain Layer[/b]

2.1) Objetos do domínio
- Gerenciam o estado e comportamento de suas proprias entidades e seus agregados
- Podem referenciar repositorios para gerenciar seu estado e/ou implementar seus comportamentos

2.2) Service Layer
- Quando presente, serve para gerenciar/implementar uma regra de negócio que envolve mais de uma entidade
- Referenciam repositorios

3) Persistence Layer
- Implementação dos Repositorios