Specifications
Specification é um padrão de projeto descrito por Evans, o mago do DDD, ou pai, ou dono. Escreveu um livro sobre isso, o famoso e largamente mal utilizado DDD. Domain Driver Design, “Atacando as complexidades no coração do software”. O famoso livro azul. E o que ele diz?
“A especificação (Specification) é uma adaptação de um formalismo estabelecido, ou seja, o predicado.”
Entendeu? Acho que não né?
Calma, num afoba não. Vai piorar.
Segundo o Wikipedia:
“É um padrão de design de software, pelo qual as regras de negócios podem ser recombinadas encadeando as regras de negócios usando a lógica booleana.”
Traduzido pelo google. Ficou ruim mas da pra entender, eu acho.
Mas que pitomba é esse predicado?
Predicados são objetos no qual criamos para separar as regras de negocio que não cabem na entidade, ou pelo menos, não seria de bom tom escreve – lá nas entidades. Predicados são regras de negócios (meu entendimento, puritanos podem não concordar) puro e simples que me trazem um retorno booleano satisfazendo ou não uma condição.
Vamos imaginar que estamos trabalhando em um contexto de muitas mudanças em regras de negócios e que talvez, precisamos combina – las.
Pagamos um exemplo de leis trabalhistas. Imaginemos criar um calculo para aposentadoria. No cenário abaixo, temos duas classes, Trabalhador e Emprego (exemplo simples do simples do simples. Atente – se ao conceito e esquece código).
public class Trabalhador { public string Nome { get; private set; } public string Cpf { get; private set; } public DateTime DataNascimento { get; private set; } public IReadOnlyCollection<Emprego> Empregos {get; } public bool PodeAposentar() { var tempoTrabalhado = this.Empregos.Sum(e => e.TempoTrabalhado()) / 12; //se data nascimento, menor que 1900 if (this.DataNascimento < new DateTime(1900, 01, 01)) { if (this.MeuPrimeiroEmprego().DataInicio > new DateTime(1920, 01, 01)) { if (tempoTrabalhado > 200) return true; } else if (tempoTrabalhado > 300) return true; } //se data nascimento, maior que 2000 segundo lei xpto if (this.DataNascimento < new DateTime(1950, 01, 01)) { if (tempoTrabalhado > 50) return true; else return false; } //se data nascimento, maior que 2000 segundo lei xpto1 if (this.DataNascimento < new DateTime(2000, 01, 01)) { if (tempoTrabalhado > 100) return true; else return false; } return false; } private Emprego MeuPrimeiroEmprego() { return this.Empregos.First(); } }
public class Emprego { public Trabalhador Trabalhador { get; private set; } public DateTime DataInicio { get; private set; } public DateTime DataSaida { get; private set; } public double TempoTrabalhado() { return (this.DataSaida - this.DataInicio).TotalDays; } }
Imagine ir implementando regras trabalhista para aposentadoria no método “PodeAposentar”, a classe vai ficar gigantesca, sendo constantemente atualizada (ferindo o OCP do SOLID). Nesse caso cai bem o uso do Specification.
Veja como ficaria.
public abstract class AposentadoriaSpecification { public abstract bool SatisfazACondicao(Trabalhador trabalhador); }
public class AposentarSegundoGetulioVargasSpecification : AposentadoriaSpecification { public override bool SatisfazACondicao(Trabalhador trabalhador) { throw new NotImplementedException(); } }
public class AposentarSegundoBolsonaroSpecification : AposentadoriaSpecification { public override bool SatisfazACondicao(Trabalhador trabalhador) { throw new NotImplementedException(); } }
Para cada lei, incluiria um novo predicado em sua Specification. Assim eu mantenho a entidade com suas regras e as modificações ficariam nas especificações. Atendendo lindamente ao OCP (O do SOLID). O mais doido e que posso combina-las, ou seja, posso usar um E e OU ou ate mesmo negar a condição.
Assunto mais avançado. Esse vídeo aqui do Elemar Junior explica bem. Tem esse aqui do Eduardo Pires se preferir.
Parece simples, porem, não é. Criar seu sistema baseado em Specification só porque é “du carai” é um tiro no pé, pois Specification e muito mais complexo que isso. Veja os vídeos acima.
Tem muita gente que confunde a separação de regras de negocio removendo todas as regras da entidade, fazendo assim o seu modelo ficar anêmico e isso papai Evans não quer. O que puder ficar de regra na entidade, o faça e pare de complicar as coisas. Software deve ser simples, se for complexo tem algo errado (não sei quem disse isso, mas alguém disse e concordo).
Como todo padrão não é uma bala de prata, use no contexto que for necessário usar. Existe uma play list do Elemar Junior sobre DDD do jeito certo que acho uma boa para quem deseja aprender mais sobre o tema.
Foi somente uma introdução do que é esse padrão e qualquer duvida é só entrar em contato. Abraço!
Bibliografia
http://www.fabriciorissetto.com/blog/specification-pattern/
https://en.wikipedia.org/wiki/Specification_pattern
https://www.eximiaco.tech/pt/2019/10/28/usando-specification-pattern-para-respeitar-o-open-closed-principle
Deixe uma resposta
Want to join the discussion?Feel free to contribute!