Rodrigo Allemand

Tag: Desenvolvimento

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

O Cliente tem sempre razão… o usuário nem sempre!

por Rodrigo Allemand em Sep.24, 2009, em Matodologia Agil

Muitas coisas fazem um projeto passar de sucesso a um completo fracasso, dentre eles uma equipe mau escolhida, um escopo não casado com os prazos, uma arquitetura ruim, etc. Mas um dos maiores problemas que eu vejo que pode transformar um “felizes para sempre” em um “problema para sempre” é o levantamento das necessidades e requisitos.

Mais uma vez, muitos podem ser os fatores que atrapalham um bom levantamento. Analistas inexperientes, hierarquias mau definidas, credibilidade da equipe, clima hostil com o cliente, falha de detalhamento – muito ou pouco, dependendo do caso, usuários indecisos, usar “o que já existe” como exemplo e o pior de todos: usuários “acostumados” com o erro.

Recentemente, estou trabalhando como bombeiro em um projeto que espelha muito do dito acima.

A proposta era redesenhar um sistema originalmente feito em Delphi, que já funcionava a alguns anos para uma estrutura web em Java que temos. Este sistema já tinha passado por diverss atualizações, transformando o código em uma bela macarronada

Por uma briga que se arrasta a gerações (rs), há um clima hostil entre o gerente de projetos e o cliente final (que não cabe a mim questionar, muito menos entender). Isso gerava muitas discursões (infinitas até) quando se queria definir algum ponto.

Dica 1:Quando o manifesto ágil diz para ter o cliente como parte da equipe não é so ter o cliente por perto, mas sim jogando no mesmo time.

Quando se senta para definir alguma coisa, quanto mais gente entendendo, melhor! Entendendo não significa estar falando ou questionando. Mas todas pessoas precisam ter o mesmo entendimento. Por muitas vezes na reunião, surgia uma pergunta que não tinha fundamento algum, como se a pessoa estivesse voando ou não entendendo nada do que estava acontecendo.

Dica 2: Nunca deixe uma duvida no ar. A reunião é justamente para atender as necessidades dos analistas. Preste atenção quando alguem fala para poder perguntar alguma coisa válida. E questione se não entender! Sempre!

Para piorar, o gerente teve uma das piores atitudes que se pode tomar em uma reunião de levantamento: proibir os analistas de perguntarem, fazendo ele um funil com o cliente. Esta atitude fez com que conceitos fossem perdidos e o pior, conceitos errados surgiram.

Dica 3: Para um projeto, hierarquias não devem existir. Claro que algumas vozes pesam mais do que outras mas no momento de levantamento, todos devem ser ouvidos.

Então começa a definição dos casos de uso. Envolvidos em conceitos errados, climinhas e muita briga, os analistas ‘copiaram’ as funcionalidades do sistema antigo sem propor nenhuma alteração. Na aprovação do documento de requisito (aqui nós temos esse passo, por enquanto, rs) o usuário reclamou de muita coisa que estava definida ali, dizendo que se fosse par ter a mesma coisa, que continuasse com o antigo.

Dica 4: O legado pode ser usado como exemplo, mas tente sempre surpreenda o cliente com alguma novidade. Pense no que pode melhorar o trabalho dele e proponha modificações, sempre embasadas em alguma teoria, por mais simples que seja.

Troca-se a equipe para dar mais força ao projeto. Com isso, o usuário já não acreditava na equipe anterior, achando que eles poderiam novamente fazer as besteiras feitas anteriormente.

Dica 5: Por mais que fosse necessária a colocação de mais recursos, nunca deixe a credibilidade da equipe em risco. Se você não acredita no vendedor, como vai comprar o produto?

A nova equipe começou a detalhar – novamente – as funcionalidades e as mesmas tiveram variações, fazendo com que coisas com pouco detalhe tivessem uma pontuação de ‘codificação’ errada diante de tantos detalhes e outras que realmente tinham um alto grau de dificuldade, com pontuações baixas diante da falta de detalhamento.

Dica 6: Detalhe somente o necessário. Incremento é justamente isso! Se Quando chegar o momento você aumentará o nivel de detalhe.

Dá pra sentir como foi a fase de desenvolvimento deste projeto, né?!

Fazendo uma analogia com a construção de uma casa, a reunião de apresentação dos requisitos e das datas de entrega foi mais ou menos assim.

Analista: (…) Então aqui nós teremos os 3 quartos necessários.
Usuário: Mas eu não preciso de 3 quartos. Eu preciso de 3 camas!
Analista: Sim mas nós colocamos 3 quartos distintos para uma melhor modularização. Sem contar que esse quarto maior aqui é uma suite.
Usuário: Mas nesse quarto aqui, alem de ser suite, ele precisa de uma cozinha.
Analista: Como assim uma cozinha? Já existe uma cozinha aqui, veja!
Usuário: Mas eu preciso de uma cozinha aqui porque na antiga casa eu tinha uma cozinha perto da cama.
Analista: Sim, mas agora nós temos quartose a cozinha em ambientes separados.
Usuário: (…) E onde está a minha janela dos fundos para eu entrar?
Analista: Agora nós temos uma porta aqui nos fundos.
Usuário: Está errado. Funcionava assim: eu entrava na casa, abria a janela, saia da casa, dava a volta na casa, entrava pela janela e acessava a parte dos fundos da casa.
Analista: Agora você não vai precisar fazer isso. Nós temos uma porta para que você entre diretamente por ela, já que o proposito é apenas entrar na casa.
Usuário: Não o proposito é entrar na casa pela janela. E janela não é porta. A porta é pra entrar pela frente, a janela é para entrar pelos fundos.

Dica 6: Para o usuário que está acostumado com o erro do software antigo (que para ele já é trivial “entrar por uma janela”), você precisa mostrar e provar para o usuário que se é para entrar, precisa ser por uma porta.

Como dizia meu avô…

Burro não aprende, burro acostuma.
Não faça do seu usuário um burro.

Comente e Recomende!

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

De Padawan a Jedi

por Rodrigo Allemand em Aug.10, 2009, em Desenvolvimento

Recentemente um desenvolvedor da minha equipe e eu estavamos conversando sobre como dar soluções bem feitas. Ele se queixava de demorar muito para achar uma solução, construindo e re-construindo por muitas vezes um determinado pedaço de código até chegar a uma solução realmente boa. Refactoring é a saida para um bom código, mas existem outos pontos de falha na sua maneira de programar.

O conhecimento hoje é uma jóia que está a apenas alguns cliques de todos nós. Hoje em dia se aprende desde a fazer arroz a até uma bomba nuclear. Mas como adquirir conhecimento na nossa área? Como programar melhor? Como otimizar o seu tempo de desenvolvimento? Muitas dessas respostas estão a disposição de todos os programadores desde o inicio do ano 2000, numa das melhores -senão a melhor – compilações de boas práticas para a área de desenvolvimento de software.

Trata-se do livro The Pragmatic Programmer, From Journeyman to Master, de Andrew Hunt e David Thomas. Eu já li o livro pelo menos umas duas vezes (falando nisso, preciso entregar o livro ao dono!) e recomendo a quem não leu ainda, seja ele junior ou sênior.

O livro traz uma série de dicas sobre como se tornar um bom programador. Segue um pequeno resumo.

  1. Preocupe-se em fazer um código bom
  2. Pense!! Critique o seu trabalho
  3. Dê opções, não dê desculpas.
  4. Conserte falhas ao encontrar a falha
  5. Seja um catalizador de mudanças
  6. Lembre-se o ‘porquê’ do projeto
  7. Faça da qualidade um requerimento
  8. Invista regularmente no seu portifólio de conhecimento
  9. Analise e critique o que você ouve e vê
  10. É o que você fala e COMO você fala
  11. DRY – Don’t Repeat Yourself
  12. Faça facil para ser reutilizavel
  13. Elimine efeitos entre coisas não relacionadas
  14. Não existem decisões finais
  15. Use traçantes para achar o alvo
  16. Prototipar para aprender
  17. Programe para o problema do domínio usando a linguagem do domínio
  18. Estime para evitar supresas
  19. Itere o cronograma com o código
  20. Deixe o conhecimento em arquivos textos
  21. Use o poder das linhas de comando
  22. Use BEM apenas um editor
  23. Sempre use um controlador de versão
  24. Resolva o problema, não a culpa
  25. Não entre em pânico ao debugar
  26. O problema normalmente não é no ’select’
  27. Não assuma algo, prove!
  28. Aprenda uma linguagem de manipulação de texto
  29. Excreva código que escreva código
  30. Não, você não pode escrever softwares perfeitos. Proteja o seu código.
  31. Desenhe soluções baseadas em contratos
  32. Pegue os problemas precocemente. Teste desde o inicio.
  33. Use asserções para prevenir o impossivel
  34. Use exceções apenas para o excepcional
  35. Termine o que começou
  36. Minimize acoplamentos entre módulos
  37. Configure! Não integre!
  38. Coloque abstração no código e detalhe no metadata
  39. Analise o workflow para melhorar a concorrências
  40. Desenhe usando serviços
  41. Sempre desenhe pensando em concorrência
  42. Separe a visão do modelo
  43. Desenhe e conheça o fluxo da informação
  44. Não programe por concidência
  45. Estime a complexidade dos seus códigos
  46. Teste as suas estimações em unidades reais
  47. Refatore frequentemente, agora e sempre!
  48. Desenvolva para os testes
  49. Teste o seu software, ou os usuários testarão
  50. Não use geradores de código que você não entenda o que foi gerado
  51. Não apenas leia os requisitos. Mergulhe neles. Escave eles!
  52. Trabalhe com um usuário para pensar como um usuário
  53. Abstrações sobrevivem mais do que os detalhes
  54. Crie um glossário de projeto
  55. Ache, pense e pese as ‘necessidades’
  56. Comece quando estiver pronto!
  57. Algumas coisas são melhores prontas do que descritas
  58. Não seja escravo da formalidade
  59. Ferramentas caras não produzem as melhores arquiteturas
  60. Organize o time por funcionalidades, e não por funções.
  61. Automatize o que puder ser automatizado.
  62. Teste frequentemente e automaticamente
  63. Só está pronto quando o teste roda com sucesso
  64. Use sabotadores para testar o seu teste
  65. Não teste apenas o código. Teste as situações do domínio
  66. Ache erros apenas uma vez
  67. Escreva documentos com os mesmos princípios que vc escreve código
  68. Não separe tanto a documentação do código
  69. Exceda a espectativa do seu cliente
  70. Assine o seu trabalho

PS: Qualquer duvida, só comentar que eu detalho os itens.

Comente e Recomende!!

Deixe um comentário :, , 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...