Quando comecei a brincar com C#, lembro ter habilitado uma opção no Visual Studio que analisava o código C# e sugeria algumas alterações para melhorias e acusava alguns problemas, entre eles o tal Cyclomatic Complexity.
Nesse artigo sugiro 3 dicas infalíveis para você reduzir essa pitomba no seu código C#.
Bom antes de você sair fazendo e habilitar a opção no Visual Studio para analisar o Cyclomatic Complexity, vamos à alguns fatos importantes no nosso Mundo Real.
Então, antes de atirar uma pedra, saiba que a maioria dos programadores não analisa o código fonte em busca de melhorias e optimizações. Todos sabem disso, mas ninguém se importa.
Existem ferramentas no mercado, gratuitas e pagas, que analisam o código fonte (também configuráveis) que sugerem diversas mudanças, melhorias e optimizações para reduzir o Cyclomatic Complexity. Mas vamos lá, o que é isso?
Cyclomatic Complexity é uma métrica criada por Thomas J. McCabe em 1976 para medir um código fonte e saber quão complexo ele é .
Essa métrica vai de 1 até N, onde não há limites. Quanto menor o resultado do CC, menos complexo será o código fonte. Há controvérsias na comunidade em adotar um número máximo de resultado que seja aceitável.
O White Box Testing Blog sugere a seguinte métrica para o Cyclomatic Complexity:
Cyclomatic Complexity
|
Riscos e Complexidade
|
1-10
|
simples, sem muito risco
|
11-20
|
muito complexo, risco moderado
|
21-50
|
muito complexo, risco moderado, atenção total
|
acima de 50
|
não dá para testar, risco alto
|
A regra de cálculo para essa métrica é meio que complexa (rsss), se você quiser saber detalhadamente como o CC é calculado, acesse o wikipedia.
Resumidamente, o CC verifica a quantidade de regras que existem em método, atribuindo notas para cada SWITCH/CASE, IF, WHILE e FOR que vai encontrando. Então, quando mais comandos desses, maior a complexidade.
Bom, voltando ao Mundo Real, abra uma solution no Visual Studio e clique no menu Analyze, depois em Calculate Code Metrics e depois clique em For Solution. O Visual Studio vai começar a analisar o seu código e mostrará uma tela assim:
Eu usei o código fonte do artigo A Mágica de Model Binder no MVC e Web API como exemplo para testar o Cyclomatic Complexity.
Repare na última coluna é exibido um valor de 230. Você deve estar se perguntando, de acordo com a tabela de métricas demonstrada anteriormente o meu código fonte é muito complexo. A resposta é “Sim e não”.
Os valores estão agrupados, então você precisa ir abrindo a árvore de código até chegar em um método para assim analisá-lo melhor.
Então, depois de saber como verificar o CC em um método C# usando a ferramenta de análise de métricas do Visual Studio, vamos as dicas:
#1 – SWITCH/CASE – Cyclomatic Complexity.
Evite uso de switch/case no código.
Ao invés disso use o design pattern Factory e/ou Strategy com polimorfismo.
Complexidade de 8 (1 para cada CASE e 1 para o método em si):
public void MethodDay(DayOfWeek day) { switch (day) { case DayOfWeek.Monday: Console.WriteLine("Today is Monday!"); break; case DayOfWeek.Tuesday: Console.WriteLine("Today is Tuesday!"); break; case DayOfWeek.Wednesday: Console.WriteLine("Today is Wednesday!"); break; case DayOfWeek.Thursday: Console.WriteLine("Today is Thursday!"); break; case DayOfWeek.Friday: Console.WriteLine("Today is Friday!"); break; case DayOfWeek.Saturday: Console.WriteLine("Today is Saturday!"); break; case DayOfWeek.Sunday: Console.WriteLine("Today is Sunday!"); break; } }
Refactorando para Factory de complexidade 1:
public void MethodDayReduce(DayOfWeek day) { var factory = Activator.CreateInstance(Type.GetType($"{day.ToString()}DayFactory")) as IDayFactory; factory.Write(); } public interface IDayFactory { void Write(); } public class MondayDayFactory : IDayFactory { public void Write() { Console.WriteLine("Today is Monday!"); } }
#2 – Expressão em IF – Cyclomatic Complexity.
Reduza a quantidade de expressões em um IF.
Ao invés disso crie variáveis locais que contenham apenas uma expressão, por exemplo:
Complexidade de 4: (1 para cada expressão e 1 para o método em si)
public void Method(bool condition1, bool condition2) { if (condition1 || condition2 && (!condition1)) { Console.WriteLine("Hello World!"); } }
Refactorando para complexidade de 2:
public void MethodReduce(bool condition1, bool condition2) { var negative = (!condition1); condition2 = condition2 && negative; condition2 = condition2 || condition1; if (condition2) { Console.WriteLine("Hello World!"); } }
#3 – BE COOL – Cyclomatic Complexity.
Não se mate por causa do Cyclomatic Complexity.
O que adianta você refactorar o seu código, reduzir a métrica CC e deixar o código ilegível ferindo os princípios de KISS (“Keep it Simple Stupid”)?
“Qualquer bobo consegue escrever código que um computador entende. Bons programadores escrevem códigos que humanos conseguem entender.” Martin Fowler.
Complementando, adote uma métrica aceitável ao seu negócio e principalmente a sua realidade. As tabelas de métricas desse artigo são apenas um guia, um norte para você começar a realizar as análises.
E quanto a performance?
Ah! Se você está preocupado se o CC pode afetar a performance, então a resposta é: “Sim”.
Mas calma! “Sim”… se a complexidade for muito alta, acima de 30 por exemplo, e ainda poderá variar de acordo com o tipo de comando que você estiver usando. Para ter certeza se afetará performance será necessário rodar algum tipo de benchmark para medir isso.
Eu diria a você: “relaxa e goza”.
Mas então é ou não necessário reduzir CC?
Claro! Quem gosta de ler um código cheio de IF encadeados e vários SWITCH/CASE? Aplicar CC, além de reduzir o uso desses comandos, vai ajudar a leitura do código por outros programadores e ainda irá adotar design patterns!
Depois de ter lido esse artigo, tenho certeza que você vai escrever um código mais amigável… certo?
Boa sorte 🙂
Reduzir Cyclomatic Complexity parece fácil mas não é.
Se você tem alguma outra dica compartilhe com a gente!