Blog

Juan Mellado, 8 Febrero, 2014 - 11:08

Los servidores de integración continua se utilizan principalmente para garantizar que todo el código que se sube a los repositorios de un proyecto es correcto. Entendiendo como "correcto" que el nuevo código permite seguir compilando el proyecto sin errores y que pasa las pruebas automatizadas (tests unitarios, de integración, ...)

Su funcionamiento es sencillo. Se componen de procesos que corren automáticamente y comprueban cada poco tiempo si ha habido cambios en los repositorios de código, aunque normalmente también admiten que se les programe para, por ejemplo, que se ejecuten a una determinada hora. Pero por lo general se configuran para que cuando se detecte un cambio se descarguen el código, lo compilen si es preciso, ejecuten las pruebas, y si todo fue correcto generen los binarios, empaquetados, o lo que requiera el lenguaje de programación utilizado y la configuración del proyecto.

El resultado de cada ejecución de cada proceso de un servidor de integración continua normalmente se puede consultar a través de una web que proporciona el propio software del servidor. De esta forma cualquiera puede ver si el código actual subido al repositorio compila antes de descargárselo a su máquina local.

Otras de las ventajas, cuando se trata con lenguajes de programación que tienen que compilarse, como C/C++ o Java por ejemplo, es que la generación del ejecutable o empaquetado se realiza siempre en una misma máquina, en un entorno estable y controlado, en vez de en la máquina de un desarrollador cualquiera del equipo.

Los proyectos de código abierto tradicionalmente se limitaban a ofrecer el código fuente y las instrucciones para su compilación en algún repositorio público gratuito, y dependiendo del lenguaje de programación y de las características del proyecto, los binarios y recursos resultantes para los sistemas operativos más extendidos que cada proyecto generaba según sus posibilidades, aunque no todos podían permitirse generar todo para todos los entornos.

Hoy en día, en el desarrollo de cualquier proyecto, medianamente serio, en cualquier empresa, también medianamente seria, los servidores de integración continua son, como se suele decir, un "must". Es decir, no se concibe el desarrollo de un proyecto sin ellos. Lo único que tiene que decidirse es que software utilizar, ya sea uno gratuito, como Jenkins, o uno comercial, como TeamCity, por poner un par de ejemplos.

Sin embargo, para los proyectos pequeños que algunos desarrollamos en casa y luego liberamos como código abierto esto no suele ser una opción. No tanto por la instalación y configuración del software del servidor, sino por el propio servidor. A la mayoría no nos resulta rentable invertir en la adquisición, mantenimiento y actualización de un servidor de integración continua propio. Afortunadamente, como ocurre con los repositorios gratuitos, también existen servidores de integración continua gratuitos.

Yo en particular estoy ahora utilizando drone.io, que permite utilizarlo de forma gratuita para tantos proyectos de código abierto como se quiera, aunque también tiene tarifas para repositorios privados. Yo lo utilizo principalmente porque tiene un buen soporte para Dart, el lenguaje que llevo utilizando para mis proyectos personales en los últimos años.

La configuración de los proyectos se realiza a través de una interface web muy clara y bien organizada. Los parámetros básicos que se tienen que indicar para cada proyecto son la url del repositorio, el lenguaje de programación (C/C++, Dart, Erlang, Go, Groovy, Haskell, Node, Java, PHP, Python, Ruby, Scala, ...), las variables de entorno, y los comandos (Linux) a ejecutar para compilar el proyecto y ejecutar las pruebas.

Si el proyecto utiliza una base de datos, la configuración permite indicar el tipo de base de datos que se necesita para la ejecución de las pruebas (MySQL, PostgreSQL, MongoDB, Redis, Memcache, ...) El servicio creará automáticamente una instancia de base de datos del tipo seleccionado para poder ejecutar las pruebas y la destruirá también de forma automática una vez acabadas. La url, usuario y password son siempre los mismos, y están perfectamente documentados en las páginas de ayuda de la propia web.

Otra característica interesante del servicio es que permite realizar deploys automáticos. Es decir, copiar el resultado de la compilación a otro servidor y desplegar la nueva versión si es preciso.

Por último, comentar que el servicio ofrece urls que se resuelven como imágenes y con las que se puede comprobar de un sólo vistazo el estado que se encuentra un proyecto:

La imagen muestra el resultado del último build, de color verde si se ejecutó con éxito, o de color rojo si falló. Pinchando sobre la imagen se accede a una página web donde se muestra el detalle de la ejecución de cada comando como si se tratara de una consola de línea de comandos.

Temas: Desarrollo
Juan Mellado, 26 Enero, 2014 - 12:19

La primera vez que me planteé subir algo de código de forma abierta a Internet usé los repositorios de Google Code, y desde entonces hasta hoy he acumulado hasta 15 repositorios distintos correspondientes a otros tantos proyectos:

https://code.google.com/u/101388150953455772115/

Sin embargo, hoy en día el servicio más popular de este tipo es sin duda GitHub. Y hasta casi cierto punto se le puede considerar una especie de red social para desarrolladores. Llevaba un tiempo rondándome la idea de darle un tiento, y ayer por fin me di de alta y repliqué allí todos mis repositorios:

https://github.com/jcmellado?tab=repositories

Curiosamente en Google Code siempre he utilizado Subversion para el control de versiones, pero en GitHub he querido cambiar, honrando el nombre del servicio, y he utilizado git. Para mi no deja de ser un sistema de control de versiones u otro, no tengo preferencias en ese aspecto.

En un principio quería tener los dos servicios sincronizados, pero después de leer documentación y rebuscar un poco por Internet no he encontrado ninguna solución que me acabase de convencer al cien por cien. Aunque evidentemente mantener dos repositorios para un mismo proyecto no tiene sentido a menos que estén automáticamente sincronizados. De momento me he conformado con que GitHub sea una copia de Google Code y con el tiempo ya iré decidiendo como gestionar todo de la mejor manera posible.

Desde el punto de vista técnico, los pasos que he tenido que dar para crear los repositorios en git a partir de uno en Subversion (svn) están bien documentados en Internet, así que sólo he tenido que ir siguiendo el guión.

Primero crear un repositorio git en local haciendo referencia al repositorio svn:

git svn init https://<PROYECTO>.googlecode.com/svn/ --stdlayout

Después recuperar el contenido del repositorio svn:

git svn fetch

En mi caso no tengo ramas, ni quería mantener en git ninguna, ni siquiera la trunk de svn, así que la borré:

git branch -d -r trunk

Un pequeño problema con el que me encontré, es que al subir el historial de cambios de svn a git, mostraba mi dirección de correo electrónico en vez de mi nombre de usuario de GitHub. Afortunadamente encontré en Internet una instrucción para modificar todo el historial de cambios:

git filter-branch -f --env-filter
  "GIT_AUTHOR_NAME='<USUARIO>'; GIT_AUTHOR_EMAIL='<CORREO>';
   GIT_COMMITTER_NAME='<USUARIO>'; GIT_COMMITTER_EMAIL='<CORREO>';"
HEAD

El último paso es subir todo desde el repositorio local al repositorio real remoto en GitHub:

git remote add origin https://github.com/<USUARIO>/<PROYECTO>.git

git push -u origin master

Puede parecer mucho trabajo estar haciendo todo esto cada vez, pero en la práctica no actualizo tanto mis proyectos para como que sea un problema, y los repositorios en GitHub se pueden borrar y recrear completamente muy fácilmente.

Temas: Dart
Juan Mellado, 19 Enero, 2014 - 12:11

DartSSRP (SQL Server Resolution Procotol) es un protocolo de Microsoft que permite descubrir todas las instancias de base de datos SQL Server que se encuentran disponibles en una red o en un servidor concreto. Proporciona los nombres de los servidores disponibles, los nombres de las instancias que se encuentran ejecutándose en dichos servidores, sus versiones, y los parámetros de conexión que un cliente necesita para poder conectarse a dichas base de datos.

El protocolo se basa en enviar un mensaje a través de UDP a una dirección IP tipo broadcast/multicast para obtener todas las instancias de base de datos que se encuentran en una red, o a una dirección IP de un servidor concreto conocido para obtener las instancias que se encuentran ejecutándose en dicho servidor.

Cuando un mensaje SSRP enviado desde un cliente llega a un servidor SQL Server, este responde con otro mensaje en el que se listan todas las instancias de base de datos que hay en el servidor. En dicho mensaje de respuesta se incluyen todos los protocolos de comunicación soportados por cada una de las instancias, así como los parámetros concretos de conexión para cada protocolo que un cliente necesita conocer para poder abrir una conexión. Por ejemplo, si una instancia admite conexiones a través de TCP/IP, en el mensaje de respuesta se retorna el número del puerto TCP en el que está escuchando la instancia. O, por ejemplo, si la instancia admite conexiones a través de una pipe, en el mensaje de respuesta se retorna el nombre de la pipe que mantiene abierta la instancia.

Además de esto, el protocolo también permite obtener el número de puerto TCP en el que se encuentra escuchando el SQL Server DAC (Dedicated Administrator Connection), que es un servicio especial de SQL Server que permite conectarse directamente a una instancia, sobre todo para realizar labores de administración y diagnóstico, y que es totalmente independiente del resto de conexiones ordinarias que se abren habitualmente para ejecutar sentencias SQL contra base de datos.

dart-ssrp es una librería cliente que implementa este protocolo y he escrito en Dart, como viene siendo mi norma últimamente, ya que sigo encontrando muy atractiva y productiva la experiencia de desarrollo con este lenguaje. En la práctica no creo que el paquete sea de mucha utilidad, es más bien un ejercicio de programación, en particular con UDP, que es un protocolo que Google ha añadido en la última release de Dart, concretamente la 1.1.1.

El protocolo es bastante sencillo de implementar, ya que los mensajes que se intercambian son muy simples. La parte más complicada que he encontrado en la especificación es el formato que utiliza para intercambiar cadenas de caracteres. La especificación se basa en el uso de MBCS (MultiByte Character Set), sin especificar ningún estándar de representación en concreto, y presuponiendo además que el codepage de la máquina del cliente y del servidor es el mismo. Dart utiliza UTF-16 para representar internamente las cadenas de caracteres, así que la solución ideal sería realizar una conversión de UTF-16 a MBCS para las cadenas enviadas desde el cliente al servidor, y de MBCS a UTF-16 para las cadenas enviadas desde el servidor al cliente. Los algoritmos están descritos en [MS-UCODEREF], pero es bastante material por si solo como para hacer otra librería. De momento me he conformado con transformar directamente los code units de UTF-16 en arrays de bytes y viceversa. UPDATE: Después de escribir esta entrada en el blog he estado buscando un rato y he visto que la clase SystemEncoding parece hacer exactamente lo que necesito.

En otro orden de cosas, comentar que en estos últimos tres meses he trabajado en otros tres proyectos personales distintos. Uno de ellos lo publiqué hace un par de meses (dart-fed), aunque nunca he hablado de él en el blog. Y de los otros dos, uno está en una fase muy temprana de desarrollo, y el otro aunque está casi terminado posiblemente no salga nunca de mi disco duro, ya que el código no está todo lo bien escrito que me gustaría. Ya veremos.

Temas: Personal
Juan Mellado, 15 Septiembre, 2013 - 19:15

VelitaOcho años de blog, que se dice pronto. A primera vista parecería que este último año ha sido un poco flojo, ya que apenas he publicado seis posts, pero teniendo en cuenta que la mitad de ellos fueron para anunciar nuevos proyectos terminados, la verdad es que no me puedo quejar.

- dart-solitaire: Una versión del clásico juego del solitario escrito en Dart. Hace años, cuando la gente pensaba que JavaScript sólo servía para validar formularios, programé este juego en JavaScript. Me pareció una buena idea hacer una nueva versión en Dart para compararla con la de JavaScript y aprovechar la ocasión para añadir opciones que nunca llegué a implementar la primera vez. Esta vez incluso añadí el famoso efecto de final de partida con las cartas rebotando. Espero ver más "juegos HTML5" implementados en Dart en el futuro.

- dart-odbc: Un binding de Dart a ODBC. Es decir, una librería que permite utilizar ODBC desde Dart, de forma que las aplicaciones en Dart puedan conectarse a cualquier base de datos que tengan un driver ODBC, algo que tienen prácticamente el 100% de las base de datos hoy en día. Hacer un wrapper sobre esta librería para ofrecer una API más sencilla, y más "Dart-oriented", sería un proyecto interesante, sobre todo por que de momento Google no parece tener intención de desarrollar su propio ORM para Dart.

- dart-neuquant: Una librería para reducir el número de colores de una imagen sin reducir la calidad de la misma utilizando una red neuronal. Este proyecto fue un desarrollo rápido, ya que prácticamente es un port a Dart de la versión original de la librería que estaba escrita en C. Los resultados son impresionantes, es capaz de reducir una paleta de cientos de miles de colores en otra de apenas 256 colores escogiendo las tonalidades más adecuadas que hacen que la imagen original con la nueva paleta se vea prácticamente igual, aunque ocupando mucho menos espacio por supuesto.

En definitiva, un buen año, tanto técnica como personalmente. Hace ya un año que cambié (otra vez) de ciudad de residencia, y la verdad es que lo estoy disfrutando.

Juan Mellado, 9 Junio, 2013 - 13:23

Hoy he liberado los fuentes de dart-neuquant, un port a Dart del clásico algoritmo Neuquant de Anthony Dekker (1994), que utiliza una red neuronal para convertir una imagen RGBA de 32 bits a otra equivalente de 8 bits. Es decir, que analiza la paleta con los distintos colores presentes en una imagen, que en el caso de 32 bits pueden ser millones, y genera una nueva paleta equivalente a la original, pero de tan sólo 256 colores.

Aunque a priori pueda parecer que el resultado no debería ser bueno, por la diferencia de colores y tonalidades que se pierden, en realidad es todo lo contrario. Por ejemplo, la imagen de la izquierda tiene 68.289 colores distintos, mientras que la de derecha sólo 256, y sin embargo ambas lucen muy similares.

dart-neuquant

Naturalmente hay que tener en cuenta que he reunido las dos imágenes en un única en formato JPG, lo que desvirtúa un tanto el resultado real. Aún así, se puede observar como algunas regiones de la imagen de la derecha presentan ciertos problemas de banding, es decir, que hay un salto brusco de colores en vez de un degradado suave. Esto se observa más en las regiones curvadas, como en algunas partes del caballo por ejemplo. La forma habitual de arreglar esto es aplicando dithering, que consiste en juntar pixeles de distintos colores para que parezca otro color, aunque el autor del algoritmo comenta que esto hace que la medida del error entre la imagen original y la generada crezca.

El algoritmo da más importancia a la componente verde (la G de RGB), ya que el ojo humano es capaz de detectar un rango más amplio de este tipo de tonalidades que del resto. Lo que no es de extrañar ya que es el color que más abunda en la naturaleza. Por lo que el resultado resulta más "agradable" en este sentido.

El proyecto ha ido bastante rápido, ya que el código C original a portar no era muy extenso. La principal dificultad ha estado en que utiliza aritmética entera, con rotaciones en vez multiplicaciones por ejemplo, por lo que he tenido que estar muy atento para que el resultado en cada paso fuera el mismo tanto en Dart como en JavaScript. En la actualidad, casi una década después de cuando se implementó el código original, creo que sería más práctico utilizar aritmética decimal, e incluso puede que más eficiente.

Lo que resulta curioso es que no tenía en mente hacer este proyecto, ha sido un poco de rebote, empecé resolviendo un error en una librería JavaScript que ni siquiera conocía, y he acabado implementando una versión en Dart.