En los títulos y los textos vais a encontrar unas cuantas citaciones cinematográficas (y si, soy un cinéfilo). Si no os interesan podéis fingir no verlas, ya que no son fundamentales para la comprensión de los post...

Este blog es la versión en Español de mi blog en Italiano L'arte della programmazione in C. Espero que mis traducciones sean comprensibles...

domingo, 9 de septiembre de 2012

No Comment 2 - El regreso
cómo escribir los comentarios en C - pt.2

Hoy ha llegado el momento de completar el discurso del No Comment del que hablamos aquí. Se habló, por así decirlo, del nivel micro (los comentarios sobre los bloques de código), pero nos perdimos el nivel macro, es decir, el propio contenedor (el file) y los grandes bloques de código que son las funciones. Decidme la verdad: si trabajáis (o habéis trabajado) en un equipo, ¿cuántas veces habéis abierto un file escrito por un compañero (que pertenece a la religión No Comment, devoto y practicante) y habéis descubierto que la única pista sobre el código contenido era el nombre del fichero mismo? Y, ya que por la Ley de Murphy, el distinguido compañero estaba de vacaciones (justas y merecidas), habéis pasado el día entero sólo para entender de qué iba el file, y sólo en ese momento, habéis empezado a descifrar el código gracias a la Piedra de Rosetta.

Un file necesita un header y las funciones (al menos las más importantes, que suelen ser las globales) necesitan una cabecera hecha como dios manda (pero también las funciones estáticas se merecen un mínimo de presentación). Espero que el mensaje sea claro.

Bien, y ahora ¿cómo podemos hacer una cabecera? Aunque las posibles variaciones son infinitas, diría que, para empezar, algo muy sencillo como esto, podría funcionar:
/*!
 *  FILE
 *     getComments.c - extracción comentarios de un file C
 *  PROJECT
 *     myDoc - generación automática documentación
 *  FUNCTIONS
 *     globales:
 *        getComments()
 *     estáticas:
 *        formatLine()
 *  AUTHOR
 *     A.Abate
 *  OPERATING SYSTEM
 *     Linux (all versions)
 *  COMPILER
 *     GNU gcc
 *  RELEASE
 *     1.0 (Septiembre 2012)
 */ 
Obviamente se puede abundar más o menos en descripciones. Por ejemplo, si el archivo contiene el código de un protocolo de comunicación, se puede agregar un bloque de descripción (un dibujo en texto) con las entidades involucradas y el flujo de mensajes de comunicación.

En cuanto a las funciones importantes, se puede utilizar la sintaxis clásica de las Man Pages de Unix (y Linux), o sea, hacer algo como esto:
/*!
 *  NAME
 *     getComments - examina un file C para extraer los comentarios
 *  SYNOPSIS
 *     int getComments(
 *        char *inpath,
 *        char *oupath)
 *  DESCRIPTION
 *     Extrae los comentarios de un file C con pathname <inpath> y los
 *     escribe en un file de documentación con pathname <outpath>.
 *  RETURN VALUE
 *     0 a operación efectuada. Un valor negativo en caso de error
 */ 
Y, también aquí, uno puede abundar más o menos con las descripciones, añadiendo, por ejemplo, los detalles de todos los códigos de retorno, y, si es necesario, mediante la inserción de un apartado EXAMPLES adicional, con breves ejemplos de uso.

Como los mas observadores habrán notado, la primera línea de los dos ejemplos anteriores comienza con "/*!", que contiene un símbolo de reconocimiento para una posible herramienta para la auto-generación de la documentación (como Doxygen). Y aún los mas observadores habrán notado que el contenido de los dos ejemplos es acerca de la auto-documentación. El hecho es que he decidido ofrecer un caso real, y que podría ser mejor que escribir, ad-hoc, un instrumento de documentación simple que he escrito y probado en un muy poco tiempo (es realmente muy simple, pero puede ser mejorado) .

Pues bien, la mini-herramienta estaría (casi) toda aquí:
int getComments(
    char *inpath,
    char *oupath)
{
    char *line = NULL;
    size_t len = 0;
    int retcode;
    bool start_comment = false;

    // abro el file de input
    FILE *fpin;
    if (fpin = fopen(inpath, "r")) {
        // abro el file de output
        FILE *fpout;
        if (fpout = fopen(oupath, "w")) {
            // leo el file de input
            while (getline(&line, &len, fpin) != -1) {
                // test final comentarios para reset flag start_comment
                if (strstr(line, "*/") && start_comment) {
                    start_comment = false;
                    fprintf (fpout, "\n\n\n");
                }

                // test flag start_comment
                if (start_comment) {
                    // formateo y escribo la linea en el file output
                    fprintf(fpout, "%s", formatLine(line));
                }

                // test inicio comentarios para set flag start_comment
                if (strstr(line, "/*!"))
                    start_comment = true;
            }

            // libera recursos y set retcode=OK
            fclose(fpout);
            free(line);
            retcode = 0;
        }
        else
            retcode = -2;    // fopen err: set retcode=err

        fclose(fpin);    // libera recursos
    }
    else
        retcode = -1;    // fopen err: set retcode=err

    // sale con el retcode seteado
    return retcode;
}
Yo diría que el código es tan intuitivo (y comentado) que no hay mucho más que añadir: se busca el código de referencia (/ *!) Y se copia en un archivo de documentación todo lo que sigue hasta el final del comentario. La función formatLine() (que he omitido) puede no hacer nada (es decir, devolver directamente la línea pasada), o hacer algo de procesamiento más o menos sofisticado (como mínimo recomiendo quitar el inicio de linea como " *"). Yo, para probar la aplicación, he escrito un main() que lee todos los files fuentes de una directory y escribe los resultados en otra directory (y, yo diría que funciona bien).

Lo que se ha presentado es una alternativa rápida a las herramientas del tipo de Doxigen, que están, por supuesto, recomendadas para grandes proyectos (aunque la alternativa artesanal descrita no esta mal).

Termino con un mensaje para los que piensan (como ya se ha dicho aquí) que escribir comentarios (y, aun mas, los headers y las descripciones de funciones) sea una pérdida de tiempo que alarga el tiempo de desarrollo. Hay que tener la mente abierta, pensar a largo plazo: aunque el tiempo de desarrollo aumente un 10% (y documentar no necesita mucho tiempo, sobre todo si lo haces mientras escribes el código), habrá un día en que se recuperará con intereses el tiempo perdido inicialmente, por ejemplo, en la primera ocasión de mantenimiento o modificación (tratad de hacerlo en un código No Comment, y luego me contáis...). Y el tiempo es oro.

Hasta el próximo post.

No hay comentarios:

Publicar un comentario