Posts
Codificando o Molho Secreto
16 de setembro de 2019 • 5 min de leitura

Cada aplicação tem seu molho secreto, sua razão de existir. Codificar o molho secreto é fundamental para escrever aplicações sustentáveis e bem-sucedidas.
Espera. O que é codificar? Paciência meu amigo, chegaremos lá.
Primeiro vamos fazer uma hipótese:
Você acabou de ser promovido a Engenheiro de Software Líder (Parabéns!). A primeira tarefa do seu CEO é criar um novo produto para a empresa. É uma aplicação de contabilidade construída do zero. Os executivos sentem que ter uma solução de contabilidade personalizada lhes dará uma vantagem sobre a concorrência.
Alguns meses se passaram, a maioria das preocupações transversais foram desenvolvidas (eba você!). A equipe agora está focada na bondade deliciosa da aplicação: o domínio de negócio (o molho secreto). É aqui que codificar o molho secreto começa.
Codificar é colocar estrutura em torno de um conceito essencial no domínio de negócio.
Na contabilidade, a relação preço (P) lucro (L) (relação P/L) é uma medida de lucros para uma empresa. Uma alta relação P/L sugere alto crescimento de lucros no futuro. A relação P/L é calculada tomando o valor de mercado por ação (preço da ação) dividido pelo lucro por ação (lucro – dividendos / # de ações em circulação).
Uma implementação simples, e eu diria, ingênua:
public class Metric
{
public string Name { get; set; }
public decimal Value {get; set}
public int Order {get; set;}
}
public class AccountingSummary
{
public Metric[] GetMetrics(decimal price, decimal earnings)
{
var priceEarningsRatio = price/earnings;
var priceEarningsRatioMetric = new Metric
{
Name = "P/E Ratio",
Value = priceEarningsRatio,
Order = 0
}
return new [] {priceEarningsRatioMetric};
}
}
Se isso é usado apenas em um lugar, está bom. E se você usar a relação P/L em outras áreas?
Como aqui em PriceEarnings.cs
var priceEarningsRatio = price/earnings;
E aqui em AccountSummary.cs
var priceEarningsRatio = price/earnings;
E aqui em StockSummary.cs
var priceEarningsRatio = price/earnings;
A relação P/L é central para esta aplicação, mas como está implementada, codificada em vários lugares, faz com que a importância da relação P/L se perca em um mar de código. É apenas mais uma árvore na floresta.
Você também se abre ao risco de alterar a relação em um lugar mas não no outro. Isso pode afetar cálculos subsequentes. Esses tipos de erros são notoriamente difíceis de encontrar.
Frequentemente testadores assumirão que se funciona em uma área, está correto em todas as áreas. Por que a aplicação não usaria o mesmo código para gerar a relação P/L para toda a aplicação? Não é esse o ponto da Programação Orientada a Objetos?
Posso imaginar um erro como este chegando à produção e não sendo descoberto até uma visita do seu executivo que exige saber por que os cálculos de relação P/L da SEC são diferentes do que a empresa arquivou. Esse não é um bom lugar para estar.
Vamos revisitar nossa implementação da relação P/L e ver como podemos melhorar nossa primeira tentativa.
Em sistemas de contabilidade fórmulas são uma coisa, vamos colocar estrutura em torno de fórmulas adicionando uma interface:
public interface IFormula
{
decimal Calculate<T>(T model);
}
Cada fórmula agora é implementada com esta interface nos dando consistência e previsibilidade.
Aqui está nossa relação P/L melhorada após implementar nossa interface:
Adicionamos um PriceEarningsModel para passar os dados necessários para nosso método Calculate.
public class PriceEarningsModel
{
public decimal Price {get; set;}
public decimal Earnings {get; set;}
}
Usando nosso PriceEarningsModel, criamos uma implementação da interface IFormula para a relação P/L.
public class PriceEarningsRatioFormula : IFormula
{
public decimal Calculate<PriceEarningsModel>(PriceEarningsModel model)
{
return model.Price / model.Earnings;
}
}
Agora codificamos a relação P/L. É um conceito de primeira classe em nossa aplicação. Podemos usá-la em qualquer lugar. É testável, e uma mudança impacta toda a aplicação.
Como lembrete, aqui está a implementação com a qual começamos:
public class Metric
{
public string Name { get; set; }
public decimal Value {get; set}
public int Order {get; set;}
}
public class AccountingSummary
{
public Metric[] GetMetrics(decimal price, decimal earnings)
{
var priceEarningsRatio = price/earnings;
var priceEarningsRatioMetric = new Metric
{
Name = "P/E Ratio",
Value = priceEarningsRatio,
Order = 0
}
return new [] {priceEarningsRatioMetric};
}
}
É simples e faz o trabalho. O problema é que a relação P/L, que é um conceito central em nossa aplicação de contabilidade, não se destaca. Engenheiros não familiarizados com a aplicação ou o domínio de negócio não entenderão sua importância.
Nossa implementação melhorada usa nossa nova classe de relação P/L. Injetamos a classe PriceEarningsRatioFormula em nossa classe AccountSummary.
Substituímos nossa relação P/L codificada por nossa nova classe PriceEarningsRatioFormula
.
public class AccountingSummary
{
private PriceEarningsRatioFormula _peRatio;
public AccountingSummary(PriceEarningsRatioFormula peRatio)
{
_peRatio = peRatio;
}
public Metric[] GetMetrics(decimal price, decimal earnings)
{
var priceEarningsRatio = _peRatio.Calculate(new PriceEarningsModel
{
Price = price,
Earnings = earnings
});
var priceEarningsRatioMetric = new Metric
{
Name = "P/E Ratio",
Value = priceEarningsRatio,
Order = 0
}
return new [] {priceEarningsRatioMetric};
}
}
Alguém poderia argumentar que há um pouco mais de trabalho com a PriceEarningsRationFormula sobre a implementação anterior e eu concordaria. Há um pouco mais de cerimônia, mas os benefícios valem bem o pequeno aumento em código e cerimônia.
Primeiro, ganhamos a capacidade de alterar a relação P/L para toda a aplicação. Também temos uma única implementação para depurar se defeitos surgirem.
Por último, codificamos o conceito da PriceEarningsRatioFormula na aplicação. Quando um novo engenheiro se juntar à equipe, ele saberá que fórmulas são essenciais para a aplicação e o domínio de negócio.
Existem outros métodos de codificar (encapsular) o domínio, como microsserviços e assemblies. Cada abordagem tem seus prós e contras, você e sua equipe terão que decidir o que é melhor para sua aplicação.
Proteger conceitos-chave do domínio em classes e interfaces cria componentes reutilizáveis e limites conceituais. Tornando uma aplicação mais fácil de raciocinar, reduzindo defeitos e diminuindo as barreiras para integrar novos engenheiros.
Autor: Chuck Conway é especialista em engenharia de software e IA Generativa. Conecte-se com ele nas redes sociais: X (@chuckconway) ou visite-o no YouTube.