Aula 19 - Análise de Métricas de Software e Qualidade 📈
Objetivo Pedagógico
Objetivo: Implementar medições objetivas da qualidade do código e da eficácia organizacional: complexidade ciclomática de McCabe, débito técnico, cobertura de código e as quatro métricas DORA (DevOps Research and Assessment).
📑 1. Fundamentos Teóricos & Análise Técnica
O que não pode ser medido não pode ser gerenciado de forma científica. A avaliação de engenharia de software contemporânea divide-se em métricas de código-fonte estrutural e métricas de desempenho organizacional: 1. Métricas Estruturais de Código: - Complexidade Ciclomática de McCabe (\(M\)): Quantifica o número de caminhos de execução linearmente independentes no grafo de fluxo de controle de um método: $\(M = E - N + 2P\)$ Onde \(E\) é o número de arestas, \(N\) o número de nós e \(P\) os componentes conexos. Funções com \(M > 10\) apresentam probabilidade exponencialmente maior de conter defeitos e exigem refatoração urgente. - Débito Técnico (Technical Debt Ratio - TDR): Razão entre o custo estimado para corrigir todos os problemas de qualidade de um sistema versus o custo total de desenvolvê-lo do zero. 2. As Quatro Métricas DORA (DevOps Research and Assessment): - Deployment Frequency: Frequência com que o código é publicado em produção (equipes de elite realizam múltiplos deploys diários). - Lead Time for Changes: Tempo decorrido desde o commit até o deploy funcional em produção. - Change Failure Rate: Percentual de deploys que resultam em incidentes ou degradações de serviço exigindo rollback ou hotfix. - Time to Restore Service (MTTR): Tempo médio necessário para restaurar a integridade do sistema após um incidente em produção.
📐 Arquitetura Conceitual & Diagrama de Fluxo
graph TD
Source["Repositório de Código & PRs"] --> Sonar["Análise Estática SonarQube"]
Sonar --> Cyclo["Complexidade Ciclomática (M < 10)"]
Sonar --> Debt["Índice de Débito Técnico (TDR < 5%)"]
Prod["Eventos de Deploy & Incidentes"] --> DORAEngine["Motor de Métricas DORA"]
DORAEngine --> D1["Deployment Frequency (Múltiplas/Dia)"]
DORAEngine --> D2["Lead Time (< 1 Hora)"]
DORAEngine --> D3["Change Failure Rate (< 5%)"]
DORAEngine --> D4["Time to Restore (< 1 Hora)"]
style Source fill:#e1f5fe,stroke:#01579b
style Sonar fill:#fff3e0,stroke:#e65100
style Prod fill:#f3e5f5,stroke:#7b1fa2
style DORAEngine fill:#e8f5e9,stroke:#2e7d32 🔍 Pilares e Diretrizes Técnicas
Nesta unidade, aprofundamos os seguintes conceitos fundamentais: - Refatoração Guiada por Complexidade: Decomposição de métodos monolíticos com excesso de bifurcações condicionais (if/else, laços) em funções menores. - Quality Gates Automatizados: Bloqueio formal de merges caso novos débitos técnicos ultrapassem 3% no código novo. - Métricas DORA de Alto Desempenho: Foco em velocidade com segurança: deploys rápidos e pequenos reduzem o impacto de incidentes. - Manutenibilidade de Longo Prazo: Preservação da legibilidade e acoplamento frouxo do código para facilitar a evolução contínua da equipe.
🛠️ 2. Implementação Prática em Métricas DORA, Complexidade Ciclomática e SonarQube
Abaixo está a implementação técnica de referência, estruturada com padrões de engenharia de software e foco em robustez:
// complexity_and_dora_tracker.py (Cálculo de Complexidade AST e Métricas DORA)
import ast
class CyclomaticComplexityVisitor(ast.NodeVisitor):
"""Calcula a Complexidade Ciclomática de McCabe analisando a AST Python."""
def __init__(self):
self.complexity = 1 # Caminho base inicial
def visit_If(self, node):
self.complexity += 1
self.generic_visit(node)
def visit_For(self, node):
self.complexity += 1
self.generic_visit(node)
def visit_While(self, node):
self.complexity += 1
self.generic_visit(node)
def visit_ExceptHandler(self, node):
self.complexity += 1
self.generic_visit(node)
def analyze_function_complexity(source_code: str):
tree = ast.parse(source_code)
visitor = CyclomaticComplexityVisitor()
visitor.visit(tree)
print(f"Complexidade Ciclomática da Função: {visitor.complexity}")
if visitor.complexity > 10:
print("[ALERTA] Função altamente complexa! Recomenda-se refatoração imediata.")
else:
print("[OK] Complexidade dentro dos padrões saudáveis de engenharia.")
if __name__ == '__main__':
sample_code = """
def processar_pedido(pedido):
if not pedido.ativo:
return False
for item in pedido.itens:
if item.preco > 100:
if item.estoque == 0:
return False
return True
"""
analyze_function_complexity(sample_code)
💡 Análise Passo a Passo do Código
- Inspeção de AST Nativa: Percorre a árvore de sintaxe abstrata contando bifurcações lógicas de forma exata e independente de formatação.
- Detecção Precoce de Débito Técnico: Alerta quando uma função atinge limites arriscados que dificultam a criação de testes unitários abrangentes.
- Automatização em Pipelines: Pode ser acoplado em verificações de CI para impedir a introdução de novas funções de alta complexidade.
🎯 3. Próximos Passos & Sequência Didática
-
Slides da Aula
-
Quiz de Fixação
-
Exercícios Práticos
-
Desafio de Projeto