Vanguardia

Sugerencias para la legibilidad del código fuente

Dino Esposito

Dino Esposito¿Ha oído alguna vez hablar del concurso internacional de código C ofuscado? En pocas palabras, se trata de un concurso abierto que selecciona un ganador de entre un puñado de programas en C que solucionan un problema (cualquiera) con un código en C extremadamente oscuro y ofuscado. Puede encontrar los códigos fuentes de los programas ganadores de años anteriores en ioccc.org/years.html.

El concurso de código C ofuscado es una forma desenfadada de mostrar la importancia del estilo y la legibilidad en programación. Esta columna resumirá algunas de las prácticas más importantes que deberá seguir para conseguir un código que sea fácil de leer y comprender, tanto para su propio beneficio como el de sus colegas.

La legibilidad como atributo

En desarrollo de software, el mantenimiento es el atributo que se refiere a la facilidad con la que puede modificar código existente para lograr objetivos tales como la corrección de un error, limpieza, la implementación de una nueva característica o simplemente la refactorización a nuevos patrones. El mantenimiento es uno de los atributos fundamentales del software, según el documento ISO/IEC 9126. Para más información sobre los atributos del software, consulte el documento en bit.ly/VCpe9q.

El mantenimiento del código es el resultado de una variedad de factores, uno de los cuales es la legibilidad. El código que es difícil de leer también es difícil de entender. Los desarrolladores que tienen que trabajar con código que no conocen ni entienden correctamente están destinados a empeorar el código aún más.

Lamentablemente, la legibilidad es un aspecto completamente subjetivo. El desarrollo de una herramienta automática de comprobación que emita un informe sobre el nivel de legibilidad del código es prácticamente imposible. Sin embargo, incluso aunque fuera posible medir la legibilidad de forma automática, posiblemente todo el mundo consideraría que dicha herramienta no es fiable y no generaría confianza alguna. Al final, la legibilidad es un atributo manual que cada desarrollador debería comprobar junto con el resto de su código. La capacidad para escribir código que sea fácil de leer debe ser parte de la responsabilidad cultural de cada desarrollador, ampliando su conjunto de aptitudes.

De forma general, la legibilidad es un atributo del código que puede y debe aprender a adoptar al comienzo de su carrera como programador, desarrollándola y mejorándola a lo largo del tiempo. Como el estilo y el buen diseño, la legibilidad no debe reservarse a los expertos. Y lo que es más importante, no debe posponerse hasta que se tenga suficiente tiempo.

Un enfoque pragmático a la legibilidad

La producción de código legible es una cuestión de respeto hacia otros desarrolladores. Un usuario de StackOverflow publicó en una ocasión: "siempre deberías codificar como si la persona que acaba manteniendo tu código fuera un psicópata violento que supiera donde vives". También debería tener en cuenta que el usuario que acabe manteniendo su código, algún día, podría ser usted.

Al leer código de otras personas, hay algunas cosas que pueden ponerle de los nervios. Un aspecto que hace que el código sea difícil de leer son los algoritmos y estructuras de datos sin un objetivo claro. Otro aspecto son las estrategias usadas en el código que son difíciles de determinar y que no están bien documentadas con comentarios. Aquí se muestra un ejemplo:

// Find the smallest number in a list of integers
private int mininList(params int[] numbers)
{
  var min = Int32.MaxValue;
  for (var i = 0; i < numbers.length; i++) {
    int number = numbers[i];
    if (number < min)
      min = number;
  }
  return min;
}

Aunque he portado el ejemplo a C# para mayor claridad, tengo que admitir que ningún desarrollador de C# consideraría jamás escribir un fragmento de código como este. El motivo es que con C# y Microsoft .NET Framework puede conseguir muchos de los mismos resultados que usando LINQ. Encontré un código similar en un proyecto, salvo que estaba escrito en Java. En cierta ocasión, me contrataron para portar el código base a .NET Framework y C#.

También puede encontrarse con código como ese en un proyecto real de .NET. Puede tener en cuenta algunas consideraciones de legibilidad sin perder el propósito. La primera cosa que no está bien en esa función es el nombre. La convención es discutible. Al nombre le falta un verbo y usa una lógica de mayúsculas contradictoria. Probablemente algo como GetMinFromList habría sido un mejor nombre. No obstante, el punto del código más debatible es el calificador privado que se usa en el nombre.

Cualquier lector ocasional de ese código puede ver que la función actúa como una utilidad. En otras palabras, representa un trozo de código potencialmente reutilizable al que puede llamar desde una gran variedad de sitios dentro del resto del código base. Por tanto, hacerlo privado no siempre tiene sentido. En cualquier caso, los desarrolladores saben del poder de la regla YAGNI (You Ain’t Gonna Need It, no lo va a necesitar) y, con sensatez, suelen no exponer código que no es estrictamente necesario.

El autor de ese código podría haber previsto que la función sería potencialmente reutilizable, pero no en el momento de la escritura. Ese es el motivo por el cual esa función se escribió para poderse convertir fácilmente en una función auxiliar, pero se marcó como privada para que solo fuera visible dentro de la clase de host. Para los lectores externos, esta estrategia de codificación podría ser difícil de comprender. Sin embargo, es solo una decisión que requiere unas pocas líneas de comentarios para explicar lo que la motivó. Si no agrega comentarios apropiados, no está siendo un buen ciudadano del mundo de la codificación. Los lectores finalmente le encuentran sentido, pero se pierden minutos y, lo que es peor, hace que los lectores adopten una actitud algo hostil hacia el autor.

Reglas prácticas de legibilidad

La legibilidad del código es uno de esos asuntos cuya importancia está ampliamente reconocida, pero no necesariamente formalizada. Al mismo tiempo, sin algo de formalización, la legibilidad del código es prácticamente un concepto vacío. En general, es posible abordar la legibilidad con la regla de las tres C: una función combinada de comentarios, coherencia y claridad.

Las herramientas IDE son mucho más automáticas hoy de lo que lo eran hace tan solo unos años. Los desarrolladores no tienen la estricta necesidad de escribir archivos de ayuda e integrar su propia documentación en proyectos de Visual Studio. Las informaciones sobre herramientas están por todas partes y se crean automáticamente a partir de los comentarios. Los IDE modernos hacen tan sencilla la definición de comentarios institucionales que en lo único en lo que tiene que pensar es en el texto y el IDE hará el resto. Un comentario institucional es el clásico comentario que se agrega a los métodos y a las clases para proporcionar una concisa descripción de los objetivos. Debería escribir estos comentarios siguiendo los estándares de la plataforma o del lenguaje. También debería considerar estos comentarios como obligatorios para cualquier fragmento de código público que cree.

Evitar los comentarios obvios es otro paso fundamental en el camino hacia una mejor legibilidad. Los comentarios obvios lo único que agregan es ruido y no información relevante. Por definición, un comentario es un texto explicativo para cualquier decisión que toma en el código que no resulta obvia de manera inmediata. Un comentario solo debería ser una nota reveladora sobre algún aspecto concreto del código. 

La segunda C es de coherencia. Todos los equipos necesitan usar las mismas instrucciones para escribir código. Es incluso mejor si esas instrucciones se utilizan de forma corporativa. Cuando hablamos de instrucciones, muchos se detienen a definir lo que deberían ser las instrucciones y dejan de intentar dar sentido a lo que es correcto y lo que no. Me atrevo a decir que lo correcto o incorrecto es algo secundario en comparación con la importancia de hacer siempre lo mismo de la misma manera a lo largo del código.

Supongamos por un momento que está escribiendo una biblioteca que lleva a cabo manipulaciones de cadenas. En muchos lugares dentro de esta biblioteca, necesitará comprobar si una cadena contiene una subcadena determinada. ¿Cómo lo haría? En .NET Framework, así como en el SDK de Java, dispone como mínimo dos formas de conseguir el mismo resultado. Podría usar los métodos Contains o IndexOf. Esos dos métodos, sin embargo, sirven para distintos fines.

El método Contains devuelve una respuesta booleana y simplemente dice si la subcadena está contenida dentro de una cadena determinada. El método IndexOf devuelve el índice de base 0 donde se encuentra la cadena que se ha buscado. Si la subcadena no está presente, IndexOf devuelve -1. Por tanto, desde una perspectiva puramente funcional, puede utilizar Contains e IndexOf para lograr los mismos objetivos.

No obstante, envían un mensaje distinto a quien lee el código y obliga al lector a volver a leer el código para ver si hay alguna razón concreta por la que se use IndexOf en lugar de Contains. Por supuesto, una segunda lectura de la línea de un código por sí sola no es un problema. Pero cuando ocurre en la totalidad de un código base con miles de líneas de código, sí que tiene un impacto en tiempo y, consecuentemente, en costos. Ese es el costo directo de no disponer de un código con buena legibilidad.

Dar una sensación de coherencia en el código debería ser parte de su responsabilidad innata. Como desarrollador, debería aspirar a escribir código limpio desde el principio y no esperar a tener algo de tiempo para poder limpiarlo más tarde. Como responsable de equipo, debería reforzar la coherencia del código mediante políticas de registro. Idealmente, no debería permitir el registro de código que no supere una prueba de coherencia.

La última versión de ReSharper puede ser una ayuda considerable para concretar esta idea. Puede usar estas herramientas de línea de comandos gratuitas (un conjunto de herramientas independiente) para integrar formas de análisis de la calidad del código directamente en su integración continua (CI) o en su sistema de control de versión. Estas herramientas de línea de comandos pueden realizar inspecciones de código sin conexión. Este es el mismo conjunto de inspecciones de código que puede llevar a cabo en el acto dentro de Visual Studio con ReSharper instalado para encontrar las duplicaciones en el código. En función de las características de personalización de su CI, podría necesitar encapsular las herramientas de línea de comandos en un componente ad hoc. Obtenga más información sobre ReSharper en el sitio web bit.ly/1avsZ2R.

La tercera y última C de la legibilidad de código es de claridad. Su código es claro si le da un estilo de forma que se lea bien, con facilidad. Esto incluye una agrupación y un anidamiento apropiados. En general, las instrucciones agregan mucho ruido al código. En algunos casos no es posible evitar las instrucciones condicionales (un pilar de los lenguajes de programación), pero si se intenta limitar el número de instrucciones IF, se consigue controlar el anidamiento y es más fácil leer el código. También puede usar una estructura IF… ELSE … IF … ELSE en lugar de instrucciones IF anidadas.

Algunas tareas pueden requerir unas cuantas líneas de código y podría ser difícil o inapropiado realizar una refactorización "Extraer método". En este caso, es bueno mantener estas líneas en bloques separados por líneas en blanco. No cambia la esencia del código, pero lo hace más fácil de leer. Finalmente, si busca inspiración acerca de qué estilo aplicar a su código fuente, eche un vistazo a algunos proyectos de código abierto.

Cuanto más corto, mejor

Las líneas más largas son más difíciles de leer para el ojo humano. Ese es el motivo por el que los periódicos y las revistas imprimen sus textos en columnas. En cuanto a su código, debería hacer lo mismo y limitar tanto la longitud horizontal de las líneas como el desplazamiento vertical de los métodos. ¿Cuál es la longitud ideal del cuerpo de un método? Generalmente, 30 líneas debería ser el límite máximo que haga sonar una alarma que le sugiera refactorizar. Por último, una buena organización de las carpetas del proyecto y una correspondencia entre carpetas y espacios de nombres suele reflejar una buena organización de los elementos de código individuales.

Cuando plantee el tema de la legibilidad y la limpieza de código, a menudo se encontrará con una objeción común: escribir código limpio es difícil y consume mucho tiempo. Debería intentar neutralizar este punto de vista; dispone de dos formas para hacerlo. Una es usar una herramienta de ayudante de código, que ayuda a escribir código limpio mediante sugerencias de refactorización, inspecciones del código en busca de malos patrones y búsquedas de código duplicado o no alcanzado. Si puede disponer de todas estas características, ya no tiene excusas para no escribir código más limpio y legible. Las herramientas de ayudante de código están disponibles a través de los proveedores principales. Elija cualquiera de ellas, pero elija una.

La otra es hacer hincapié en la superación personal y en la actitud de sus desarrolladores para escribir código más claro como una cuestión de práctica general. Los desarrolladores experimentados hacen esto correctamente. La capacidad para saber aproximadamente cómo de lejos está de la versión final de su código, y entonces limpiarlo de verdad, es una característica clave que marca la diferencia entre los desarrolladores experimentados de los que tienen menos experiencia.


Dino Esposito es el coautor de “Microsoft .NET: Architecting Applications for the Enterprise” (Microsoft Press, 2014) y “Programming ASP.NET MVC 5” (Microsoft Press, 2014). Como evangelizador técnico para las plataformas .NET Framework y Android en JetBrains y orador frecuente en eventos mundiales de la industria, Esposito comparte su visión sobre el software en software2cents.wordpress.com y en Twitter en twitter.com/despos.

Gracias al siguiente experto técnico de Microsoft por revisar este artículo: James McCaffrey