Rodrigo Allemand

Tag: DDD

DDD encapsula a minha Regra de Negócio

por Rodrigo Allemand em Oct.16, 2009, em 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, seja em conversas informais, fóruns, palestras, etc.

Onde colocar as minhas regras de negócio?

A resposta é…. Depende! rs

Se você escolheu utilizar DDD no seu projeto é porque você conhece e já isolou o problema a ser resolvido que, por ser complexo, será baseado em um modelo, recebendo o foco e a prioridade necessárias para a solução deste domínio. Quando você isola este domínio, obviamente você deve encapsular tambem todas as regras de negócio dentro desse domínio.

Para exemplificar melhor vamos fazer a seguinte funcionalidade de exemplo no nosso dóminio.

Todos os pedidos com valor acima 1.000,00 e que são pagos com dinheiro em espécie são elegíveis a um desconto de 10% por produto.

Claro que esta informação tem que ser passada para o usuário final do sistema, mas é responsabilidade do sistema checar se as informações passadas estão corretas. Você pode até colocar a regra de validação tambem na camada de apresentação ou dentro do seu banco de dados em forma de triggers (argh, rs!), mas de qualquer maneira o domínio tem que ter esta validação, já que um dos princípios do DDD é justamente poder trocar a camada de apresentação sem que o domínio seja alterado ou compartilhar o mesmo domínio entre interfaces/sistemas diferentes.

Portanto, segue a primeira afirmação:

Por mais que a sua camada de apresentação faça as regras necessárias para uma determinada funcionalidade, o seu domínio tambem deve, obrigatoriamente, fazer com que estas regras estejam presente internamente, tornando-o coeso da camada que ele comunica.

Vamos melhorar este exemplo mostrando como ficariam as entidades envolvidas nesta funcionalidade.

public class Pedido {
	private List<ItemPedido> itens;
	private BigDecimal precoTotal;
	//Acessores omitidos
}
public class ItemPedido {
	private Produto produto;
	private BigDecimal precoVenda;
	private BigDecimal desconto;
	//Acessores omitidos
}

OBS.: Muitos podem perguntar porque a informação referente ao preço final é um atributo da classe e não um comportamento da entidade (um método que poderia somar todos os preços finais decrementando os descontos dados por cada produto, multiplicado pela quantidade de cada produto). Vamos pensar que o preço do Produto pode – e deve – variar e o sistema precisa manter a informação do preço de venda naquele momento, ok?

Eu encaro que esta regra de negócio deve estar em uma checagem no momento da inclusão, como por exemplo uma Specification destinada somente a esta regra. Lembro que, a Specification tem, neste caso, o intúito de validar uma informação e que ela não precisa ser necessariamente apenas uma única specification. Eu posso – e é até melhor – dividir a informação em várias Specifications, uma para cada regra de negócio que a minha funcionalidade exige.

Vamos pensar então que a minha classe ValidarDescontoDadoSpecification tem o seguinte código:

public class ValidarDescontoDadoSpecification
	implements Specification<ItemPedido> {

	public static final BigDecimal DESCONTO_MAXIMO_PGTO_DINHEIRO = 10;

	public boolean isSatisfiedBy(ItemPedido item){
		if(itemPedido.getFormaPagamento.equal(FormaPagamento.DINHEIRO){
			BigDecimal descontoDado =
				Calculadora.percentualEntre(
					item.getPrecoVenda(),
					item.getDesconto());
			if(descontoDado.compareTo(DESCONTO_MAXIMO_PGTO_DINHEIRO) > 1){
				//É necessário comunicar ao domínio o porque da falha
				//Neste caso, leia mais sobre Notification
				return false;
			}
		}
		return true;
	}
}

Pensando que você sempre salva o pedido, poderiamos ter uma outra Specification para isso, conforme abaixo:

public class PersistirPedidoSpecification
	implements Specification<Pedido> {

	public boolean isSatisfiedBy(Pedido pedido){
		/*
		  As boas maneiras de aplicativos internet diz que
		  vc deve validar tudo de uma unica vez, rs
		*/
		boolean resultado = true;

		//Validações referente ao Pedido

		ValidarDescontoDadoSpecification spec =
			new ValidarDescontoDadoSpecification();
		for(ItemPedido item : pedido.getItens()){
			if(!spec.isSatisfiedBy(item)){
				/*
				  Lembre que a informação da falha deve ser feita
				  pela outra Specification, não por esta!
				*/
				resultado = false;
			}
		}
		return resultado;
	}
}

Assim, no final de tudo, nós poderiamos ter no repositório Pedidos, o seguinte código:

public class Pedidos{

	public static void persistir(Pedido pedido){
		PersistirPedidoSpecification spec
			=  new PersistirPedidoSpecification();
		if(spec.isSatisfiedBy(pedido){
			dao.salvar(pedido);
		} else {
			//Comunica a falha encontrada às outras camadas
		}
	}
}

Espero ter ajudado!!!

Abraço a todos!!!

Comente e Recomende!!

13 Comentários :, , mais...

DDD – Fabricando e Encontrando Objetos

por Rodrigo Allemand em Aug.17, 2009, em DDD

Antes de mais nada, este post não é – como nenhumk dos outros desta série – focado extritamente em DDD. Leia o primeiro post da séries para entender melhor…

Em qualquer sistema OO, vc trabalha com….. objetos (ohhhhhhhh)

Qualquer objeto ‘precisa’ ser….. criado antes de ser utilizado…. (ohhhhhhh)

Qual a melhor maneira de se criar objeto? (errr…. humm….. bem…….)

Muitas são as maneiras… usando um construtor, por DI (Dependency Injection), por fábricas, etc.

O mais utilizado são as fábricas, ou Factories conforme catalogado pelo GoF, ou Gang of Four.

Resumidamente, “o padrão Factory fornece uma interface para a criação de famílias de objetos correlatos ou dependentes sem a necessidade de especificar a classe concreta destes objetos”.

Diversos exemplos de fábricas existem espalhados pela internet, e eu não vou colocar mais um aqui. Procure, rs!

A motivação inicial do padrão era a criação de objetos complexos, fazendo com que a lógica estivesse toda em um unico lugar… princípio de DRY nos promórdios da Arquitetura de Software!

Porém, certos objetos alem de serem complexos, precisavam de um processo de construção demorado. Algumas tecnicas para a sulução deste problema era ‘reter’ o objeto contruido e utilizá-lo como um ponto de acesso único, otimizando assim o processo de construção.

Com isso, por muitas vezes os desenvolvedores juntavam dois padrões de projetos para sanar o problema de contrução complexa e demorada, utilizando Factory e ‘Singletons’ para colocar objetos a disposição do ‘domínio’.

Colocar fábricas a disposição dos desenvolvedores, por muitas vezes, mascarava onde realmente estes objetos deveriam ser criados. Poderiam existir inúmeras fábricas em um único projeto, como eu já presenciei num passado não muito distante. Era DaoFactory pra cá, AbstractDaoFactory pra lá, ReportFactory aqui e ServiceFactory acolá! Uma verdadeira macarronada de factories!

Então, como manter um ponto único de acesso para ‘encontrar’ os objetos?

Fowler resolveu colocar tudo em um unico padrão e o nomeou de Registry, ou Registro.

De acordo com Fowler, Registry é

Um objeto conhecido que outros objetos podem usar para encontrar objetos e serviços comuns.

A função do Registro é:

  1. Criar objetos
  2. Encapsular complexidades de criação
  3. Reter objetos criados
  4. Funcionar como ‘local dos objetos’

Com isso, se você quizer saber ou precisar de um objeto e o seu sistems tem um Registro, pergunte a ele!

Normalmente os Registros são factories e singletons mesclados, conforme o exemplo abaixo:

public MyDomainRegistry{
    private static MyDomainRegistry INSTANCE = null;

    private MyDomainRegistry(){
        loadVariables();
    }

    private static MyDomainRegistry instance(){
        //Coloque aqui a sua implementação de Singleton
        return INSTANCE;
    }

    //Posso usar SubDomains
    private ConsultarSubDomain consultarSubDomain;
    //Posso usar Services Services
    private ConversaoService conversaoService;
    //Qualquer objeto que eu queira localizar!
    private MyRepository myRepository;

    private void loadVariables(){
        //Aqui vc deve criar os seua objetos como achar melhor
        this.consultarSubDomain = new ConsultarSubDomain();
    }

    //Aqui vc coloca os métodos estáticos para retornar
    //os objetos que o registro precisa controlar
    public static ConsultarSubDomain consultarSubDomain() {
        return instance().consultarSubDomain;
    }
}

Bem simples, não?

Agora, para você utilizar um objeto, basta solicitar ao registro, assim.

public class FachadaDoDominio {

    private FachadaDoDominio() {
    }

    public static ConsultarSubDomain consultar(){
        return MyDomainRegistry.consultarSubDomain();
    }
}

Comente e Recomende!

5 Comentários :, , , , mais...

DDD – Camadas e Comunicação

por Rodrigo Allemand em Feb.26, 2009, em DDD

Camadas

DDD – Domain Driven Design – depende que vc desenvolva em camadas, isso é fato. A maioria das aplicações utilizam 4 camadas, conforme a figura abaixo:

  1. Camada de Interface com o Usuário (User Interface)
  2. Cama de Aplicação (Application Layer)
  3. Domínio (Domain Model)
  4. Camada de Infra-estrutura
Camadas básicas de uma aplicação DDD

Camadas básicas de uma aplicação DDD

A camada de interface com o usuário, como o próprio nome diz (dããããã!) é a camada que… hum…. er… cria uma interface com o usuário… rs. Deixando a brincadeira de lado, a definição desta camada é tão simples quanto o próprio nome. Ela é responavel por ter uma interface amigavel com o cliente, tanto de entrada quando te saída (leia amigavel como algo que o cliente consiga ler e excrever). Se a sua aplicação for Web, essa camada seria os seus JSPs e todos aqueles outros arquivos que te auxiliam na comunicação com o usuário (imagens, scripts, etc). Se vc tem um WebService, pode ser a linguagem de máquina que vc está usando (SOA, JMS, etc). Se for uma aplicação Client-Server, por exemplo, baseada em Java, são os seus componentes de GUI, como SWT, AWT, Swing, etc.

A camada de aplicação é a camada responsavel por tratar trabalhar os objetos da camada de domínio. Nela estão raros e possiveis trabalhos sobre informações da camada de aplicação sem que se execute qualquer tipo de regra de negócio, por mais simples que isso seja. Utilizando exemplos de aplicações Web, estes seriam os seus Servlets ou Commands ou Actions (no caso do Struts, por exemplo).

A camada de domínio é o coração do sistema. Nela estão todas as regras de negócio, ou melhor, ela é responsavel por abstrair o negócio. No decorrer dos posts, vc entenderá melhor o que será esta abstração.

A camada de infra-estrutura é toda a parte que liga a lógica ao físico, como banco de dados, emails, arquivos e coisas do tipo. Uma duvida que muitos tem é que a camada de dominio NÃO é responsavel por gravar/buscar nada em lugar algum, seja isso banco de dados ou um arquivo. Isso é tarefa da camada de infra estrutura. Você verá como o domínio solicita essa iteração com as mídias quando chegarmos em Repositorios.

Dependências e comunicação

Repare bem como ficam as dependências entre as camadas na figura acima. As dependencias são sempre na descendente vertical. A camada de interface depende da camada de aplicação que depende do domínio que depende da infra-estrutura. Eventualmente vc pode ter a camada de interface depender da camada de infra, mas nunca o contrário. As camadas sempre dependerão da mais inferior, e nunca da superior. O dominio NUNCA pode depender da camada de interface ou da camada de aplicação. Nunca passe um objeto da camada de aplicação para a camada de dominio!! As setas da figura podem lhe ajudar a entender a dependência.

Como você já sabe pode imaginar, dentro do dominio existem podem existir outras camadas. Alguns autores conseguem tipar os domínios, como vc pode ver no livro Pojos em Ação, onde o autor coloca tipos de domínios (Exposto e Aberto são os unicos que me vem a cabeça no momento).

Não vou me arriscar a falar de tipos de domínio por ser um assunto que eu não concordo. Vamos usar sempre a nossa camada de domínio bem fechada e definida.

Até a proxima!

Comente e Recomende!

3 Comentários :, , , , mais...

Procurando por algo?

Use o campo abaixo para procurar por todo o site:

Ainda não achou? Deixe um comentário ou me mande um email que eu cuido disso!

Minhas indicações!

Alguns blogs que eu recomendo...