martes, 25 de junio de 2013

¿34000 qué?

 34000 visitas

El pasado día 14 de junio del 2013 a las 4:02 am -5GMT estaba tratando de redactar un artículo para mi blog. Coincidentemente mis ojeras descubrieron que el número de visitas había ascendido a 34001. Así que esta breve nota tiene como objetivo felicitar a todos aquellos que siguen interesados en los temas que se discuten en este blog. Espero que el interés se incremente porque realmente ahora es que empieza la mejor parte. Le invito a suscribirse mediante RSS para que no se pierda los próximos artículos acerca de varios temas interesantes en las ramas de la cibernética, edición de video, software libre, temas jurídicos, economía, música, lingüística, un poco de filosofía no muy elevada ... y hasta los temas de su preferencia. Todo es posible ... simelo pides :).

Desde hace tiempo he deseado hacer resúmenes semestrales de la actividad de mi blog parecidos al reporte del inicio del año 2011 y el reporte del primer trimestre del año 2011. Sinceramente no he tenido mucho tiempo ... pero ya se me ocurrirá algo al respecto.

lunes, 24 de junio de 2013

El (posible) significado de los números de versiones

Semantic versioning

A continuación les ofrezco unos comentarios acerca de un enfoque llamado semantic versioning. Esta guía ha sido formalizada por Tom Preston-Werner (inventor de Gravatar y co-fundador de Github) para lidiar con las dependencias de las aplicaciones de software. Muchas veces leí en las conversaciones de la lista bloodhound-dev@incubator.apache.org que los números de las versiones son ''baratos''. Para un proyecto que está en su fase inicial este consejo creo que es válido. Sin embargo, en mi opinión se deben considerar otras variantes para desarrollos con mayor madurez que implican un número considerable de usuarios. De gran importancia es este tema para librerías que son utilizadas muy frecuentemente para desarrollar distintos tipos de software.

¿Qué es el versionado semántico?

La versión 2.0.0 define este sistema de numeración de versiones de la siguiente manera:

  1. Cada versión se identifica utilizando tres números separados por punto MAJOR.MINOR.PATCH
    e.g. 2.3.1
  2. Los números de las versiones sucesivas se incrementan considerando las siguientes
    reglas generales
    1. Se incrementa MAJOR cuando se realizan cambios incompatibles en la API,
    2. Se incrementa MINOR cuando se añaden nuevos elementos compatibles con versiones anteriores,
    3. Se incrementa PATCH cuando se corrigen errores y el resultado es compatible con versiones anteriores.
  3. Se permiten ciertos calificadores para distribuciones todavía en desarrollo
    (e.g. alpha, beta, release candidate, ...)

¿Para qué sirve?

El objetivo fundamental consiste en prevenir, o al menos tener la capacidad de detectar casos del fenómeno conocido como dependency hell. En el ámbito de la ingeniería de software es muy importante poder hacer algo al respecto mientras se desarrollan sistemas complejos con gran número de dependencias. Bajo este esquema los números de versiones y la manera en que se asignan ofrecen rápidamente una información valiosa acerca del código y la compatibilidad de las mejoras incorporadas de una versión a la siguiente.

Ejemplo : La aplicación A se construye utilizando la versión 2.3.6 de la librería L.
Los usuarios finales la instalan de forma automática desde un repositorio que maneja las
relaciones entre los diferentes paquetes de software disponibles, quizás compilándolos en
tiempo de instalación. Como la librería L respeta los términos del versionado semántico
y la compatibilidad entre las versiones de la rama 2.x.x entonces los autores de la aplicación A
pueden especificar las restricciones L>=2.3.6 , L<3.0.0. En este rango de versiones
los autores de la librería L crean la expectativa de mantener compatibilidad en la API con las consecuentes garantías para permitir el correcto funcionamiento de A.

En mi experiencia como programador y arquitecto de sistemas considero útiles los puntos siguientes:

  • Punto 5: La versión 1.0.0 define la primera API pública estable.
  • Puntos 9, 10, 11: El estándar no impone un significado especial para las versiones de prueba.
    Existen modelos que le asocian un significado también a estas distribuciones intermedias, por ejemplo
    el esquema de versiones de Apache™ Subversion.
  • Se recomienda que la caducidad de una parte de la API se debe ofrecer inicialmente en una versión
    que incremente el número MINOR para que las dependencias puedan prepararse para adoptar versión
    subsecuente que incremente el número MAJOR.

Conclusiones

Existen otros esquemas para numerar las versiones. Apache™ Bloodhound no adoptó el versionado semántico. En este caso se consideró el número MAJOR como una señal. Es por eso que la próxima versión será la 0.6.0 a pesar de que es substancialmente diferente a (y en momentos incompatible con) las versiones precedentes; en especial definiendo la API pública de la solución multi-productos.

Sin embargo recomiendo mucho el uso del versionado semántico, el cual empleo en otros proyectos. Para estar al tanto de su utilidad es posible suscribirse mediante RSS.

viernes, 14 de junio de 2013

Tutorial de LD_PRELOAD, segunda parte

man ld.so

Un artículo previo mostraba cómo remplazar una función de la librería estándar de C con una versión personalizada. Esta nota explica lo que es preciso hacer para invocar la función original desde la nueva función.

Comencemos por recordar el ejemplo presentado anteriormente. Todo consistía en un programa llamado prog.c que invocaba la función fopen.


#include <stdio.h>

int main(void) {
    printf("Calling the fopen() function...\n");

    FILE *fd = fopen("test.txt", "r");
    if (!fd) {
        printf("fopen() returned NULL\n");
        return 1;
    }

    printf("fopen() succeeded\n");

    return 0;
}

¿Cómo hacer entonces una función que pueda remplazar a fopen y al mismo tiempo sea capaz de invocar la función fopen de la libraría estándar de C? Veamos el código de myfopen.c.


#define _GNU_SOURCE

#include <stdio.h>
#include <dlfcn.h>

FILE *fopen(const char *path, const char *mode) {
    printf("In our own fopen, opening %s\n", path);

    FILE *(*original_fopen)(const char*, const char*);
    original_fopen = dlsym(RTLD_NEXT, "fopen");
    return (*original_fopen)(path, mode);
}

Como se puede apreciar la librería exporta la versión personaizada de la función fopen. Prestando atención se puede constatar cómo se obtiene la referencia a la función original pasando el símbolo RTLD_NEXT a dlsym. Es muy importante definir el símbolo _GNU_SOURCE para tener acceso a RTLD_NEXT en dlfcn.h. De esta forma se coninua la resolución del símbolo en cuestión en el orden de búsqueda a continuación de la librería actual. La compilamos de la siguiente manera:

$ gcc -Wall -fPIC -shared -o myfopen.so myfopen.c -ldl

Al ejecutar el comando de ejemplo en cuestión con ayuda de la variable de entorno LD_PRELOAD, esto es lo que se obtiene:

$ LD_PRELOAD=./myfopen.so ./prog
Calling the fopen() function...
In our own fopen, opening test.txt
fopen() succeeded

Este truco es realmente útil para cambiar el funcionamiento de partes del sistema o depurar detalladamente ciertos detalles. Le invito a suscribirse mediante RSS para que no se pierda los próximos artículos de esta serie.