2 puntos por GN⁺ 2025-03-12 | 1 comentarios | Compartir por WhatsApp
  • Al revisar recientemente una base de código, surgió una experiencia mentalmente agotadora a pesar de la calidad del código
    • Esto estaba relacionado con la legibilidad más que con la complejidad del código
  • Se derivaron 8 patrones para mejorar la legibilidad del código

Métricas de legibilidad del código y métricas alternativas de complejidad

  • No existe una métrica universal y ampliamente utilizada para medir la legibilidad del código
  • Solo existen artículos académicos que no se usan en la práctica u opiniones personales
  • En lugar de crear una nueva métrica, se pone el foco en patrones visuales que cualquiera pueda discutir fácilmente
  • Condiciones importantes en una métrica de complejidad:
    • Debe funcionar sobre fragmentos de código fuente o funciones individuales
    • Debe enfocarse en la forma de escribir el código, no en la complejidad algorítmica
    • No se enfoca en elementos de estilo (nombres de variables, espacios, sangría, etc.)

Métrica de complejidad de Halstead

  • Métrica de complejidad de código desarrollada por Maurice Halstead en los años 70
  • Permite cuantificar la forma de escribir código sin importar el lenguaje ni la plataforma
  • Calcula la longitud, volumen y dificultad de un programa con base en la cantidad de operadores y operandos
  • Principales medidas:
    • Cantidad de operadores únicos (n1)
    • Cantidad de operandos únicos (n2)
    • Cantidad total de operadores (N1)
    • Cantidad total de operandos (N2)
  • Mientras más operadores y operandos se usen, mayor será la complejidad del código
  • Como la definición de operadores y operandos no es clara en todos los lenguajes, es importante usar herramientas consistentes

Ideas obtenidas de la complejidad de Halstead

  • Las funciones cortas y con pocas variables tienen mayor legibilidad
  • Minimizar el uso de operadores o azúcar sintáctica específicos de cada lenguaje
  • El uso de cadenas en programación funcional (map/reduce/filter, etc.) puede perder legibilidad si se vuelve demasiado largo

Complejidad cognitiva (Cognitive Complexity)

  • Métrica de complejidad desarrollada por SonarSource
  • Un intento de medir con mayor precisión la dificultad de leer código
  • Tres principios principales:
    1. Las construcciones abreviadas (shorthand constructs) reducen la dificultad de lectura
    2. Las interrupciones en el flujo no lineal aumentan la dificultad
    3. Los flujos de control anidados aumentan la dificultad

Ideas obtenidas de la complejidad cognitiva

  • Las construcciones abreviadas son concisas, pero implican un riesgo potencial de bugs
  • Las condicionales y los operadores lógicos reducen la legibilidad si se usan en exceso
  • El manejo de excepciones es una causa importante del aumento de complejidad del código
  • goto en general debe evitarse, pero en ciertas situaciones puede ser útil
  • Conviene reducir en lo posible las estructuras de control anidadas

Forma, patrones y variables de las funciones

  • La "forma" visual de una función cumple un papel importante en la legibilidad del código
  • Tres principios para mejorar la legibilidad:
    1. Usar nombres de variables claros y específicos
    • Evitar la duplicación de variables (shadowing)
    • Usar nombres visualmente distinguibles (evitar nombres parecidos como i y j)
    1. Acortar la vida útil (liveness) de las variables
    • Cuanto más corto sea el alcance de uso de una variable, mejor
    • Las variables que permanecen mucho tiempo o atraviesan límites de funciones aumentan la complejidad
    1. Reutilizar patrones de código familiares
    • Mantener patrones de código consistentes mejora la legibilidad
    • Priorizar patrones ya conocidos en lugar de enfoques nuevos

8 patrones para mejorar la legibilidad del código

  1. Reducir líneas/operadores/operandos – usar funciones pequeñas y menos variables mejora la legibilidad
  2. Evitar enfoques nuevos – mantener patrones familiares dentro de la base de código
  3. Agrupar – separar cadenas largas de funciones, iteradores, etc. en funciones auxiliares
  4. Simplificar las condicionales – mantenerlas cortas y minimizar la mezcla de operadores lógicos
  5. Minimizar goto – si es necesario, usarlo de forma limitada solo en manejo de errores
  6. Minimizar el anidamiento – reducir la lógica anidada y, si hace falta, separarla en funciones
  7. Usar nombres de variables claros – emplear nombres específicos y no duplicados
  8. Acortar la vida útil de las variables – mantenerlas por poco tiempo dentro de la función y evitar que crucen límites de funciones

Conclusión

  • La legibilidad del código es un factor importante en la calidad del software
  • Halstead y Cognitive Complexity pueden cuantificar problemas de legibilidad y orientar mejoras
  • Escribir código conciso y claro facilita el mantenimiento y reduce la probabilidad de bugs
  • La mejor forma de escribir código es priorizar la simplicidad, la consistencia y la claridad

1 comentarios

 
GN⁺ 2025-03-12
Opiniones de Hacker News
  • Encadenar estructuras de programación funcional como map, reduce y filter es conciso, pero las cadenas largas tienden a perjudicar la legibilidad

    • Eso no es lo que el artículo da a entender
    • Se siente como una queja común de que algo es malo solo por no resultar familiar
    • Con un poco de costumbre, es más fácil de leer y escribir que otros métodos
    • Es importante aprender los fundamentos de la programación funcional
    • No hace falta explicar los monads, pero sí familiarizarse lo suficiente como para no criticar map y filter al azar
  • Un aspecto importante del buen código es que es cualitativo y literario

    • Esto puede resultar incómodo para programadores y académicos con una mentalidad matemática
    • Me gustan Dostoievski y Wodehouse, pero sus textos son muy distintos
    • Lleva tiempo entender el estilo de una base de código
  • El problema más agotador al leer código es la mutabilidad

    • La capacidad de "fijar" una variable una sola vez es un gran regalo
    • El proceso de entender un método debería aumentar de forma monótona del 0% al 100%
    • La razón por la que los GOTO son dañinos es que es difícil conocer el estado de las variables mutables
  • Las funciones pequeñas y pocas variables por lo general son más fáciles de leer

    • El enfoque en la "legibilidad" está sesgado hacia la microlegibilidad
    • Eso hace que el código quede demasiado fragmentado
    • Los lenguajes de la familia APL están en el extremo opuesto
  • TypeScript hace que el código sea difícil de leer

    • Si el modelo de datos se mantiene "atómico", está bien
    • Si dependes de la inferencia de tipos, es difícil rastrear los campos hasta su ubicación original
  • La función getOddness4 introduce asimetría

    • La función getOddness2 ofrece una elección simétrica
  • El artículo es interesante, pero no del todo satisfactorio

    • No estoy de acuerdo con la opinión de evitar operadores específicos del lenguaje o azúcar sintáctico
    • Estructuras como map, reduce y filter, si se usan bien, reemplazan otros operadores y reducen el "volumen"
  • El intento de definir la legibilidad es digno de elogio

    • Para mucha gente, se podrían encontrar las dimensiones reales de la legibilidad mediante pruebas
  • La complejidad del código se expresa por el tamaño del árbol sintáctico

    • Reducir la complejidad local no tiene un gran impacto en la complejidad total
  • En cadenas largas de funciones o callbacks, conviene dividir en grupos pequeños y usar variables con buenos nombres

    • Ambas versiones son iguales en términos de eficiencia
    • La diferencia está en el compilador