May 30

Autocompletar en los IDE

autocompletar en javascriptPara trabajar siempre me gustan más los lenguajes estáticamente tipados que los dinámicamente tipados y entre otras ventajas, una de ellas es la de autocompletar de los IDE. Pero siempre que digo esto, alguien me comenta que si el IDE está correctamente configurado, los dinámicamente tipados también tienen autocompletar.

Bien, esto es cierto, pero sólo parcialmente. Imagina el siguiente trozo de código en un lenguaje estáticamente tipado, como java

public void metodo ( UnaClase parametro) {
   parametro.???
}

Cuando empezamos a teclear en la zona de ???, el IDE sabe que parámetro es de tipo UnaClase, porque se ve claramente, así que es perfectamente capaz de darnos los métodos y atributos públicos de parámetro para que elijamos uno.

Sin embargo, en un lenguaje dinámicamente tipado, si tenemos el código equivalente

function unaFuncion (parametro) {
   parametro.???
}

aquí el IDE no tiene ni idea de qué tipo es parámetro y de hecho, no puede saberlo, porque parámetro puede ser de cualquier tipo cuando el código se esté ejecutando, se puede llamar a unaFuncion() pasándole un entero, una cadena de texto, un objeto propio que hayamos creado o cualquier otro tipo que se nos ocurra. Así que el IDE aquí es totalmente incapaz de ofrecernos opciones, salvo que el lenguaje tenga algo común en todos sus tipos.

¿Cómo se apaña entonces para autocompletar?. Bien, un caso como el que acabamos de mostrar es imposible, pero los IDEs tienen sus trucos para ofrecernos opciones de autocompletar cuando es posible. Por ejemplo, en el caso anterior, si tenemos

function unaFuncion (parametro) {
   parametro.funcion1();
   parametro.funcion2();
   var a = parametro.atributo1;
   parametro.???
}

aquí el IDE ve qué cosas usamos de parámetro, así que cuando lleguemos a los ??? nos ofrecerá las funciones y atributos que ya hemos usado (funcion1, funcion2, atributo1), sean o no correctos y de hecho, pueden no ser correctos porque nos hemos equivocado al teclear o simplemente porque en tiempo de ejecución alguien nos pasa como parámetro algo que no tenga esas funciones ni atributos.

Otro truco usado por los IDE es el siguiente

function unaFuncion () {
   var b = new UnaClase()
   b.???
}

en este caso, se ve claramente qué contiene la variable b, aunque no tenga tipo definido, ya que estamos haciendo un new de una clase concreta y metiéndola en la variable. Si el IDE es capaz de encontrar en nuestro código la definición de UnaClase, será capaz de ofrecernos sus métodos/funciones y atributos … es justo el caso de la imagen.

Así que sí, los IDE pueden autocompletar en lenguajes dinámicamente tipados, pero con ciertas limitaciones.

May 16

ESB vs MQ vs DDS

Ando últimamente mirando herramientas estilo Enterprise Service Bus (ESB), de colas de Mensajes (MQ) y Data Distribution Systems (DDS). La primera vez que oyes hablar de ellas te preguntas ¿qué son exactamente? ¿Para que sirven?. La primera explicación que encuentras en la Web de cualquiera de ellas es la habitual : "Una herramienta maravillosa que con poco trabajo te resuelve todos tus problemas y te va a hacer el más feliz de los programadores". Si profundizas un poco más, llegas a las definiciones técnicas que nadie entiende, como "Es la implementación del estándar JSR x33, bájate y lee el estándar de dos mil páginas para saber de qué estamos hablando".

Aquí va un "pequeño" resumen de qué son y para qué sirven, según lo he entendido tras andar investigando y jugando con algunas de ellas.

¿Cual es el problema que pretenden resolver?

Todas ellas pretenden resolver más o menos el mismo problema, pero lo hacen con diferentes aproximaciones, siendo más o menos intrusivas en nuestro desarrollo.

Imagina un sistema complejo en el que varios ejecutables están corriendo en varios ordenadores. Estos ejecutables colaboran entre sí enviándose mensajes unos a otros, compartiendo datos, repartiendo tareas, etc. El esquema podría ser similar al de la siguiente figura, donde hay tres ordenadores (las cajas cuadradas), con siete ejecutables A,B,C… y las comunicaciones entre ellos

Problema que pretende resolver ESB, MQ y DDS

Cada ejecutable conoce a los demás ejecutables con los que está trabajando y establece las conexiones que necesita para colaborar con ellos. Esta aproximación tiene varios problemas:

  • Cada ejecutable debe saber las IP/hosts y puertos donde están los otros ejecutables con los que colabora
  • Los ejecutables deben ponerse de acuerdo en el formato en el que se envían los datos.
  • Si más adelante queremos ampliar o modificar el sistema añadiendo, quitando o moviendo de sitio ejecutables, tendremos que tocar todos los ejecutables afectados. Por ejemplo, imagina que añadimos un cuarto servidor con ejecutables H y J que quieren colaborar con algunos de los ya existentes, casi seguro que tendremos que tocar los ya existentes para que admitan a los nuevos.
  • ¿Y qué pasa si alguno de esos ejecutables existentes no podemos tocarlo porque es un producto comercial, nos lo hizo otra empresa o se ha ido el desarrollador que lo concoce? (triste, pero real como la vida misma, a veces se va el que lo ha hecho y nadie más se atreve a tocarlo).

Dar flexibilidad a este tipo de montajes y facilitar la conexión con nuevos ejecutables es lo que pretenden resolver todo este tipo de herramientas ESB, MQ y DDS. Empezamos a ver la solución que propone cada una de ellas, empezando de la menos intrusiva (la que nos oblgaría a hacer menos cambios en nuestros ejecutables ya existentes) a la más intrusiva (que nos obligaría prácticamente a diseñar el sistema pensando en ella).

Enterprise Service Bus (ESB)

 Hay varias herramientas gratuitas de este tipo, como Apache Service Mix, Mule ESB, JBoss Fuse, WSO2 Enterprise Service Bus.La solución que proponen estas herramientas es arrancar uno o varios ejecutables ESB de forma que todas las aplicaciones se conecten al ESB en vez de unas con otras. Es en este ESB donde configuramos las rutas de las conexiones, diciendo por ejemplo, que lo que mande el ejecutable A se debe enviar al ejecutable B. El esquema sería parecido al siguiente

Enterprise Service Bus

Las bondades de esta solución son las siguientes

  • En el ESB se establecen las rutas de qué ejecutables hablan con qué ejecutables. De esta forma, el conocimiento de qué ejecutables hay y dónde están queda centralizado en el ESB, en vez de repartido por los distintos ejecutables de nuestra aplicación.
  • Estas rutas se pueden crear, modificar y eliminar en caliente, por lo que sería posible, por ejemplo, añadir un nuevo ejecutable a nuestro sistema y establecer las rutas en caliente para que este ejecutable sea capaz de enviar/recibir de los que ya están arrancados.
  • Las rutas pueden tener "inteligencia", de forma que pueden enviar un mensaje procedente de un ejecutable a varios ejecutables a piñón fijo, o bien seguir algún tipo de criterio para decidir a cual enviarlo, filtrar para enviar unos mensajes sí y otros no, etc, etc. Por supuesto, esta "inteligencia" se puede cambiar en caliente.
  • Como parte de la "inteligencia", las rutas pueden modificar los mensajes, siendo uno de los casos más habituales el cambio de formato de mensaje. Si un ejecutable usa el protocolo FTP y el otro HTTP, la ruta podría hacer la conversión correspondiente para, por ejemplo, coger ficheros de un servidor FTP y subirlos a una web con HTTP o al revés. Si los protocolos son estándar (FTP, HTTP, SNMP, XML, …) los ESB saben tratarlos y convertir entre ellos. Si no son estándar, podemos añadir nuestro trozo de código dentro del ESB para hacer las conversiones a nuestro gusto.
  • Otra ventaja adicional es que estas herramientas permiten de alguna forma monitorizar las rutas, de forma que podemos ver qué mensajes pasan por ellas, si se utilizan o no, si hay fallos, etc.
  • Las posibilidades que implementan las rutas suelen conocerse como "Enterprise Integration Patterns" o EIP. Siguiendo el enlace puedes ver todos estos patrones que suelen implementar.

Este es el mecanismo menos intrusivo porque nuestros ejecutables siguen siendo tal cual y enviando/recibiendo los mensajes en los formatos que ya tienen. Únicamente debemos cambiar la IP/host de conexión para que sea contra ESB en vez de unos con otros y nos queda el trabajo de configurar rutas en el ESB y darles la lógica que sea necesaria (conversiones de datos, filtros y en general cualquier EIP de la lista anterior).

Colas de Mensajes MQ

 Hay varias herramientas de colas de mensajes gratuitas, siendo ActiveMQ posiblemente la más conocida. Otras son RabbitMQ o Apache Kafka. La solución planteada es similar a ESB en el sentido de que debemos arrancar uno o más ejecutables MQ y nuestras aplicaciones deben conectarse a ellos. Sin embargo, es más intrusiva que ESB en el sentido de que debemos conectarnos con el protocolo que establece MQ, no podemos seguir conectándonos usando nuestros propios protocolos.

A MQ le enviamos mensajes en el formato que admite y cualquier otro ejecutable que tenga interés puede recibirlos. El esquema de trabajo sería como el siguiente

 Message Queue

Dentro de MQ se definen "topic" y "queue" con nombres, tantos como queramos. Los ejecutables envían mensajes a estos topic o queue. Otros ejecutables se suscriben a estos topic y queue de forma que recibirán los mensajes. La diferencia entre un topic y un queue es que un topic entregará sus mensajes a todos los ejecutables que se hayan suscrito, mientras que un queue sólo lo entregará a uno de los suscriptores. Un queue se utiliza más como un reparto de tareas.

Esta aproximación me parece más sencilla y elegante que la de los ESB, pero tiene el inconveniente de que nuestros ejecutables deben estar pensados para enviar y recibir mensajes a MQ, por lo que puede ser un trabajo modificar un ejecutable existente para adaptarse a MQ.

O quizás no. Los ESB suelen entender los mensajes de los MQ, de hecho, Apache Service Mix (un ESB) lleva integrado ActiveMQ (un MQ) Nuestra aplicación puede conectarse con su protocolo normal contra ESB y en ESB podemos establecer una ruta para convertir los mensajes en el formato de la aplicación a mensajes en el formato de MQ y enviarlos a MQ. Por otro lado, en otro sitio, haremos una ruta que recoja estos mensajes MQ, los convierta al protocolo que necesite la aplicación receptora y se los despache en el formato que ella entienda.

 Data Distribution Service DDS

De este tipo de aplicaciones hay menos gratuitas, pero tenemos por ejemplo OpenDDS y OpenSplice DDS. El concepto aquí es similar a las MQ, pero va más allá. Debemos arrancar uno o más ejecutables DDS y nuestras aplicaciones deben conectarse a ellos. La diferencia con MQ es que en DDS debemos definir todos nuestros tipos de datos y nuestros datos. Por ejemplo, si nuestra aplicación controla una flota de camiones, debemos indicar a DDS que tenemos un tipo camión con los campos matrícula, carga máxima, año de fabricación, modelo, marca, etc. y debemos indicar a DDS que vamos a tener una lista de camiones en revisión, una lista de camiones en recorrido, etc, etc.

A partir de aquí, nuestros ejecutables se conectan a DDS y en formato DDS van alimentando estos datos. Cualquier ejecutable puede a su vez suscribirse a los datos para enterarse de cambios en ellos. El esquema sería el siguiente

Data Distribution Service DDS

Esta solución como se puede intuir es la más intrusiva de todas, ya que no solo nos obliga a adaptarnos al protocolo de DDS, sino que de alguna forma dejamos en DDS la responsabilidad de mantener nuestros datos. Hasta cierto punto, DDS hace las veces de una base de datos (de hecho, suele tener una base de datos detrás que respalda nuestros datos), pero con la posibilidad de suscribirse a cambios. DDS suele además poder trabajar "distribuido". Varios ejecutables DDS interconectados entre sí, de forma que si metemos datos por uno de ellos, podemos retirarlo en cualquiera de los otros.

La principal ventaja de DDS es que está pensado para ser muy eficiente, por lo que no es raro encontrarlo en sistemas de tiempo real, defensa , espacio, transporte.

May 09

He leído “ActiveMQ in Action”

ActiveMQ in actionHe leído ActiveMQ in Action, una forma de enterarse de qué va ActiveMQ. El libro en sí no me ha gustado demasiado, se hace pesado de leer. Explica un concepto (eso sí es útil), te dice que el ejemplo de código de ese concepto está en tal sitio web, que para ejecutarlo uses tal comando y luego te planta dos páginas de libro viendo el log de salida del programa. Así una y otra vez.

Sin embargo, como yo soy más de enterarme bien de los conceptos que de andar mirando el detalle del código, el libro me ha servido para saber de qué va ActiveMQ y sus posibilidades.

ActiveMQ ofrece un servicio de mensajería entre distintas aplicaciones, o incluso para distintas partes dentro de una misma aplicación. Una aplicación o una parte de ella puede enviar mensajes a ActiveMQ y otra aplicación u otra parte de la misma pueden recoger esos mensajes. Aparte de esto, las características que mas me han llamado la atención de ActiveMQ son las siguientes:

Los mensajes pueden ser persistentes, es decir, se guardan automáticamente en ficheros o base de datos, según configuremos, de forma que si paramos la aplicación ActiveMQ y la volvemos a arrancar más adelante, los mensajes no entregados cuando paramos la aplicación, se recuperan y se pueden entregar en cuanto alguien los recoja.

Tiene posibilidad de arrancar varios ActiveMQ para trabajar colaborando, bien en forma de cluster, bien en configuración maestro-esclavos. En la configuración de cluster, los ActiveMQ se interconectan entre sí, de forma que si entregamos un mensaje en uno de ellos, se puede recoger en cualquiera de los otros. La configuración de cluster es muy sencilla, tiene posibilidad de "autodescubrimiento" de forma que según se vayan arrancando aplicaciones ActiveMQ en la red local se incorporan automáticamente al clustter, o bien podemos indicar las IPs concretas donde está cada ActiveMQ, para formar un cluster fijo. En cuanto a la configuración maestro-esclavo, es también sencilla. Un ActiveMQ es el que hace de maestro y es al que se conectan las aplicaciones. Los esclavos únicamente van guardando réplicas de los mensajes. Si el maestro se cae, uno de los esclavos entra en funcionamiento y las aplicaciones deben re-conectarse al nuevo maestro. Las librerías para clientes de ActiveMQ se pueden configurar de forma que hagan esta reconexión automáticamente.

Y lo que más me ha gustado, embeber un ActiveMQ dentro de nuestra propia aplicación es casi inmediato. Si ponemos la dependencia del jar adecuado (activemq-broker y activemq-client), basta con que nuestra aplicación establezca una conexión contra ActiveMQ usando el protocolo "vm://un-nombre" y automáticamente se creará una instancia de ActiveMQ con nombre "un-nombre" dentro de nuestra aplicación, disponible para cualquier parte de ella. Si además, a esa instancia le creamos una conexión adicional  "tcp:….", otros programas externos podrán conectarse a nosotros para recibir nuestros mensajes o enviarnos los suyos propios. También podemos crearle conexiones de red adicionales, de forma que nuestra instancia embebida de ActiveMQ forme parte de un cluster externo de ActiveMQ.

En resumen, me ha gustado la herramienta, es bastante simple de poner en marcha, de montar clusters e incluso de embeberla en nuestras aplicaciones. No me ha gustado que el envío de mensajes es relativamente tedioso: hay que crear la conexión, de la conexión una sesión, de la sesión un destino que no es más que un nombre, del destino crear una cola o un topic (son dos posibles formas de distribución del mensaje), un producer (el que envía el mensaje), construir el mensaje y enviarlo. Muchos de estos pasos se pueden dejar preparados para no repetirlos muchas veces, pero no deja de ser "un pelín" engorroso. Con la recepción algo similar.

De todo esto han salido algunos tutoriales de ActiveMQ en la Chuwiki.

Nov 30

Sobre angularjs

Porque me ha tocado en el curro, me he leído AngularJS by Brad Green and Shyam Seshadri y he empezado a trabajar con AngularJS. Aprovecho aquí para comentar el libro y los conceptos básicos de angularJS.

El libro

El libro no me ha hecho demasiada gracia. Los dos primeros capítulos sí me gustaron, muy sencillos y explican lo más básico de angularJS. Sin embargo, a partir del tercer capítulo, la cosa se complica y no me parece que hayan conseguido explicarla bien. Empiezan a meter mucho código con muchas de las cosas propias de angular sin dar una explicación detallada de ellas, por lo que aunque intuyes de que va el tema o cómo funciona, los detalles no te quedan claros. Imagino que con la práctica me acabe enterando.

Los conceptos

angularJS es un framework MVC javascript mantenido por google. Ya estamos con los "palabros", vamos a intentar explicarlo.

En angularJS el modelo no es más que una variable javascript llamada $scope en la que se añaden de la forma normal en javascript todos los datos (modelo) que queramos.

La vista es un HTML en el que podemos poner algunas cosas específicas de angularJS. Por ejemplo, un párrafo podría ser <p>{{unaVariable}}</p> done unaVariable es un atributo de $scope, es decir, $scope.unaVariable existe y es lo que se pondrá dentro de los tags <p> y </p>. Una característica interesante de angularJS es que esta relación es bidireccional y automática, de forma que si nuestro código javascript modifica el valor de la variable, automáticamente se refleja en la vista HTML, y si ese {{unaVariable}} lo pusieramos en un input text así <input type="text" ng-model="unaVariable">, en cuanto el usuario teclea se actualiza la variable.

El controlador es una clase javascript en cuyo constructor recibe el $scope (y otras cosas) y se encarga de rellenarlo con los datos que necesitemos. También a esa clase le ponemos todas las funciones javascript que necesitemos y a las que se podrán llamar desde los distintos eventos de HTML (onclick, submit, etc).

Por supuesto, podemos hacer un HTML principal (index.html o similar) que dentro llevará varias vistas, cada una con su propio modelo y controlador. La idea es hacer una aplicación de simple página e ir reemplazando dentro de ella los distintos trozos HTML según el usuario vaya pulsando botones y menús.

Aparte de este concepto MVC, angularJS tiene una serie de utilidades que resuelven los problemas típicos en cualquier aplicación web. Veamos los más importantes

Directivas : En angularJS podemos definir nuestras propias directivas, aparte de las que angularJS ya nos proporciona. Una directiva es una forma de reemplazar un tag a atributo de un tag html por lo que  nosotros queramos. Un ejemplo tonto sería hacer una directiva "horaActual", de forma que si en nuestro HTML ponemos <horaActual></horaActual> se reemplazará por la fecha/hora actual (porque así lo hemos codificado en la directiva). Por supuesto, el código que hay que hacer es más sencillo que andar buscando los tags HTML y reemplazándolos a pelo.

Servicios : En angularJS podemos definir servicios, que simplemente son código javascript realizado por nosotros con determinadas funciones que queremos poder aprovechar en varios sitios. Si creamos un servicio con una serie de funciones javascript, angularJS podrá pasarlo como parámetro en el constructor de los controladores, de forma que estos tendrán disponible y podrán usar las funciones javascript de nuestro servicio. Es bastante habitual hacer que los servicios sean los que hablen con el servidor, para pedirle información que debe presentarse al usuario, o enviarle las operaciones que ha realizado el usuario.

Promises : Relacionado con los Servicios cuando estos hacen llamadas al servidor, tenemos las Promises. Si el usuario hace una operación que necesita enviar y esperar respuesta del servidor, normalmente llamará a una función javascript de uno de nuestros servicios. Este función hará la llamada al servidor (con AJAX por ejemplo) y recibirá de forma asíncrona el resultado. Pues bien, nuestra función javascript del servicio puede devolver inmediatamente, sin esperar el resultado, una de estas Promises, que no es más que una instancia de una clase javascript de angularJS, y cuando tenga el resultado llamar al método resolve() de la Promise. angularJS se enterará y actualizará el modelo cuando el resultado esté disponible (hayamos llamado a resolve). Un pequeño ejemplo lo dejará más claro

function pideDatosAlServidor (…, $q) {     // $q es un objeto específico que nos pasará angularJS para trabajar con Promises
   var defer = $q.defer();            // Obtenemos un objeto deferred para manejar nuestra Promise
   $.get ("url", function (data) {          // Nuestra llamada a ajax. AngularJS tiene parte de jQuery embebido.
       // hacemos algo con los datos recibidos
      defer.resolve();                      // Indicamos que ya se dispone de los resultados.
   }
   return defer.promise;             // Devolvemos la Promise
}

Fíjate que la llamada a $.get() es una llamada AJAX que llamará a function(data) cuando se tengan los resultados. El código pideDatos() hace esta llamada y directamente, sin esperar el resultado, devuelve el defer.promise. Esto le bastará a angularJS para saber que tiene que esperar por los datos antes de refrescar la página.

Test : AngularJS está pensado para que se puedan hacer test unitarios y de integración, por lo que viene con herramientas como e2e (end to end), facilitando, con herramientas adicionales, incluso cosas como levantar un servidor para los test y ejecutarlos.

Por supuesto, angularJS tiene otro montón de cosillas típicas para ayudarnos en nuestro desarrollo, como facilidades para la internacionalización, validación de formularios, bucles en las plantillas HTML, filtros, etc, etc.

Bueno, me he quejado de que el libro no explica bien, y escribiendo esto veo que es difícil explicarlo bien, pero al menos no  he necesitado 175 páginas.

Nov 23

Herramientas frikis vs amigables

friki sheldom big bang theoryCuando busco herramientas para trabajar o aplicaciones para instalar, gratuitas, me he encontrado con frecuencia que hay dos herramientas con éxito, pero que difieren entre sí en un detalle, su facilidad de instalación/administración y sus posibilidades de extensión. Una de las herramientas es lo que yo llamo "para frikis", suele ser una herramienta muy potente y configurable, pero que requiere muchos conocimientos para administrarla. La otra es la herramienta "amigable", que un administrador sin profundos conocimientos informáticos puede instalar y poner en marcha sin demasiados problemas, pero que hace lo que hace y no es tan fácilmente salirse de eso. Veamos algunos ejemplos

Eclipse vs Netbeans . Ambas muy aceptadas en el mundo de desarrollo java. Eclipse es la herramienta de frikis. Puedes bajarte un eclipse "pelado" que apenas hace nada y luego liarte a instalarle plugins según el tipo de desarrollo que vayas a hacer (C++, java escritorio, java ee, plugins, etc, etc). Netbeans, por el contrario, es una herramienta más monolítica. Sí, también tiene plugins que puedes instalar/desinstalar, pero basta compara la página de descarga de eclipse y la de netbeans, para ver que eclipse requiere más conocimientos para saber qué quieres bajar. De hecho, hay más entornos de programación basados en eclipse, como el de Android o el de Spring, o el Aptana, que sobre netbeans. Suele ser normal también encontrarse que se usa eclipse en los entornos de desarrolladores profesionales, mientras que usan más netbeans los programadores que están empezando.

drupal vs joomla . Ambos para la construcción de sitios web. Drupal es la herramienta de frikis, aunque tiene una administración bastante intuitiva, es más espartana, muchos plugins desarrollados y posibilidades realmenten sorprendentes. Joomla, sin embargo, tiene una administración más vistosa (aunque a mi me resulta menos intuitiva) y tiene bastantes y más vistosos temas que drupal. De alguna forma, drupal es adecuada para administradores con conocimientos que en un momento dado requiran instalar o desarrollar plugins que hagan cosas que se salgan de lo normal en un sitio web, mientras que joomla es adecuado para obtener rápidamente un sitio web vistoso. Basta mirar el número de plugins de drupal (más de 14000) y el de joomla (más de 7000).

Geoserver vs mapserver Ambos servidores web de mapas. Mapserver es el de frikis, ejecutable nativo, mucho más eficiente sirviendo mapas, pero sin una interfaz web de administración (salvo instalando plugins) y un horror para configurar los mapas, a base de editar ficheros con sintaxis específicas. Geoserver, sin embargo, hecho en java, algo más lento sirviendo mapas, tiene una interfaz web de administración muy intuitiva y sin muchos conocimientos de geoserver, en pocos minutos se puede tener funcionando y sirviendo mapas. Mapserver es adecuado para un servidor de mapas que no vaya a tocarse mucho y que se requiera que sea eficiente, se configura una vez y listo. Geoserver más adecuado si se va a andar cambiando con frecuencia los mapas servidos o va a tener que administrarlo alguien sin muchos conocimientos.

redmine vs trac. Ambos gestores de tareas/incidencias. Redmine es el amigable, con una interfaz web de administración muy intuitiva, mientras que trac venía sin interfaz web de administración cuando lo estuve mirando, aunque ahora ya la lleva. La administración se hace por línea de comandos con un comando "trac-admin". Eso sí, al menos cuando los instalé, ninguno de los dos es fácil de instalar, aunque redmine me dio bastante menos guerra.

Git vs Mercurial. Ambos sistemas de control de versiones distribuidos. Git, diseñado por linus torvalds, cuenta aparentemente con más comandos avanzados y de bajo nivel, dándonos más posibilidades de hacer más cosas. Mercurial, sin embargo, tiene los comandos necesarios para hacer lo que se necesita en este tipo de herramientas. Sus características avanzadas están deshabilitadas por defecto. Git gusta a los frikis, Mercurial tiende a ser más la herramienta de los que necesitan un control de versiones distribuidos y no quieren pelearse con ella, sino dedicarse a desarrollar su propio proyecto. Es curiosa la comparativa en que se dice que Git es como Wesley Snipes y Mercurial como Denzel Washington. Denzel Washington es todo un actor, pero tiene una vida real normal, nada interesante. Mientras que Wesley Snipes, quizás no siendo tan buen actor, es mucho más divertido por tener una vida real más agitada. Por cierto, en el artículo dicen que Subversion sería Morgan Freeman.

Aunque una de ellas no es gratuita, por supuesto, Windows vs Linux. No hay mucho que comentar, creo que todos conocemos las virtudes y defectos de ambos sistemas operativos. Todos sabemos cual es el amigable y cual el de frikis. Y de la misma forma, Android vs iOS, que creo que tampoco es necesario comentar

Y seguramente hay más, aunque en este momento, con mi mujer al lado dándole a la ruidosa aspiradora, no se me ocurren más.

Jan 28

El vi, esa gran maravilla

Ando liado con menús y chorradas varias en el proyecto. El "rollo" es que a veces los menús son muy largo (fíjate en esta tabla de códigos ISO de paises). En base de datos va el código numérico o el de dos/tres letras, mientras que al usuario se le deben presntar los textos legibles con el nombre completo del país. A veces es símplemente mostrar un país resultado de una consulta, otras veces es mostrar un menú (unos select/option de HTML).

Pues bien, a partir de una de esas tablas hay que conseguir bien una tabla en base de datos con dos columnas: código – texto legible, bien el menú select/option de HTML, bien un fichero properties de java con muchas líneas codigo=país, etc. Y muchas veces la única entrada que tenemos es copiar de una página web como esa.

Habitualmente, un "truco" que hago es seleccionar con el ratón la tabla de la página web en cuestión, esto me copia en el portapapeles el código de la tabla HTML y afortunadamente, si se pega eso en un Excel lo hace de forma correcta (fíjate en la imagen)

excel importando paises

Ahora el proceso es más fácil, se puede exportar esto a un CSV, que no es más que un fichero de texto en el que cada fila corresponde a una línea y los valores de las columnas van separados por comas, encerrados en comillas o como queramos. Eliminamos antes las columnas que no nos interesen y obtenemos un fichero de texto como este (abierto ya con el editor vi)

CSV en el vi

 

Bien, pues con un fichero como este, lo habitual sería cogerle algún lenguaje de script, como phyton, perl, awk o cualquiera de nuestro gusto y hacer un pequeño programita que lea eso línea a línea y genere lo que  nosotros queramos, estilo

<option value="AF">Afganistán</option>

si queremos, por ejemplo, un select/option de HTML. Pero no es necesario uno de estos lenguajes, el mismo editor vi (gvim en mi caso) tiene un potente buscar y reemplazar con expresiones regulares similares a las de cualquiera de esos lenguajes. Si en el editor anterior ejecutamos el comando (lo explicamos al final)

:%s/^\(\S\+\); *\(.*\)$/<option value="\1">\2<\/option>/

nos da el resultado esperado

gvim modificado

El comando no es más que un comando de vi que permite sustituir unas cadenas por otras.

El : es para entrar en el modo que nos permite escribir comando de este tipo.

El %s indica la s un "sustituir" y el % que se haga en cada línea. El comando s lleva este formato s/cadena a buscar/cadena nueva/.

La cadena a buscar es una expresión regular, en la que ^ indica inicio de línea y $ fin de línea, como en cualquier lenguaje.

\S+ indica caracteres no espacios una o más veces, como en las expresiones regulares de cualquier otro lenguaje. La diferencia aquí es que el + hay que escaparlo, por eso \S\+. Esto ira casando con los códigos de dos letras. El .* indica cualquier cadena de caracteres, que iran casando con las descripciones de los paises.

Como nos interesa guardarnos ambas cosas (el código y la descripción), las encerramos entre paréntesis, pero a diferencia de otros lenguajes, aquí también hay que escaparlos, así que quedan cosas tan feas como \(\S\+\) y \(.*\). Entre ambas está el ; y el espacio que por lo que vemos es opcional, es decir <espacio>*

En la parte de la nueva cadena, tenemos disponibles en \1 y \2 lo que habíamos colocado entre paréntesis, es decir código de país y descripción. Así que la cadena nueva no es más que el <option> completo, poniendo \1 donde va el código de país y \2 donde va la descripción.

Nada que no se pueda hacer desde un script en otro lenguaje, como hemos dicho, pero .. ¿qué pasa en mi caso que posiblemente hiciera el script usando el vi? ¿para qué hacer el script, salvo que piense reutilizarlo más veces?

Oct 25

He leído “OpenLayers 2.10 Beginner’s Guide”

http://blog.sonxurxo.com/wp-content/uploads/2011/03/openlayers-beginners-guide.pngAcabo de leer OpenLayers 2.10 Beginner’s Guide 

OpenLayers es una librería javascript que nos permite hacer aplicaciones con mapas en nuestra página web. Los mapas pueden ser los de Google Maps, Bing, OpenStreetMap o servidor por cualquier servidor que cumpla los estándares OGC, como Geoserver. OpenLayers "traga" además otro montón de formatos para dibujar mapas directamente de ficheros.

El libro es muy básico, empieza desde el principio, tan desde el principio que incluso nos explica lo básico de javascript y qué son las clases, la herencia, los métodos y atributos. Por supuesto, no se entretiene demasiado en ello, una simple explicación para no pillarse los dedos según va avanzando en OpenLayers.

Si, como yo, has empezado con OpenLayers a base de ensayo y error, copy-paste de código en google y ya tienes algo de experiencia, este libro es muy básico, pero siempre acalara algún concepto que puedes no haber "pillado" en tus pruebas, ensayos, errores, copies y pastes.

Es ideal sin embargo para leer antes de empezar con OpenLayers, el libro va despacio, no es muy complejo lo que explica y va asentando bases antes de seguir. Cada apartado resulta un poco repetitivo porque primero te explica cómo funciona, luego te lo vuelve a explicar mientras te dice cómo codificarlo y finalmente te lo vuelve a explicar añadiendo un título "¿Qué acaba de pasar?" después de que hayas ejecutado el ejemplo que acabas de codificar. Lo dicho, ideal para quien no tiene idea del tema y le gusta asentar bien las cosas.

 

Sep 20

He leído “Test Driven: TDD and Acceptance TDD for Java Developers”

tdd acceptance testBueno, realmente exagero un poco cuando digo "he leído…", me he dejado sin leer los últimos capítulos.

La parte central del libro me ha encantado, pero la primera parte y la última me han resultado muy pesadas e inútiles, hasta el punto de dejar de leerlo en esa última parte.

Los primeros capítulos nos cuenta principalmente las ventajas de TDD, no se extiende mucho en qué es o cómo se hace TDD, sino que se extiende mucho (muchísimos) en sus ventajas. Estas ventajas son más o menos conocidas por todos (código con menos fallos, confianza en que no estropeamos nada a la hora de hacer refactoring por lo que nos cuesta menos hacerlo, etc, etc). Por ello, varios capítulos dedicados a las ventajas me parece excesivo e incluso repetitivo, ya que una y otra vez comenta las mismas ventajas.

Afortunadamente el grueso de capítulos centrales me ha parecido una maravilla. No por TDD en sí mismo, sino porque se dedica para cada tipo de proyecto diffícilmente testeable (base de datos, jsp, swing, etc) a mostrarnos los distintos frameworks con los que podemos trabajar (jdbc, hibernate, spring, jsf, tapestry, wicket, …) como las librerías útiles para hacer test automáticos en esos frameworks (mockito, clases de spring que son mock objects de interfaces java complejas, jspunit, fit, etc, etc). Lo mejor de todo esto es que no da por supuesto que conocemos cada framework o librería, sino que nos da un resumen de cada uno de ellos, qué es, para qué sirve y cómo se usa. Así que esta parte, más que para hacer test automáticos, sirve realmente para conocer de qué van todas esas siglas que oímos de continuo y a veces no sabemos qué son (jsf, spring mvc, tapestry, jsf, wicket …) y es una primera guía para saber por dónde empezar a usarlas.

Dentro de este grupo de capítulos nos habla de los test de aceptación, que son test automáticos de más alto nivel donde idealmente se considera el sistema como caja negra y se testea desde fuera automáticamente. Idealmente estos test deben estar escritos por el cliente más que por los desarrolladores, puesto que el cliente es el que sabe lo que quiere y si el test es o no suficiente. Así que, aparte de discutir en qué casos se puede/debe testear desde fuera el sistema como caja negra, o cuando se puede/debe testear justo por debajo de la interfaz de usuario, nos introduce en herramientas como fit o fitnesse.

En la última parte, la que he dejado de leer, nos muestra los problemas que podemos tener con nuestros compañeros de trabajo si intentamos convencerlos de que usen TDD, y cómo identificar esos problemas y cómo abordarlos. Pero para mí, programador principalmente, lo de las relaciones humanas no es un libro que me entretenga. Y para mí, cabeza cuadriculada, semejante texto me parece demasiado "etéreo" y evidente. Oír por enésima vez las ya consabidas frases estilo "para que tus compañeros hagan TDD, dales ejemplo haciéndolo tú" o "si te dicen que sí sin entusiasmo igual te están diciendo que no", no me parece que ayuden demasiado a pelearte con los problemas día a día. Este tipo de problemas son problemas que puedes resolver si tu forma de ser es la adecuada para ello, y los resolverás o no independientemente de que hayas leído este libro. Hay quien de forma innata es un lider y que yo sepa, no existe quien de forma innata es un anti-lider y se convierte en lider con un cursillo.

Hablando de cursillos, me ha llamado la atención (creo que tiene toda la razón), este post sobre el peligro de las certificaciones, tan de moda hoy en día http://www.javiergarzas.com/2012/09/problemas-testing.html

Y volviendo al libro otra vez, una frase traducida más o menos libremente que me ha llamado la atención "Los buenos programadores sufren un tipo especial del síndrome de déficit de atención, consistente en poner todo su empeño en usar una herramienta nueva, para abandonarla pocos meses después  y poner nuevamente todo su empeño en otra herramienta más nueva". Real como la vida misma.

Aug 13

Configurando Hibernate para test unitarios.

Cuando hacemos test de JUnit o la herramienta que sea, una de las cosas difíciles de probar son las transacciones con base de datos. En nuestro entorno de desarrollo necesitaríamos una base de datos igual que la de producción y deberíamos borrar todos los datos, meter los datos previos al test para tener la base de datos en un estado conocido, hacer el test y luego revisar el contenido de la base de datos. Esto, aparte de complejo, puede ser muy lento con una conexión a una base de datos real.

Una de las soluciones es utilizar una base de datos en memoria (como HSQLDB, H2, etc). Estas bases de datos suelen ser un jar que no necesita instalación, así que basta con añadirlo a nuestro classpath en los test. Al ser en memoria, los test serán también muy rápidos. Sin embargo, sigue habiendo dos problemas:

  • En cada test habría que crear todas las tablas desde cero.
  • Las SQL de estas bases de datos pueden no ser las mismas que la de nuestra base de datos de producción (MySQL, Oracle, etc).

Para ayudarnos a solucionar estos problemas podemos usar Hibernate (u otra herramienta similar). Si en el fichero de configuración de Hibernate, los de mapeo de clases (o anotaciones) y nuestro código no usamos nada específico de una base de datos (debería ser lo normal salvo casos excepcionales), Hibernate nos hará independientes de la base de datos que usemos (de hecho, ese es uno de sus objetivos). Por otro lado, hibernate tiene un parámetro de configuración hibernate.hbm2ddl.auto en el que le podemos indicar que cree desde cero todas las tablas de la base de datos. Así que Hibernate nos resuelve, en principio, los dos problemas mencionados.

La primera idea que se nos ocurre es tener dos ficheros de configuración de Hibernate (hibernate.cfg.xml), uno para producción con la base de datos real y otro para test. Pero somos buenos programadores y no nos gusta tener cosas repetidas (principio DRY), posiblemente esos ficheros sean prácticamente iguales salvo los parámetros de conexión a la base de datos y el mencionado parámetro hibernate.hbm2ddl.auto, que en nuestro base de datos de test valdrá "create" y en la de producción puede valer algo como "verify".

La solución es simple, basta tener un único fichero de configuración para la base de datos de producción, con toda la parámetrica real. Para los test cargamos ese fichero … y modificamos en código sólo lo que nos interese. Se puede hacer de esta forma

Configuration configuration = new Configuration().configure();
configuration.setProperty("hibernate.connection.url", "jdbc:h2:mem:databaseName");

configuration.setProperty("hibernate.hbm2ddl.auto","create");
SessionFactory sessionFactory = configuration.buildSessionFactory();
 

El método configure() de Configuration leerá el fichero por defecto de configuración (suponemos que es el de producción) y luego, con el método setProperty() podemos "machacar" todas las propiedades que queramos de ese fichero. En el ejemplo sólo hemos cambiado la url de la base de datos y hibernate.hbm2dll.auto, aunque posiblemente deberíamos cambiar también el nombre de la clase del Driver de base de datos, usuario, password, etc.

Ahora sólo nos quedaría poner este código en algún sitio al que nuestras clases de test puedan acceder. Nuestras clases de test obtendrían el sessionFactory usando este código, mientras que el código de producción lo obtendría de la forma habitual, posiblemente a través de un UtilHibernate.java.

Por supuesto, no nos libra nadie de llenar la base de datos en cada test con unos datos conocidos y analizar luego los resultados.

Nos queda un detalle, que es borrar los datos después de cada test. Utilizando la base de datos en memoria como hemos hecho en el código anterior, quedará "viva" y con datos mientras esté arrancada la máquina virtual java. Al ejecutar una batería de test (con mvn test, por ejemplo), la máquina virtual no muere hasta que acaban todos los test, por lo que los datos que unos test van dejando en base de datos quedan para los siguientes test, aunque estén en memoria. Debemos vaciar esos datos después de cada test.

Una opción "pesada" es ir borrando los datos o hacer un "drop" de las tablas, en el orden adecuado para evitar problemas de "contraints". Pero otro método rápido y sencillo consiste en simplemente cerrar el SessionFactory. El siguiente test tendrá que crear un SessionFactory nuevo (con el código de arriba) y así se volverán a crear todas las tablas desde cero. Es decir, nuestras clases de test tendrán los métodos setUp() y tearDown() (o @Before y @After en JUnit 4) de la siguiente forma

public class TestUno extends TestCase {
   private SessionFactory = sessionFactory;

   @Override
   public void setUp() {
      sessionFactory = // Obtener session factory con el codigo anterior
   }

   @Override
   public void tearDown() {
      sessionFactory.close();
   }
   …
}

 

Simplemente un detalle. De esta manera realmente no se borran los datos al terminar en test. En realidad se borran al empezar el siguiente test, ya que el "create" de hibernate.hbm2dll.auto hace exactamente eso, borrar para crear desde cero.

 

Aug 09

Se me han pasado las ganas de jugar con Git submodules

Sigo jugando con Git y lo siguiente que me apetecía probar era el tema de git submodule. Con ellos puedes construir un proyecto/repositorio de Git en el que algunos de los directorios son otros proyectos/repositorios de git. De esta forma tienes un "super repositorio" compuesto de varios pequeños repositorios (aparte de tener su propio código).

Me pongo a ello, a mirar en google cómo se hace y veo que es un poco liado. Finalmente este tutorial me quita las ganas de probarlo. Git tiene unas pequeñas restricciones que hace que la creación de módulos sea un poco laboriosa y "pesadita"

  • En un repositorio bare no se pueden hacer commits.
  • No se puede clonar como submodulo un repositorio vacío.
  • No se puede añadir un submodulo en un repositorio bare.
  • No se puede hacer push si el origin es un repositorio no bare

Con todo esto el proceso de creación es tan complicado como lo siguiente (puedo estar equivocado en algún detalle, sólo lo he leído, intentado probarlo rápidamente y desistido por ser algo pesado)

  • Creas los repositorios que harán de submodulos como repositorios normales (no bare) y haces algún commit en ellos (si es bare no puedes  hacer el commit)
  • Los clonas para convertirlos en bares, pero con git config tienes que tocar manualmente las referencias en la copia, para que el bare no tenga como origen el repositorio normal.
  • Creas el super repositorio como repositorio normal y haces algún commit en él.
  • Convertimos el super repositorio en bare haciendo otro clone y tocando nuevamente las referencias a mano con git config.
  • Hacemos otro clone más del super repositorio bare y entonces añadimos los submodulos en la copia. Hacemos commit y push al repositorio central.

y tras este "simple" proceso está más o menos listo, salvo el detalle de que si un segundo desarrollador clona el super repositorio, tiene que acordarse de ejecutar git submodule init y git submodule update para que los submodulos realmente se clonen … ¿cómo hacemos estos comandos en un hudson por ejemplo? ¿O hudson lo tiene controlado?

Y bueno, si sólo fuera el proceso de crearlos, aun se podía plantear hacerlo (eso se hace sólo una vez en la vida de cada proyecto y lo hace el que crea el repositorio, supuestamente una persona avezada en git). El problema son los "gotchas" que vienen en el tutorial anterior. Indica que siempre hay que acordarse de publicar los cambios en los submodulos ANTES que los cambios en el superproyecto. Me hace a mí que en un grupo relativamente grande de desarrolladores, alguno se va a equivocar con bastante frecuencia. Aunque todo es cuestión de aprender el truco y convertirlo en hábito : "siempre commit y push de los submódulos primero".

Está bien saber que existen los submodulos de git por si algún día hacen falta. De hecho, trabajando en java es algo que echo de menos cuando tenemos muchos proyectos independientes pero que comparten juegos de ficheros no java comunes. Por ejemplo, juegos de iconos, dlls de windows, ficheros de script o ficheros de configuración (xml, properties, etc). La solución de "copiar" todo ese juego de ficheros en cada proyecto es un poco pesada, pero si no se copia es dificil hacer automáticamente un zip de instalación que tenga todos esos ficheros. La solución que se me ocurre es hacer un repositorio git con todo ese juego de ficheros y añadirlo como submodulo en los proyectos que lo necesiten.

En cualquier caso, queda pendiente para más adelante. Ahora me he puesto a jugar con Spring Framework WEB/MVC 😉