Comentando el Código

Autor: Águila Negra
Mail: andres.age(arroba)gmail(punto)com

Sí, ya sabemos que los auténticos programadores no ponen ni un solo comentario, que los machotes no necesitan esas mariconadas y que los trozos más complicados y los algoritmos más inentendibles incluso se ofuscan para que ni dios lo entienda (¡como debe ser!). Total, si ha sido dificil de programar, debe ser dificil de entender... :D Sin embargo, el código fuente está hecho por humanos y para humanos, el ordenador ya usará los binarios que para eso están ;) Por tanto un código debe tener algo de legibilidad... y los comentarios juegan un papel importante en ello.

Suele haber muchos tipos de comentarios, según las categorías de los programadores:

1 - Enamorados

A pesar de que por definición un programador es un friki antisocial (lease la primera parte de este artículo con bastante sarcasmo), hay algunos especímenes raros (y tan raros) con vida social! Y algunos tienen novia y todo... y lo que es peor, son tan horteras que llenan el código de

-- Te amo, cariño

-- Sueño con tu pelo, mi corazón late cuando pienso en tí bla bla bla

Lo que les convierte en el hazmereir de media oficina en cuanto alguien más lee el código. Eso sí, no ponen ningún comentario más, ni siquiera en la especificación de las librerias, y has de adivinar para que rayos sirve aquella función "calcular". Aunque si algun dia dejas la informática y encuentras novia, no tendrás que recurrir a los versos de Becker para conquistarla...

2 - Amargados

Debido al stress, son los que despotrican contra el jefe o el profesor porque los plazos son los peores posibles. Suele estar cargado de insultos contra el hijo de ... del jefe o el c... del profesor que no para de dar por c... Si un compañero lee el código, o se echará unas risas o asentirá, pero tampoco sabrá para que está la función "calcular"...

3 - Aburridos

De muchas clases, está el que escribe estrofas enteras de heavy metal o reggaeton en la cabecera de los algoritmos, o el pesimista sincero que pone

-- Dios, esto va a petar mala manera y cuando lo haga estaré hasta el cuello de m...

-- Esto no se para que m... sirve, pero funciona así que no tocar

-- Esto lo hizo pepito, no tengo npi de que hace, pero funciona

Y demás lindeces, normalmente empiezan por m, e incluyen la palabra "fuck" más que la letra "e" en el quijote. El codigo fuente del kernel de linux o la versión filtrada del Windows 2000 está comentada de esta forma en su gran mayoría.

4 - Reprimidos

Un friki antisocial, como debe ser, pero que por dentro no quiere serlo. Tiene la necesidad biológica de expresarlo todo, y como es muy callado y reservado escribe su vida en los comentarios. Lo comenta todo, su media es de 5 lineas de comentarios por linea de código útil. Y en las cabeceras de las librerias se multiplica por 10. No solo escriba su aburrida vida sin sentido, sino también cosas del código (aleluya, el primero que lo hace). Desgraciadamente, aunque comenta el código, este es totalmente redundante

x:=x+1; -- Sumamos 1 a x
procedure calcular is -- declaramos el procedimiento calcular

Cuando lees su código piensas en porque no marcastes economía en la hoja de la universidad tras aprobar la selectividad. Gracias a este tipo de personas se inventaron los programa que eliminan los comentarios de los códigos, puesto que a veces... sin comentarios se hace legible y todo!!!

Las 3 categorías anteriores suelen poner nombres ilegibles a las variables

  a1: boolean;
  a2: integer;
  a3: boolean;
  type a4 is (a,b);
  a5: string (1..a2);
  type a6 is array (1.. a2) of a4:
  a7: a6;

O algunos, ya de mala leche, nombres esotéricos y ofuscados. Mientras, este ultimo tipo de programador intenta explicar todo, y las variables hablan por si mismas. Quizás demasiado...

Variable_que_sirve_para_saber_cuando_salir_del_bucle: boolean;

5- Los que no saben que es un debugger

Realmente cualquiera de los cuatro anteriores puede caer en esta categoría ocasionalmente.
Son lo que ponen lineas de código como
put("lalala");
en C:
printf("lalala");
para saber si un fragmento se ejecuta correctamente. Nadie les ha enseñado a usar un debugger, o son tan vagos que no quieren usarlo.
Mejor ponen esa linea, compilan y ejecutan. Después son tan vagos que en vez de presionar una docena de veces la tecla Supr, prefieren presionar dos veces la tecla de comentarios. Por eso su código está lleno de
-- put("lalala");
en C:
// printf("lalala");

Este tipo de comentarios tampoco aporta nada útil normalmente. Solo sirven para adivinar (al estilo Sherlock Holmes) que el programador tiene una laguna en sus conocimientos, y a veces te planteas el que se debería dar un curso de "HOW TO usar un debugger!" - además de que el algoritmo no funcionó correctamente en su momento. Por tanto, si no funciona, puedes adivinar que el fallo estará "por ahí", con un intervalo de confianza del 95% de 5 lineas.

Desde luego, ninguna de estas 4 (o 5 extendidas) categorías es muy útil a la hora de comentar el código, aunque englobe la mayor parte de programadores que existen (especialmente la última).

En teoría, un comentario debería señalar para que sirve el programa. Que se supone que debe de hacer, independientemente de como esté implementado. Lo que haga, se puede ver ejecutandolo ;) pero se debería indicar para que está esta linea o aquella.

Muchos programadores expertos opinan que el principal comentario (y casi casi el único, exceptuando cosas especiales o determinadas lineas) que debería tener un algoritmo es poner la precondición y la postcondición. La precondición te dice en que estado está ANTES de ejecutarse el algoritmo, es decir con que parámetros debe empezar el algoritmo para que su ejecución sea correcta. La postcondición, es el estado POSTERIOR a la ejecución del algoritmo, es decir que es lo que ha hecho.
Así, poniendo un par de lineas de precondición y postcondición, se puede comentar una función entera. O si dentro hay while o loops se le puede aplicar lo mismo, poniendo pre y post condición. Y por supuesto si algo requiere un comentario especial, se pone, pero lo mínimo. Y con eso el código debe quedar entendible, alguien que lo lea debe tener una visión clara de como funciona el programa, QUE se supone que hace, con que valores funciona correctamente, y en general tiene una visión profunda del algoritmo.

Por ejemplo, este algoritmo de división

r:=a; q:=0;
  while r>=b loop
  r:=r-b; q:=q+1;
end loop;

¿Que tiene que cumplir sus parámetros de entrada para su correcto funcionamiento? Que tanto a como b sean mayores que 0. Y en que estado termina? Dandote un resto r, menor que el divisor y un cociente q.
Entonces

Prec: a>=0 ^ b>0
Post: a=b*q+r ^ 0<=r<b

O si es muy formal, en lenguaje natural

Prec: a y b dos naturales. b es mayor que 0 y a mayor o igual que 0.
Post: a=b*q+r y r está entre b y 0.

O este otro algoritmo, que suma los cuadrados de 0 hasta n.

i:=0; p:=1; q:=0; s:=0;
  while i<n loop
  i:=i+1; q:=q+p; p:=p+2;
  s:=s+q;
end loop

A simple vista es muy difícil "adivinar" que hace este algoritmo.
Pero si ponemos

Prec: n mayor que 0
Post: s es el sumatorio de los cuadrados de los números entre 0 y n.

o bien

Prec: n>=0;
Post: s= (Sum K: 0<k<=n : k**2)

Pues queda absolutamente claro que es lo que debe hacer este algoritmo y cuales son los parámetros de entrada válidos.
Veamos ahora un algoritmo más complejo (por ejemplo, el de una multiplicación hecha recursivamente que ha sido pasada a iterativo)

a:=u; b:=v; s:=0;
  while a>0 loop
  s:=s*2 + a mod 2;
  a:=a/2; b:=b*2;
  end loop;
  prod:=0;
  while not s=0 loop
  r:=s mod 2; s:=s/2; b:=b/2;
  if r/=0 then prod:=prod+b; end if;
  end loop;

se puede explicar claramente esta metodología de prec y postc.

Prec: u,v>=0;
Post: prod=u*v

De esta manera, algoritmos que pueden ser "complicados" de entender se sintetizan rápida y fácilmente. Otro ejemplo, un poco más "realista": en un arbol podemos usar la función "primero" para recorrerlo en inorden. Podemos especificar "primero" facilmente

  function primero (x:in nodo) return nodo;
  -- Prec: x es un nodo de T
  -- Post: devuelve el 1 nodo a visitar del subarbol de raíz x

O el algoritmo de Hanoi (para que el no lo conozca, que busque el enunciado en google) de forma recursiva

  procedure hanoi (h: in integer; a,b,c: torre);
  -- Prec: Los discos a,b y c están bien formados.
  -- h>0 y la torre a tiene al menos h discos.
  -- Los h discos de la cima de a son más pequeños
  -- que cualquier disco de las torres b y c.
  -- Postc: Los h discos que estaban inicialmente en la cima de a
  -- ahora están en la cima de c.

Quizás a la hora de llevarlo a la práctica puede ser un poco difícil (estos casos expuestos son muy sencillos, para dar una idea de que consiste la precondición y la postcondición), pero si uno se pone a usarlos se acostumbra, y sabrá adaptarlo a cualquier algoritmo. Si el código resultante está bien comentado y es fácil de entender (además de funcionar :P), habrá cumplido su objetivo. Y el resultado será muy limpio y formal, además de sistemático.