Dúvidas básicas DDD

Pessoal, estou tentando implementar o famoso DDD, mas surgiram algumas dúvidas, talvez devido ao fato de ter visto alguns exemplos mal elaborados e explicações vagas, mas enfim, vou tentar exemplificar.

Dividi o sistema nas seguintes camadas: Interface Usuário / Action / Service / Repositório

Para fazer simples CRUD’s tudo bem, não tive nenhuma dúvida, ficou assim:

1 - Exemplo simples!!!

[code]// crud básico
public class ClientAction {
public String saveClient() {
clientService.create(client);
return “saveClient”;
}
}

public class ClientService {
public void create(Client client) {
clientRepository.persist(client);
}
}

public class ClientRepository extends GenericRepository implements IClientRepository {
public void persist(Client client) {
entityManager.persist(client);
}
}
[/code]

Pois bem, ao chegar em problemas mais complexos, tive várias dúvidas, por exemplo:

1 - Existe algum padrão de nomenclatura? Tipo, para todos os casos de uso deve existir os métodos create(), delete(), retrieve() e update() em todas as camadas? Porque quando envolve regras de negócio e não CRUD, faz sentido o método “pedidoService.create(pedido)” (que é chamado pela Action) ter as regras de negócio dentro dele? Ou faz mais sentido chamar outro método, com outra nomenclatura, tipo “pedidoService.salvarPedidoVariasRegras(pedido)” e dentro desse método ser chamado “this.create(pedido)” ou até mesmo “pedidoRepository.create(pedido)”?

Acho que mostrando código fica mais fácil entender:

// Exemplo 1
public class PedidoAction {
    public String savePedido() {
        pedidoService.create(pedido);
        return "savePedido";
    }
}

public class PedidoService {
    public void create(Pedido pedido) {
        // regras
        // regras
        // regras
        // regras
        // regras
        pedidoRepository.persist(pedido); // ou
    }
}

// Exemplo 2
public class PedidoAction {
    public String savePedido() {
        // salvar pedidoes tem dezenas de regras
        pedidoService.salvarPedidoVariasRegras(pedido);
        return "savePedido";
    }
}

public class PedidoService {
    public void create(Pedido pedido) {
        pedidoRepository.persist(pedido);
    }
   
    public void salvarPedidoVariasRegras(Pedido pedido) {
        // regras
        // regras
        // regras
        // regras
        // regras
        this.create(pedido);
    }
   
}

2 - Uma classe PedidoService pode “conhecer” EmailService ou PedidoService deveria “conhecer” apenas EmailRepository? O que faz mais sentido?
Porque dependendo da entidade, Email por exemplo, não existe uma área para persisti-la, ou seja, não necessita das camadas Interface Usuário / Action / Service / Repositório, teoricamente apenas com Repository já conseguiria fazer o que preciso.

3 - Posso tratar regras simples na Action? Por exemplo:

[code]public class ClientAction {

public String deleteClient() {		
	if(client.getCards().isEmpty()) {
		clientService.delete(client);
	} else if (!client.getCards().isEmpty()) {
		FacesMessages.instance().add("Não é possível excluir um Cliente que possua vínculo com Cartão.");
	} 	
	return "deleteClient";
}

}[/code]
É errado fazer isso? Ou deveria delegar a tarefa ao Service?

Valeu pessoal, abraços!!

Cara, olhei por cima, mas já vi diversos problemas…

  1. Camadas. Tudo bem ter Interface com o usuário e uma camada de ações. Mas separar serviços? Alguns serviços fazem parte do dominio, que serviços você está separando?
  2. Por que uma camada repositório não entendi. O repositório é uma interface, faz parte do dominio.

Pelo que entendi no código abaixo, você simplemesmente renomeou os DAOs como repositório. Isso não é o correto. Leia isso: http://blog.fragmental.com.br/2010/01/18/domain-driven-bolovo-passando-conhecimento-e-etc/
e isso http://blog.fragmental.com.br/2008/05/22/domain-driven-design-e-simples/

[code]public class ClientService {
public void create(Client client) {
clientRepository.persist(client);
}
}

public class ClientRepository extends GenericRepository implements IClientRepository {
public void persist(Client client) {
entityManager.persist(client);
}
} [/code]

Só complementando…

1- Seria interessante utilizar um State para ele estar mudando o estado para a mudando a ação a partir do estado: create, update…

2- Isso pode depender muito da regra de negócio, mas acredito que não tenha necessidade de se “conhecerem” já que eles fazem coisas totalmente diferentes.
3- não acho interessante tratar regras no Action, já que ele representa a camada de visão.

[quote=x@ndy]Cara, olhei por cima, mas já vi diversos problemas…

  1. Camadas. Tudo bem ter Interface com o usuário e uma camada de ações. Mas separar serviços? Alguns serviços fazem parte do dominio, que serviços você está separando?
  2. Por que uma camada repositório não entendi. O repositório é uma interface, faz parte do dominio.

Pelo que entendi no código abaixo, você simplemesmente renomeou os DAOs como repositório. Isso não é o correto. Leia isso: http://blog.fragmental.com.br/2010/01/18/domain-driven-bolovo-passando-conhecimento-e-etc/
e isso http://blog.fragmental.com.br/2008/05/22/domain-driven-design-e-simples/
[/quote]
Obrigado pelas dicas, mas prefiro nem entrar em discussões que envolvem “purismos” em excesso.
Não vi ninguém que explicasse com clareza a diferença entre DAO e Repositório.
Eu segui um exemplo da JavaMagazine, e havia essa separação de serviços.

Olha o DAO é a camada que faz acesso ao Banco de Dados e alimenta os Objetos.
O Repositório pelo que eu entendi é a camada que gerencia os serviços.

Sobre a javaMagazine, você poderia dizer qual foi a edição e o artigo ?

Isto não está correto. Repositório armazena objetos de alguma classe do seu domínio. Por exemplo, se você tem a classe Contato, pode ter o repositório Agenda, que contém os métodos salvarContato(contato), pesquisarContatos(critériosBusca), apagarContato(contato), e etc. O Repositório faz parte do domínio e não tem nada a ver com DAO. A implementação do seu repositório pode acessar um DAO (ou um Service dependendo da divisão de camadas que você usar)

Conselho: estude o livro do Eric Evans e do Martin Fowler e os artigos do Shoes para conhecer, mas não fique bitolado para fazer a arquitetura perfeita. Isto depende muito da natureza da sua aplicação, do escopo, do tamanho, etc. Comece codificando e vá refatorando. Lembre-se apenas de boas práticas, como alta coesão e baixo acoplamento.

amhfilho Obrigado pela correção.
E valeu pela dica

[quote=samerjamal]
Obrigado pelas dicas, mas prefiro nem entrar em discussões que envolvem “purismos” em excesso.
Não vi ninguém que explicasse com clareza a diferença entre DAO e Repositório.
Eu segui um exemplo da JavaMagazine, e havia essa separação de serviços.[/quote]

Não é purismo. Uma coisa é repositório, outra é DAO. O repositório não sabe nada da implementação é só uma interface que salva e reconstitui os objetos (pode ser uma classe abstrata ou uma interface mesmo)
O que ocorre com DDD e isso é bem comum, é que antigos conceitos não renomeados e para se enquadrar como DDD mas isso não é DDD. DDD não chamar DAOs de repositórios. O DAO é implementação do repositório, só que o repositório é uma interface e poderia ter qualquer tipo de implementação.
Não li a matéria da Java Magazine mas é impossivel explicar todo o livro do Evans em um artigo. O que pode ter acontecido nesse artigo é uma certa confusão na qual o Evans muito no seu livro é sobre os “tipos de serviço”. No seu aplicativo pode haver três tipos de serviço:

  1. Infraestrutura: responsavel por exemplo pela persistência dos objetos como JPA ou alguma infraestrutura de envio de e-mails.
  2. Aplicativo: são os serviços da aplicação que processam aquilo que o usuário solicita, mas não fazem parte do dôminio, como um serviço para converter alguns dados em uma planilha do excel ou que processa as solicitações XML do usuário e passa para o domínio.
  3. Serviços do Dominio: São objetos sem comportamento mas que são relevantes ao dominio! Um exemplo seria um serviço de notificação do usuário do sistema no caso de uma alteração em seu cadastro. Esse serviço sabe que deve notificar o usuário mas não sabe como “notificar” então ele usa alguns serviços de infraestrutura para isso, como envio de SMS ou e-mail. Esse tipo de seviço faz parte do domínio, pois uma das regras desse é que o usuário deve ser notificado sempre que for feita uma atualização no seu cadastro!
    Agora, como implementar isso dentro do dominio? Ai entra DDD, o jeito mais simples seria:

e dentro da classe usuario:

public class Usuario{ public void salvarAlteracoes(){ repositorioUsuario.Salvar(this); servicoNotificacaoUsuario(this); } }
se eu fizer isso:

public class AlgumServicoDoAplicativo{ public void salvarUsuario(Usuario usuario){ repositorioUsuario.Salvar(usuario); servicoNotificacaoUsuario(usuario); } }
A minha lógica do dominio vazou para fora dele!
A consequencia mais simples é que sempre que eu necessitar salvar o usuário, vou ter que replicar código.

Um conselho: se você quer entender DDD leia o livro do Evans, leia também o livro do Fowler “Padrões de Aplicações Corporativa” lá eles mostram uma implementação do repositório.

Se eu não me engano a última edição da Java Magazine dá destaque a este assunto