2 pontos por GN⁺ 2025-03-12 | 1 comentários | Compartilhar no WhatsApp
  • Ao revisar recentemente uma base de código, houve a experiência de sentir cansaço mental apesar da qualidade do código
    • Isso estava relacionado à legibilidade, mais do que à complexidade do código
  • Foram identificados 8 padrões para aumentar a legibilidade do código

Métricas de legibilidade de código e métricas alternativas de complexidade

  • Não existe uma métrica universal e amplamente usada para medir a legibilidade do código
  • O que existe são artigos acadêmicos que não são usados na prática ou opiniões pessoais
  • Em vez de criar uma nova métrica, o foco foi colocado em padrões visuais que qualquer pessoa pode discutir facilmente
  • Condições importantes para uma métrica de complexidade:
    • Deve funcionar em trechos de código-fonte ou funções individuais
    • Deve focar na forma como o código é escrito, e não na complexidade algorítmica
    • Não deve focar em elementos de estilo (nomes de variáveis, espaços em branco, indentação etc.)

Métrica de complexidade de Halstead

  • Métrica de complexidade de código desenvolvida por Maurice Halstead na década de 1970
  • Permite quantificar a forma como o código é escrito, independentemente da linguagem ou plataforma
  • Calcula o comprimento, o volume e a dificuldade do programa com base no número de operadores e operandos
  • Principais medidas:
    • Número de operadores distintos (n1)
    • Número de operandos distintos (n2)
    • Número total de operadores (N1)
    • Número total de operandos (N2)
  • Quanto mais operadores e operandos forem usados, maior será a complexidade do código
  • Como a definição de operadores e operandos não é clara em todas as linguagens, é importante usar ferramentas consistentes

Insights obtidos com a complexidade de Halstead

  • Funções curtas e com poucas variáveis têm maior legibilidade
  • O uso de operadores específicos da linguagem ou açúcar sintático (syntactic sugar) deve ser minimizado
  • O uso de cadeias na programação funcional (map/reduce/filter etc.) perde legibilidade quando fica longo demais

Complexidade cognitiva (Cognitive Complexity)

  • Métrica de complexidade desenvolvida pela SonarSource
  • Uma tentativa de medir com mais precisão a dificuldade de leitura do código
  • Três princípios principais:
    1. Construções abreviadas (shorthand constructs) reduzem a dificuldade de leitura
    2. Interrupções no fluxo não linear aumentam a dificuldade
    3. Fluxos de controle aninhados aumentam a dificuldade

Insights obtidos com a complexidade cognitiva

  • Construções abreviadas são concisas, mas trazem risco potencial de bugs
  • Condicionais e operadores lógicos, quando usados em excesso, prejudicam a legibilidade
  • Tratamento de exceções é uma das principais causas de aumento da complexidade do código
  • goto geralmente deve ser evitado, mas pode ser útil em situações específicas
  • Estruturas de controle aninhadas devem ser reduzidas sempre que possível

Forma, padrões e variáveis das funções

  • A “forma” visual de uma função desempenha um papel importante na legibilidade do código
  • Três princípios para melhorar a legibilidade:
    1. Usar nomes de variáveis claros e específicos
    • Evitar sombreamento de variáveis (shadowing)
    • Usar nomes visualmente distinguíveis (evitar nomes parecidos como i e j)
    1. Encurtar a vida útil (liveness) das variáveis
    • Quanto menor o escopo de uso de uma variável, melhor
    • Variáveis que permanecem por muito tempo além dos limites da função aumentam a complexidade
    1. Reutilizar padrões de código familiares
    • Manter padrões de código consistentes melhora a legibilidade
    • Dar preferência a padrões já conhecidos em vez de abordagens novas

8 padrões para melhorar a legibilidade do código

  1. Reduzir linhas/operadores/operandos – funções pequenas e poucas variáveis melhoram a legibilidade
  2. Evitar abordagens novas – manter padrões familiares na base de código
  3. Agrupamento – separar cadeias longas de funções, iteradores etc. em funções auxiliares
  4. Simplificar condicionais – manter condicionais curtas e minimizar a mistura de operadores lógicos
  5. Minimizar o goto – quando necessário, usá-lo de forma limitada apenas no tratamento de erros
  6. Minimizar aninhamentos – reduzir lógica aninhada e, se necessário, separá-la em funções
  7. Usar nomes de variáveis claros – usar nomes específicos e sem duplicidade
  8. Encurtar a vida útil das variáveis – mantê-las por pouco tempo dentro da função e evitar que ultrapassem seus limites

Conclusão

  • A legibilidade do código é um elemento importante da qualidade do código
  • Halstead e Cognitive Complexity podem quantificar problemas de legibilidade e indicar caminhos de melhoria
  • Escrever código conciso e claro facilita a manutenção e reduz a probabilidade de bugs
  • Escrever um código ideal significa priorizar simplicidade, consistência e clareza

1 comentários

 
GN⁺ 2025-03-12
Opiniões do Hacker News
  • Encadear estruturas de programação funcional como map, reduce e filter é conciso, mas cadeias longas tendem a prejudicar a legibilidade

    • Isso não é algo que o artigo esteja insinuando
    • Parece uma reclamação genérica de que algo é ruim só por não ser familiar
    • Com um pouco de familiaridade, fica mais fácil de ler e escrever do que outras abordagens
    • É importante aprender o básico de programação funcional
    • Não é preciso explicar Monad, mas é preciso ter familiaridade suficiente para não criticar map e filter aleatoriamente
  • Um aspecto importante de um bom código é que ele é qualitativo e literário

    • Isso pode ser desconfortável para programadores e acadêmicos com mentalidade matemática
    • Gostam de Dostoiévski e Wodehouse, mas a escrita deles é muito diferente
    • Leva tempo para entender o estilo de uma base de código
  • O problema mais cansativo ao ler código é a mutabilidade

    • A capacidade de “fixar” uma variável apenas uma vez é um grande presente
    • O processo de entender um método deve aumentar de forma monotônica de 0% a 100%
    • GOTOs são prejudiciais porque tornam difícil saber o estado de variáveis mutáveis
  • Funções pequenas e poucas variáveis geralmente são mais fáceis de ler

    • O foco em “legibilidade” está enviesado para a microlegibilidade
    • Isso faz com que o código fique excessivamente fragmentado
    • Linguagens da família APL estão no extremo oposto
  • TypeScript torna o código difícil de ler

    • Tudo bem se o modelo de dados for mantido “atômico”
    • Se você depender de inferência de tipos, fica difícil rastrear os campos de volta à sua origem
  • A função getOddness4 cria assimetria

    • A função getOddness2 oferece uma escolha simétrica
  • O artigo é interessante, mas não satisfaz

    • Não concordam com a opinião de evitar o uso de operadores específicos da linguagem ou açúcar sintático
    • Estruturas como map, reduce e filter, quando bem usadas, substituem outros operadores e reduzem o “volume”
  • A tentativa de definir legibilidade é digna de elogio

    • Com testes em muitas pessoas, seria possível encontrar as dimensões reais da legibilidade
  • A complexidade do código é expressa pelo tamanho da árvore sintática

    • Reduzir a complexidade local não tem grande impacto na complexidade total
  • Em cadeias longas de funções ou callbacks, é melhor dividir em pequenos grupos e usar variáveis com nomes claros

    • As duas versões são equivalentes em termos de eficiência
    • A diferença está no compilador