top of page

Clean Code: Domain Driven com Tabelas de Decisão e Tuple Patterns

  • Foto do escritor: Marcos Jonatan Suriani
    Marcos Jonatan Suriani
  • 22 de out. de 2020
  • 3 min de leitura

Atualizado: 23 de out. de 2020



Há anos venho me deparando com situações em que a regra do domínio (vulgo regra de negócio) quando escrita em linguagem natural, seja para critérios de aceite ou documentação, tende a ser de leitura complexa. Há casos que esta escrita natural até possui um padrão de escrita - como Given-When-Then, contudo o problema persiste!


Quando regras de negócio possuem tomadas de decisão e são convertidas em código-fonte, condicionais e desvios de fluxo tendem a ser implementados, o que tende tornar o código mais difícil de ler e manter, principalmente por características inerentes à complexidade ciclomática.


Para exemplificar, considere a seguinte regra de negócio fictícia escrita no padrão Given-When-Then:


Feature: Desconto em inscrição em um plano na plataforma

Cenário: Residência em País Bonificado
Dado que usuário reside em país com benefício 
Quando se inscrever em qualquer plano e utilizar Pagamento anual ou mensal
Então aplicar 50% de desconto

Cenário: Plano Padawan com Pagamento Mensal
Dado que usuário não reside em país com benefício 
Quando se inscrever no Plano Padawan e utilizar Pagamento Mensal
Então aplicar 10% de desconto

Cenário: Plano Padawan com Pagamento Anual
Dado que usuário não reside em país com benefício 
Quando se inscrever no Plano Padawan e utilizar Pagamento Anual
Então aplicar 15% de desconto

Cenário: Plano Mestre Jedi com Pagamento Mensal
Dado que usuário não reside em país com benefício 
Quando se inscrever no Plano Mestre Jedi e utilizar Pagamento Mensal
Então aplicar 20% de desconto

Cenário: Plano Mestre Jedi com Pagamento Anual
Dado que usuário não reside em país com benefício 
Quando se inscrever no Plano Mestre Jedi e utilizar Pagamento Anual
Então aplicar 25% de desconto

Notou como fica extenso, de difícil leitura, e procurar a regra correta demanda que muito texto seja lido?


Será que parte da problemática se deve à conversão de uma regra escrita em linguagem natural para uma linguagem de programação, contendo seus paradigmas, semânticas e sintaxe?


Como podemos pelo menos tentar reduzir esta distância?


Tabelas de Decisão

A Tabela de decisão é uma maneira de expressar, em forma de tabela, qual o conjunto de condições que é necessário ocorrer para que um determinado conjunto de ações deva ser executado. O ponto principal de uma tabela de decisão é a regra de decisão, que define o conjunto de ações a ser tomado, a partir de um conjunto de condições. [wikipedia]

A vantagem do uso de tabelas de decisão se dá pelo fato de ser muito focada em palavras-chave e ubíquas relacionadas ao negócio - orientada a domínio, se assim podemos dizer :)

Em outras palavras, podemos considerar que é uma forma tabular de tomada de decisão.


A mesma regra escrita em linguagem natural acima foi convertida para uma tabela de decisão, conforme segue:


Feature: Desconto em inscrição em um plano na plataforma

Convertemos cerca de 24 linhas de texto em uma tabela 6x8, contando com cabeçalho e rodapé. O que achou?



Show me the Code!


Seguindo o exemplo citado acima, há uma abordagem clássica para codificar estas estruturas de controle de fluxo e tomadas de decisão.


decimal PercentualDesconto(Plano plano, Usuario usuario, Pagamento pagamento)
{
	if (PaisComBeneficio(usuario.PaisResidencia))
		return 50;
	if (plano == Plano.Padawan && pagamento == Pagamento.Mensal)
		return 10;
	if (plano == Plano.Padawan && pagamento == Pagamento.Anual)
		return 15;
	if (plano == Plano.MestreJedi && pagamento == Pagamento.Mensal)
		return 20;
	if (plano == Plano.MestreJedi && pagamento == Pagamento.Anual)
		return 25;
		
	return 0;
}

Utilizando o Tuple Patterns do C# 8 podemos reduzir drasticamente a complexidade e evitar controles de fluxo com if/then/else.


decimal PercentualDesconto(Plano plano, Usuario usuario, Pagamento pagamento) =>
	(plano, pagamento, PaisComBeneficio(usuario.PaisResidencia)) switch
	{
		(_, _, true) => 50,
		(Plano.Padawan, Pagamento.Mensal, _) => 10,
		(Plano.Padawan, Pagamento.Anual, _) => 15,
		(Plano.MestreJedi, Pagamento.Mensal, _) => 20,
		(Plano.MestreJedi, Pagamento.Anual, _) => 25,
		(_, _, _) => 0
	}

Em termos de atributos qualitativos, o que achou do readability?


O quão distante ficamos do formato tabular para tomada de decisão?


Esta é apenas mais uma abordagem em meio a inúmeras possibilidades! Se tiver uma diferente ou sugestão de melhorias, deixe seu comentário. Vamos adorar conhecer!

Comments


Conheça mais sobre essa fantástica Jornada!

Obrigado por se registrar!

bottom of page