Complexidade Ciclomática no Android

Como utilizar essa métrica de software para ter um código mais legível e testável.

Arildo Borges Jr
Android Dev BR
4 min readMar 15, 2021

--

Photo by Denys Nevozhai on Unsplash

Complexidade Ciclomática

Antes de mais nada, o que é Complexidade Ciclomática?

Complexidade ciclomática (ou complexidade condicional) é uma métrica de software usada para indicar a complexidade de um programa de computador. Ela mede a quantidade de caminhos de execução independente a partir de um código fonte. Sua fórmula é: M = E - N + P, onde E = quantidade de setas, N = quantidade de nós e P = quantidade de componentes conectados.

Partindo dessa definição, é possível concluir que a complexidade ciclomática está diretamente relacionada à quantidade máxima de caminhos que o código fonte pode executar, como por exemplo, uma condicional if:

O código acima pode ser representado da seguinte maneira:

fluxograma representando código acima

Seguindo a fórmula de cálculo da complexidade ciclomática, temos:

M = 5 (setas) - 5 (nós) + 2 (componentes conectados) = 2

Portanto a complexidade do código de exemplo é 2, pois esse é o número máximo de caminhos que o código pode executar.

Importância dessa métrica no Android

Como visto anteriormente, essa métrica está diretamente ligada à complexidade lógica do código, porém isso também reflete na legibilidade do código, pois à medida que se aumenta a quantidade de caminhos possíveis, também se aumenta a dificuldade de leitura desse código, se tornando cada vez mais difícil de manter. Outro bom ponto é a dificuldade de se escrever testes unitários, visto que será necessário cobrir todas as N possibilidades dentro de uma mesma função.

Como gerar essa métrica no Android

Existem diversas formas e ferramentas para se extrair complexidade ciclomática no Android, mas indico a ferramenta SonarQube, que além de oferecer diversas outras métricas, ainda oferece suporte a diversas outras linguagens, não se restringindo apenas ao android:

Como diminuir a complexidade de um código

Uma boa estratégia é extrair códigos específicos para funções próprias para que, além de deixar o código mais legível, também diminua a quantidade de caminhos que uma única função possui, pois serão diluídos em outras funções. Essa abordagem vem muito ao encontro do que o SRP (Single Responsability Principle, o "S" de SOLID) define:

No entanto, de acordo com o Princípio da Responsabilidade Única, um módulo, uma classe ou uma função tem que fazer apenas uma coisa. Em outras palavras, eles devem ter apenas uma responsabilidade. Desta forma, o código é mais robusto, mais fácil de depurar, ler e reutilizar. (traduzido do original em Towards Data Science)

Veja essa abordagem na prática, usando um código bem simples:

como existem 5 caminhos possíveis no código acima, sua complexidade é 5

O código acima possui complexidade de 5. Uma forma de diminuir esse número e ao mesmo tempo conformar ao SRP seria extrair o trecho when para uma função separada, pois a responsabilidade dele não é exibir o toast, mas sim definir se deve ser exibido ou não, de acordo com o tipo de usuário:

Note que no código acima, a funcionalidade não foi alterada, porém agora tem uma complexidade de 2 (1 componente + 1 condicional if). Isso permite uma granularidade maior de testes, visto que será possível testar duas funções separadamente, showUserNotification() e shouldShowAdsToUser() , cada uma com sua respectiva responsabilidade.

Por mais que esse seja um exemplo simples, já dá para visualizar os ganhos dessa abordagem, agora imagine a diferença no mundo real, com funções grandes, código legado, etc…

Conclusão

Embora a análise da complexidade ciclomática de um código seja um ponto muito importante, ela sozinha não garante que você tenha um código bem legível:

fonte: https://www.sonarsource.com/resources/white-papers/cognitive-complexity.html
fonte: https://www.sonarsource.com/resources/white-papers/cognitive-complexity.html

Veja nos dois exemplos acima, ambos possuem mesma complexidade, 4, porém legibilidade totalmente diferentes.

O ideal é sempre utilizá-la em conjunto de outras métricas e investir em boas práticas de desenvolvimento, principalmente princípios SOLID, que são um ótimo referencial para você ter um código legível, testável e fácil de manter.

Dica: Indico a leitura sobre uma segunda métrica relacionada a esse assunto, a Complexidade Cognitiva, que está diretamente ligada a legibilidade e leiturabilidade do código.

Abraços e até a próxima!

--

--