Qualidade de software — manutenibilidade — complexidade ciclomática

Diogo Peixoto
6 min readDec 23, 2020

Contexto

Discussões com clientes, sejam eles internos ou externos, sobre a viabilidade financeira de desenvolver produtos de software com qualidade é um cenário comum. Algumas vezes aplicar as boas práticas de engenharia de software (TDD, Design Patterns, Architectural Patterns, DevOps, entre outras) pode ser desafiador.

Muitas vezes, a equipe de desenvolvimento se vê obrigada a desenvolver sem utilizar as boas práticas de engenharia de software para atender as necessidades de distintos stakeholders. Alguns motivos comuns para isso acontecer são: pressões da equipe de negócio de colocar no mercado um determinado produto para não perder o time to market, por pressões de gestores que se comprometeram com prazos apertados ou até mesmo a falácia de que desenvolver um produto de software de qualidade é caro.

Sabemos que essas são situações reais, e que dificilmente vamos estar em um cenário ideal, onde teremos o tempo necessário para lançar um produto no mercado ou os prazos serão factíveis, pois isso é uma realidade para projetos de empresas tradicionais. Por isso, em determinadas situações, é importante avaliar os trade-offs de investir mais tempo em qualidade de software, sacrificando outras variáveis (tempo de lançamento ou não cumprir com o que foi acordado).

Porém, existe a falsa sensação de que construir um software de qualidade é mais caro do que construir um que não utiliza as melhores práticas. O custo de desenvolver software é equivalente a 30%-40% do custo total do ciclo de vida de um software, portanto, apenas aproximadamente 1/3 do orçamento é gasto na fase de construção. Os outros 60%-70% são gastos na fase de manutenção / evolução do produto que acontecem depois de seu lançamento [1].

Segundo a definição dada por Institute of Electrical and Electronics Engineers (IEEE), a manutenção de software é a modificação de um produto de software depois de sua entrega para corrigir bugs, melhorar a performance e outros atributos, ou então para se adaptar a uma mudança de ambiente [2]. A manutenção pode ser divida em três categorias:

  1. Manutenção adaptativa - “Modificação de um produto de software realizada após a entrega para manter um programa de computador utilizável em um ambiente alterado ou em mudança.”
  2. Manutenção corretiva - “Modificação reativa de um produto de software realizada após a entrega para corrigir falhas descobertas”.
  3. Manutenção perfeita - “Modificação de um produto de software após a entrega para melhorar o desempenho ou capacidade de manutenção.” [3]

A manutenção perfeita engloba não apenas o desempenho do produto como também o desenvolvimento de novas funcionalidades e recursos que existem no produto de software. À medida que um produto é lançado no mercado, os usuários vão testar e validar hipóteses da equipe de negócio e dos stakeholders. Portanto, talvez seja necessário agregar novos recursos, modificá-los ou eliminá-los por conta dos feedbacks dados pelos usuários ou, até mesmo, uma mudança de mercado ao qual o produto está inserido.

A fase da manutenção do software, como já vimos, é bastante onerosa no ciclo de vida de um produto. Como saber se o produto terá um custo elevado nesta fase? Existe um atributo de software que indica o grau de facilidade de manter um software, onde quanto maior esse atributo, mais fácil de mantê-lo, e por isso, menos energia, tempo e dinheiro são necessários. A manutenibilidade é o atributo de software que mede a facilidade com que um produto ou componente de software pode ser modificado (manutenção adaptativa, corretiva ou perfeita) [4].

Portanto, a impressão de que o software de boa qualidade custa caro pode não ser verdadeira. Pois, de início, o preço pago por ele, provavelmente, será maior que um que não tenha tanta qualidade. No entanto, à medida que o software entra em operação, e novas funcionalidades são desenvolvidas, o custo e o tempo de agregá-las serão menores.

Gráfico que compara a quantidade de funcionalidades acumuladas durante o tempo de software de boa qualidade com um de baixa
Gráfico: funcionalidades acumuladas vs tempo [5]

O gráfico indica que existe um ponto onde a quantidade de funcionalidades acumuladas no tempo serão iguais entre os softwares de alta e baixa qualidade. No entanto, depois deste ponto, para adicionar funcionalidades ao de baixa qualidade custará muito tempo, e como consequência dinheiro. Além de tempo e dinheiro, podemos considerar que como demorará muito tempo, a empresa pode perder o time to market e ver o seu negócio sendo afetado pelo software de baixa qualidade.

Dado que a qualidade de software é inversamente proporcional ao custo, ou seja, quanto maior a qualidade, menor o custo total do software (construção + manutenção) e que a manutenibilidade é um dos atributos importantes, como medir esse atributo? Existem diversas métricas para medí-lo: linhas de código (Lines of Code — LoC), complexidade ciclomática, complexidade cognitiva, acoplamento, coesão, entre outras [6]. No entanto, este artigo irá apresentar apenas a complexidade ciclomática.

Complexidade Ciclomática

Esta métrica foi desenvolvida por Thomas J McCabe, onde utiliza a teoria dos grafos para medir a complexidade de um software. Segundo ela, a complexidade é independente do tamanho físico do software (LoC), a complexidade depende apenas da estrutura de decisão do programa [7].

Quanto maior a estrutura de decisão do software, ou seja, quanto maior a possibilidade de caminhos para a execução de um programa, mais casos de testes deverão ser criados para cobrir todas as possibilidades. A fórmula para calcular a complexidade ciclomática V(G) de um grafo G é:

V(G) = e - n+2

Onde “e” é o número de arestas (edges), “n” de vértices. Vamos ver como calcular na prática a complexidade através do exemplo de como calcular o número máximo entre dois inteiros.

public int max(int a, int b){
int max = a;
if(max < b){
max = b;
}

return max;
}
Grafo da tomada de decisão do código
Grafo da tomada de decisão do código

V(G) = 4 - 4 + 2 = 2

Como o programa tem 4 arestas e 4 nós, a complexidade ciclomática é 2. Ou seja, existem apenas dois caminhos possíveis para a execução do programa. Um que é caso o “a” seja menor do que “b” e o outro é caso o “a” seja igual ou maior que “b”.

Apesar de não ser uma fórmula complexa, à medida que o código de um componente vai ficando grande, o cálculo da complexidade vai se tornando custoso. No entanto, existem ferramentas no mercado que medem a complexidade através de análise de código estática — Sonarqube é um exemplo.

Porém, apenas analisando a complexidade ciclomática de um software como um todo não ajuda a saber o quão complexo é de manter e testar esse software. Pois, a complexidade é dada pelo somatório de todos os elementos de software. Por isso, é necessário analisar componentes que possuam uma alta complexidade ciclomática, pois, pode ser um indicativo de que esta classe pode ter um code smell.

Identificando o code smell, uma refatoração deve ser realizada para aumentar a testabilidade e manutenibilidade. Onde a testabilidade de software é o grau em que um artefato de software (ou seja, um sistema de software, módulo de software, etc) suporta o teste em um determinado contexto de teste. Se a testabilidade do artefato de software for alta, será mais fácil encontrar falhas no sistema (se houver) por meio de testes.

Portanto, um programa onde tenha uma alta complexidade ciclomática possui uma testabilidade baixa o que dificulta criação de testes unitários e como consequência uma baixa confiança na hora de fazer mudanças e uma falta de eficiência em criar novas funcionalidades.

Conclusão

A manutenibilidade de um software é um atributo desejado que impacta diretamente no custo de manutenção de software que é responsável pela maior parte dos gastos do ciclo de vida de um produto de software. Portanto, software de qualidade é sinônimo de redução de gastos.

Para avaliar se o software tem esse atributo, existem diversas métricas que foram criadas. Neste artigo, vimos a complexidade ciclomática que leva em consideração a quantidade de caminhos de execução de um software.

Para calcular a complexidade, existem ferramentas de análise de código estático. No entanto, é importante avaliar a complexidade de cada elemento de maneira individual, ao invés da complexidade total do software. Um elemento que tem uma complexidade alta pode ter um code smell, e provavelmente será necessária uma modificação neste componente para melhorar sua manutenibilidade e sua testabilidade.

Referências

[1] IEEE, IEEE Standard: 1219–1993 — IEEE Standard for Software Maintenance, INSPEC Accession №4493167 IEEE Computer Society (1993).

[2] IEEE, IEEE Standard: 828–1998 — IEEE Standard for Software Configuration Management Plans, IEEE Computer Society (1998).

[3] IEEE, IEEE Standard: 1219-1998 — IEEE Standard for Software Maintenance, IEEE Computer Society (1998).

[4] IEEE 1990, IEEE Standard Glossary of Software Engineering Terminology The Institute of Electrical and Electronics Engineers, Inc., New York.

[5] https://martinfowler.com/articles/is-quality-worth-cost.html

[6] Mäntylä, Mika & Vanhanen, Jari. (2003). Bad Smells in Software — a Taxonomy and an Empirical Study.

[7] Thomas J. McCabe, “A Complexity Measure”, IEEE Transactions on Software Engineering, Vol. SE-2, №4, December 1976

--

--

Diogo Peixoto

Apaixonado por compartilhar, errar, aprender e um pouco de engenharia de software