3 Dicas Infalíveis para Reduzir Cyclomatic Complexity no C#

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.

 
3 Dicas Infalíveis para Reduzir Cyclomatic Complexity no C#


 

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.

 
3 Dicas Infalíveis para Reduzir Cyclomatic Complexity no C#
 

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:

 
3 Dicas Infalíveis para Reduzir Cyclomatic Complexity no C#
 

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.

 
3 Dicas Infalíveis para Reduzir Cyclomatic Complexity no C#
 

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

 
3 Dicas Infalíveis para Reduzir Cyclomatic Complexity no C#

 
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!


 

Sobre o Autor:
Trabalha como arquiteto de soluções e desenvolvedor, tem mais de 16 anos de experiência em desenvolvimento de software em diversas plataformas sendo mais de 14 anos somente para o mercado de seguros.
Revisado por:
Um rapaz curioso que sempre gostou de Tecnologia, ciência e questões filosóficas. Entrou no mundo da programação em 2011 e hoje trabalha com desenvolvimento mobile back-end em C#, e desenvolvimento de apps em iOS. Sente um grande interesse por ciência de dados, e no futuro ainda pretende cursar Física.

  • Heymer Britto

    Muito bom o artigo, exemplificou muito bem como dar cabo dos ifs rsrsrs Parabéns 😀

    • Opa @heymerbritto:disqus ! Muito obrigado 🙂 Existem mais dicas para reduzir, mas essas são as principais 🙂

  • Thiago Locci Bomtempo

    Legal exemplo de Factory, bom artigo.

    • Show @thiagoloccibomtempo:disqus ! Vou implementar mais algumas dicas 🙂

  • Leonardo Ribeiro da Silva

    Bem legal o artigo e muito detalhado, aguardando mais dicas!

    • E ai @leonardoribeirodasilva:disqus valeu muito obrigado 😉

  • Davi Menezes

    otimizar eh legal, mas eh meio controverso. A parte do Switch então… se for enorme tudo bem, mas trocar um simples switch pela aquela abstração toda, me parece meio paranóico

    • Isso @davimenezes:disqus ! Não podemos se matar por causa disso, tudo deve ser analisado com calma, estipular um número aceitável para métrica e correr pro abraço 😉

  • Douglas Modesto

    Boa noite, uma dúvida, no primeiro caso do swicht, vc cria uma classe pra cada dia da semana? O custo disso é menor?

    Quero deixar meus parabéns pelo artigo, dicas super importantes pra quem quer evoluir na programação. Obrigado.

    • Oi @disqus_5HYFqNQklY:disqus ! Sobre custo é quase a mesma coisa, a diferença é que diminiui a complexidade, fica mais legível e possui separação das responsabilidades. É claro que, para poucos switch e que não envolvam regras de negócio, a gente não precisa se matar por causa do Cyclomatic Complexity. 🙂