DDD – Blindando o Domínio
por Rodrigo Allemand em Mar.05, 2009, como DDD
Lembram que nesse post eu falei que o domínio deveria ser fechado e bem definido? Então! A melhor maneira de fazer isso é criar uma camada que faça uma “blindagem” no domínio, definindo o acesso a ela e validando contratos para os métodos.
Contrato nada mais é do que vc garantir que o que entra no domínio está valido e o que sai está de acordo com o que o método se propõe a fazer! Retirado do Wiki do Phillip…
Se quem chamar me garantir a pré-condição, eu garanto a pós-condição.
Garantir a pré-condição é garantir que todos os parâmetros que vc precisa (e recebe) para efetuar uma ação estejam de acordo com uma especificação mínima. Com isso, a pós-condição – que é a sua resposta do método (retorno) – estará garantida.
O padrão utilizado neste caso – para criar uma camada de comunicação do domínio com o mundo – é o Facade (leia-se “Fasseide”, “conjuncão de Face + ade”), um padrão de projeto citado no livro Design Patterns: Elements of Reusable Object-Oriented Softwares, da Gang of Four [Gof]. Ele cita o seguinte:
Fornece uma interface unificada para um conjunto de interfaces em um subsistema. Façade define uma interface de nivel mais alto que torna o subsistema mais facil de ser usado.
A motivação básica desse padrão é dividir sistemas em subsistemas para reduzir a complexidade do código.
Como eu falei anteriormente, um padrão pode ser desenvolvido de diversas maneiras, mas algumas implementações são tão simples que são frequentemente copiadas ao longo dos projetos. A implementação mais comum de Facade é ter um construtor privado – para impossibilitar a criação de uma instancia da classe - e colocar os métodos da facade como estáticos. Veja o exemplo:
public class Facade {
private Facade(){
}
public static String sayHello(){
return "Hello World!";
}
}
Dentro do seu método, vc pode perfeitamente trabalhar da maneira que melhor imaginar, porem, não convem colocar nenhuma regra de negócio ou validação dentro da facade, já que um método interno do domínio pode referenciar outro método do domínio sem necessariamente passar pela facade.
Existem tambem quem utilize uma classe para fachada, criando outras classes mais especificas para controlar cada ação, dividindo o sistema em sub-dominios, chamados por uma mesma fachada.
Blindar e validar sem ter regra de negócio? Para organizar melhor esta bagunça, Martin Fowler e Erick Evans desenvolveram o padrão Specification.
[...] business logic can be recombined by chaining the business logic together using boolean logic.
OBS.: Aqui está o PDF de Fowler sobre Specification.
Com a Specification, vc pode validar, selecionar e até mesmo construir objetos-modelo para satisfazer a sua regra de negócio. Mais uma vez, nenhum padrão tem uma implamentação fixa, todas podem variar, mas a mais utilizada para Specification em Java é a seguinte:
public interface Specification<T> {
boolean isSatisfiedBy(T t);
}
No exemplo acima, ela retorna true ou false, caso o objeto passado esteja de acordo com a especificação. Esta especificação ainda pode ser de vários tipos, conforme alguns exemplos descrito abaixo:
public abstract class AndSpecification<T> implements Specification<T>{
private final Specification<T> one;
private final Specification<T> other;
//Retorna true se o objeto passar pelas duas especificações
public AndSpecification(Specification<T> one, Specification<T> other) {
this.one = one;
this.other = other;
}
public boolean isSatisfiedBy(T t){
return one.isSatisfiedBy(t) && other.isSatisfiedBy(t);
}
}
public abstract class OrSpecification<T> implements Specification<T>{
private final Specification<T> one;
private final Specification<T> other;
//Retorna true se o objeto passar por uma das duas especificações
public OrSpecification(Specification<T> one, Specification<T> other) {
this.one = one;
this.other = other;
}
public boolean isSatisfiedBy(T t){
return one.isSatisfiedBy(t) || other.isSatisfiedBy(t);
}
}
public interface SelectionSpecification<T> {
//Filtra uma lista de acordo com uma especificação
List<T> isSatisfiedBy(List<T> list);
}
Utilizando o nosso exemplo, vamos criar um exemplo para validar o cadastro de um usuário:
public class CadastrarUsuarioSpecification
implements Specification<Usuario> {
public boolean isSatisfiedBy(Usuario usuario) {
if(usuario.getNome().equals("") ||
usuario.getSenha().equals("") ||
usuario.getLogin().equals("")){
return false;
}
return true;
}
}
OBS.: Lembrando que isso é apenas um exemplo didático, a entidade usuário do exemplo tem mais campos para serem validados!
O Dominio deve ter a sua validação independente do que vc utilize fora dele, seja Client-side com JavaScript ou Server-Side no seu servlet, por exemplo. Sempre faça o Design By Contract valer no seu domínio.
A especificação CadastrarUsuarioSpecification deve executar todas as validações necessárias para a inclusão de um usuário na base de dados. Utilizando-a em conjuntio com a Facade, teriamos algo como:
public class Facade {
private Facade(){
}
public static void cadastrar(Usuario usuario){
CadastrarUsuarioSpecification spec =
new CadastrarUsuarioSpecification();
if(spec.isSatisfiedBy(usuario)){
//Cadastrar usuario
} else {
//Levantar erro!
}
}
}
Com isso, isolamos o domínio, garantimos o contrato e o seu domínio está vacinado conta possiveis erros vindo de outras camadas!
P.S.: Para o conceito de Specification não ficar vago, ainda existem muitos modelos de se contruir uma especificação, seja ela para acesso a banco, para colecionar critérios, para gerar um SQL, para filtrar uma lista, etc. O que precisamos ter em mente é que sempre que vc quizer implementar uma regra de maneira clara, procure ver antes se ela se encaixa em uma specification.
Até!
comente e Recomende!
March 8th, 2009 em 11:16 pm
Muito interessante esse Specification, não o conhecia.
March 25th, 2009 em 4:39 pm
Na minha opinião a validação deveria ficar dentro do proprio objeto.
Para garantir q seu dominio seja valido o proprio objeto deve cuidar disso.
Mas achei interessante o padrao.
March 25th, 2009 em 5:17 pm
Olá Eric!
Obrigado pela visita!
Bem onde colocar a validação (dentro do objeto, fora, dividido) fica a critério do desenvolvedor. Mas a simplicidade e o isolamento que o Specification te dá, faz com que ele esteja separado do objeto, mas atuando em conjunto para prover essa validação (no caso da validação). Até porque vc pode ter vários tipos de validação (um para exclusão, outro para alteração, mais um para inclusão, e assim por diante), o que deixaria a sua entidade “gorda” demais.
April 5th, 2009 em 4:15 pm
Muito bom! gostei muito do post Rodrigo! gostaria de saber se você tem outros posts relacionados a padrões de projeto usando java( principalmente ). parabens!
April 9th, 2009 em 11:23 am
Ola Wagner!
Obrigado pela visita e continue acompanhando o blog que teremos uma série de posts sobre o assunto do seu interesse. E claro, todos em Java! rs
Abraço!!
June 27th, 2009 em 9:59 pm
Olá Rodrigo,
Minha pergunta pode não estar muito correta por estar estudando DDD a pouco tempo, mas aí vai:
A ação de cadastrar o usuário não deveria estar sendo feita pelo Repositório?
A facade nesse caso está atuando como o Repositório descrito no DDD?
Parabéns pelo blog. Muito bom!
Abraço!
October 14th, 2009 em 6:07 pm
Olá Rodrigo,
Antes de mais nada gostei da iniciativa ótimo post.
Eu estou buscando me aprofundar no DDD e estou esbarrando em uma coisa. Segundo a literatura do DDD o Domain é onde deve estar o core da App, logo é onde devem ficar as regras, por exemplo:
- Garantir um desconto para pedidos acima de 100mil
- Garantir que tenham vagas antes de efetuar uma matricula
Então sabendo disso é que vem a minha pergunta, onde este tipo de verificação deve ser colocado?
- É válido criar um método que recebe minhas regras no objeto a ser validado?
- É válido verificar as regras na camada Application antes de acessar o Repository?
- É válido criar uma classe onde nesta sejam verificadas todas as regras de um objeto que sera passado para ela?
[]’s
October 16th, 2009 em 11:29 am
Olá Diego!
Obrigado pela visita e pelo comentário. Desculpe a demora na resposta, mas sabe como é a vida de desenvolvedore, né… rs
Respondendo a sua pergunta, o Domínio é realmente igualado ao Core da aplicação, com isso, todas as regras de negócio devem estar dentro deste domínio.
Sobre a sua pergunta, ela é tão ampla e é tão frequente de muitos, que eu resolvi coloca-la em um post separadamente.
Ele está aqui:
http://blog.rodrigoallemand.com.br/?p=186
Valeu!!!
October 16th, 2009 em 12:34 pm
[...] Rodrigo Allemand em Oct.16, 2009, como DDD Resolvi responder ao comentário do Diogo (no post Blindando o Domínio) em um post separado por achar que essa é a duvida mais frequente que eu vejo de muitas pessoas, [...]
April 14th, 2010 em 5:13 pm
Rodrigo, muito interessante a postagem, mas me preocupo também com a redundância das verificações, apesar de achar seguro e coeso.
A preocupação é principalmente nos casos onde as transações devem ser verificadas em banco (triggers e procedures). Neste caso não seria interessante apenas as verificações do banco?
Sei que muita gente até “arrepia” os cabelos ao falar em trigger para regra de negócio, mas existem casos que elas são essenciais, de fato.
April 14th, 2010 em 5:33 pm
Olá Bruno!
Primeiramente, obrigado pela visita!
Conforme dito por muitos, em desenvolvimento não existe uma bala de prata, uma regra ‘fixa’ para sair do outro lado com um ótimo produto. Os padrões são soluções catalogadas para um determinado problema. Porém os problemas não são os mesmos sempre, eles mudam de caso em caso, mesmo que sutilmente. EU PESSOALMENTE, não gosto de soluções por triggers e procedure por achar que banco de dados apenas armazena dados. Eu penso que se um banco de dados tem regra de negocio é porque a aplicação não é ‘forte’ o suficiente pra gerir tais regras. E mais, se vc pensar que a sua aplicação – o seu domínio – é ‘usável’ em qualquer contexto, o seu banco e a sua interface são ‘trocaveis’, ou seja, vc tem que garantir que todas as regras de negocio – dentre elas a validação – sejam feitas por este domínio. A redundancia da verificação sempre vai – e ao meu ver DEVE – existir, seja ela no banco (trigger e constraints), na interface (Javascript) ou dentro do domínio. Sei que esse não é o melhor dos mundos mas existem aplicações que são consideradas ótimas mesmo tendo toda verificação no banco por intermédio de triggers e procedures.
Enfim, em cada lugar que eu vou eu vejo um tipo de ‘verificação’ diferente e todas bastante funcionais. Cabe a equipe de desenvolvimento se adequar às regras da casa, seja ela por trigger, por javascript, por Hibernate Validation, por Specification ou por todas elas ao mesmo tempo!