Por favor, comenta el código

Recuerdo que cuando empecé a programar en la carrera (hace ya unos cuantos años), una de las cosas en la que más nos insistían los profesores era en que usásemos comentarios en nuestro código. Muchos comentarios. Prácticamente uno por cada línea. Visto con perspectiva, es posible que sólo trataran de averiguar la intención que había detrás de ese código tan enrevesado que escribíamos para cualquier cosa, o de obligarnos a pensar lo que queríamos hacer antes de empezar a escribir cada línea de código.

El hecho es que esa filosofía de sobreabundancia de comentarios llevaba escribir código de este estilo:

// suma los elementos de un vector
// param: vector con los datos a sumar
// return: suma de los elementos
int sumaVector(int[] vector) {
  // Variable para almacenar la suma de los elementos
  int suma = 0; 
  // Recorremos el vector 
  for (int i = 0; i < vector.length; i++) {
    // Obtenemos el elemento i-ésimo del vector
    int elem = vector[i];
    // Actualizamos la suma
    suma = suma + elem;
  }
  return suma;
}

Seguro que más de uno ha escrito código así más de una vez cuando estaba empezando. Lo malo de este tipo de comentarios es que no añaden gran cosa al código e introducen mucho ruido, consiguiendo el efecto contrario al deseado: no ayudan a entender mejor el código, sino que lo hacen más difícil. Además, existe el riesgo de que los comentarios se «desincronicen» y no digan lo mismo que el código, contribuyendo a la confusión.

Afortunadamente, en cuanto se adquiere algo de experiencia, se deja de usar este estilo de comentarios, pero entonces llega la fase de la «documentación automática». Muchos lenguajes tienen herramientas para generar documentación a partir de determinados comentarios, y esa documentación luego queda muy bonita en el autocompletado del IDE o en un HTML autogenerado, así que acabamos escribiendo cosas como ésta:

/// <summary>
/// Clase para representar una persona
/// </summary>
public class Person
{
  /// <summary>
  /// Obtiene o establece el nombre de la persona
  /// </summary>
  public string Name { get; set; }
}

Con esto hemos pasado del nivel aprendiz al nivel consultor. Ahora tenemos un montón de ruido en el código con comentarios que sólo dicen obviedades, pero éste está escrito siguiendo el manual de buenas prácticas de la empresa de turno.

Esto se puede «mejorar» introduciendo en cada fichero un aviso de copyright, o llevar a un nivel extremo haciendo que en la cabecera de cada clase o método se introduzcan el autor y el historial de modificaciones (supongo que para no tener que fiarse de control de versiones). Suena exagerado, pero existe código así.

Todo este (ab)uso de los comentarios acaba provocando la reacción lógica: matemos los comentarios.

Además lleva a una situación curiosa y es que los comentarios, que deberían servir para destacar cosas importantes del código, la mayoría de las veces quedan ocultos en regiones de los editores de texto o coloreados de forma que resalten menos sobre el fondo.

Escribe código autoexplicativo

Cuando se empieza la crítica feroz hacia los comentarios se suele incidir en que un comentario es una justificación para un código mal escrito, y que es mejor reescribir el código de manera que no haga falta ese comentario.

Este es un argumento perfectamente válido y es algo que debemos cuidar especialmente. En lugar de escribir este código:

// Procesa un pedido aplicando descuentos a clientes preferentes
public void Process(Order order)
{
  // Si es un cliente preferente...
  if (order.Customer.OrderCount > 5 && order.Customer.PurchasedAmount > 1000) 
  {
    // ...aplicamos un descuento del 5%
    order.Total = order.Total * 0.95m;
  }
}

Podemos escribir este otro código y ahorrarnos los comentarios:

public void ApplyDiscounts(Order order)
{
  if (order.Customer.IsPreferred) 
    order.ApplyDiscountPercentage(5m);
}

En estos casos, las refactorizaciones «extraer método», «introducir variable», «renombrar método», «renombrar variable» y compañía, son el camino a seguir para obtener para obtener un código más fácil de entender y mantener.

Los comentarios necesarios

Donde se nos empieza a ir la cosa de las manos es cuando empezamos a pervertir la idea de evitar comentarios redundantes y pasamos a renunciar a escribir cualquier tipo de comentario. Por mucho que queramos, hay cosas que no podemos capturar con el código y en las que un comentario nos puede ayudar a evitar problemas en el futuro.

Por ejemplo, hay veces en las que decidimos usar un algoritmo con una complejidad mayor en caso promedio, pero que para el tipo de datos que esperamos se comporta mejor:

// Usamos ordenación por selección en lugar de mergesort o quicksort
// porque los datos de entrada estarán casi ordenados y el coste será O(N)
var sorted = InsertSort(input);

Si no estuviese ese comentario, es fácil que quien mantenga nuestro código en el futuro (probablemente nosotros mismos) cuando vea que estamos usando un algoritmo «ineficiente» decida «optimizarlo» provocando al final una pérdida de rendimiento. Cuando tomamos una decisión que, a simple vista, resulta poco ortodoxa (pero razonada), dejarla documentada con un comentario es importante.

Esto mismo es aplicable a los casos en que escribimos un algoritmo complicado y queremos dejar constancia de la idea general o de las estructuras de datos que estamos empleando y por qué.

Es cierto que seguimos teniendo el problema de que los comentarios pueden mentir y no ajustarse a la realidad del código. Ese es un riesgo real y requiere disciplina para tratar de mitigarlo, pero no comentar el código suele ser peor.

Lo importante, en todo caso, es comentar el porqué, más que comentar el qué o el cómo. El cómo ya lo estoy viendo, es el código. El qué no debería ser necesario si escribes código autoexplicativo, pero por qué has decidido hacerlo así a sabiendas de que resulta extraño, eso sí que deberías explicarlo.

Existen otro tipo de comentarios que me duele mucho escribir pero que llega un momento en que son necesarios: los comentarios de documentación en lenguajes dinámicos.

Cuando utilizas un lenguaje estático puedes aprovechar el sistema de tipos y los nombres de las variables (o parámetros) para transmitir mucha información sobre el código, lo que ayuda a hacerlo más comprensible y hace que, como veíamos al principio del post, muchos comentarios de documentación sean poco útiles.

En un lenguaje dinámico se pierde parte de esa información y nos quedamos sólo con los nombres de las variables y funciones para indicar el tipo esperado. Esto se puede paliar utilizando tests como documentación, pero hay veces que tampoco eso es excesivamente práctico, ya que para averiguar cómo funciona una función nos obliga a ir a revisar sus tests (que pueden ser muchos) y a navegar por distintas áreas del código, saltando de la definición de la función a sus tests.

El uso de comentarios en estos casos para documentar el interfaz de la función es una gran ayuda (aunque seguimos corriendo el riesgo de que acaben desincronizados con el código, cosa que con los tests no pasa) y en lenguajes como Python o Clojure incluso forman parte de la sintaxis de definición de funciones.

Conclusiones

Los comentarios en el código se han ganado durante mucho tiempo mala fama debido al mal uso que se ha hecho de ellos, y eso ha llevado a una reacción exagerada anti-comentarios que acaba siendo contraproducente.

Nunca debemos olvidar que casi todo el código que escribimos hay que mantenerlo después, y eso implica poder comprenderlo dentro de un tiempo. Para ello lo fundamental es escribir un código que sea lo más autoexplicativo posible, pero hay consideraciones externas al código que pueden ser tan importantes como el propio código, y los comentarios son una buena forma de documentar esas decisiones.

3 comentarios en “Por favor, comenta el código

  1. Hola, Juanma.

    Me ha gustado mucho leer tu artículo. Es un buenísimo contrapunto a lo que opiné hace varios días en mi blog.

    Mi opinión extrema es similar a una reacción alérgica ante la obligación de abusar de ellos hasta el absurdo.

    Tengo que darte la razón. Los comentarios en el código tienen su utilidad y no hay motivo para exterminarlos a lo trabucaire, sin que quede ni uno. Incides en la necesidad de usarlos bajo determinadas circunstancias y pides que se comente, expresamente, incluso dándole título a tu publicación.

    Estoy de acuerdo en que en algunos casos sí puede ser conveniente añadir un comentario. Pero para mí esta práctica debe ser excepcional: Primero hemos debido intentar expresar la intención usando el propio código. Si aun así es necesario hacer alguna aclaración, adelante. El caso más claro es el que comentas sobre los algoritmos. De hecho, es uno de los pocos casos en los el código puede no ser suficiente. Sin embargo, no deja de ser algo excepcional, a no ser que trabajemos a diario con algoritmos (eso lo dejo para gente más lista que yo :))

    Querría hacer hincapié en algo que dices. Supuestamente un comentario de código es una algo que debería ser visible para que determinado aspecto sea evidente, como un texto en negrita. Cuando casi todo el texto está en negrita es como si no la hubiera. Como bien dices, también se llega al punto casi kafkiano de ocultar los comentarios (parece que en algún momento alguien se dio cuenta de que molestaban más que otra cosa…).

  2. Pingback: Documentar sí, pero ágil | Omar del Valle Rodriguez

Comentarios cerrados.