Complexidade Ciclomática no Android
Como utilizar essa métrica de software para ter um código mais legível e testável.
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:
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:
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:
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!