Mar 29

No me gusta Grails

Llevo ya dos o tres semanas jugando con Grails. La parte de hacer código estupenda, se hace mucho con muy poco, la parte de vistas y controladores bien, la de modelo y base de datos me ha dado algún problemilla, pero supongo que lo habitual si te metes con cosas que hay por debajo, como Hibernate y encima no lo controlas.

Sin embargo, me ha dado por configurar el DataSource para la base de datos. Por defecto, Grails pone una base de datos HSQLDB. Si en el fichero DataSource.groovy cambias los parámetros de conexión y pones otra base de datos, también funciona bien todo. Puse una base de datos MySQL, puse en el directorio lib el jar con el conector de MySQL, cambié los parámetros de conexión y todo correcto.

Pero claro, a mi me gustaría hacer un war de mi aplicación y ponerlo en algún sitio descargable para que la gente se lo descargue, lo ponga en su servidor, configure la base de datos a su gusto y le funcione en su entorno. Y ahí es donde me he encontrado con problemas y cosas que no me han parecido muy lógicas.

DataSource.groovy es un fuente groovy, por lo que una vez compilado, metido en un war y desplegado, no se puede cambiar fácilmente. Tampoco parece muy amigable poner en las instrucciones de instalación que se toquen los fuentes groovy y se compilen, obligando a descargar el entorno grails al que sólo quiera instalar y utilizar la aplicación.

Pero no hay problema, se mira en la documentación de grails y se acaba encontrando que se puede poner un fichero de propiedades normalito, de los de toda la vida, con la configuración de la base de datos. Estas propiedades sobreescriben a las de DataSource.groovy. Unicamente hay que hacer dicho fichero de properties y en el fichero Config.groovy poner esto al principio

grails.config.locations = ["file:path/fichero.properties"]

Podemos poner file:, como en el ejemplo, o classpath:, para cogerlo del classpath.

Lo del classpath funciona correctamente, basta meter el fichero de propiedades en el el directorio WEB-INF/classes y todo bien. Pero claro, yo soy un poco "tikis-mikis" y no me gusta meter un fichero de configuración en el directorio de classes. No creo que sea un lugar intuitivo donde alguien busque un fichero de configuración. Quizás un directorio conf o algo así….

Así que me decanto por la opción file. Pero se me presenta otro problema. Cuando despliego mi war en un Tomcat, el directorio actual de ejecución resulta ser el directorio en el que está el script de arranque del Tomcat (el catalina.bat o catalina.sh). Desde ahí no se puede poner un path relativo hacia el fichero de configuración. Bueno, sí se puede, pero sería así de feo ../webapps/MiAplicacion/WEB-INF/conf/fichero.propiedades o algo así. Y si en vez de Tomcat es otro servidor, igual no existe eso de webapps (no lo sé).

Pues nada, vamos a ver si conseguimos de alguna forma el directorio raíz de la aplicación una vez desplegada, para poder poner el path relativo desde ahí. Las variables predefinidas de grails en el config.groovy no ayudan. Tenemos ${appName}, para el nombre de la aplicación y no recuerdo las otras, pero eran dos o tres nada más y hacen referencia al número de versión de la aplicación y poco más. Nada sobre ningún path donde se está ejecutando nuestra aplicación. Siento no poner el enlace donde he visto esas tres variables, pero la maravillosa documentación de grails no me permite volver a encontrarlo fácilmente.

Sí podemos poner variables de entorno, por lo que definir una variable propia, estilo MIAPLICACION_HOME o ${userHome} sí valen. Pero tampoco es una solución elegante. No podemos decir a nuestro usuario que defina una variable de entorno indicando dónde ha desplegado tomcat nuestra aplicación y rearranque el Tomcat entero, o que se vaya a su HOME y ponga un fichero, sobre todo si el Tomcat se arranca como servicio/demonio. Es más, poner el fichero de propiedades en un sitio fijo y apuntado por una variable de entorno, la que sea, no nos permitiría desplegar dos instancias de nuestra aplicación en el mismo servidor.

Sigo investigando y descubro que hay una maravillosa cosa llamada ServletContext en la que creo que puedo obtener este path que me hace falta para localizar el fichero de propiedades. Veo además en Grails que las clases groovy tienen accesible un servletContext como atributo (o parecido). Qué casualidad, justo Config.groovy y DataSource.groovy no lo tienen, así que directamente no lo tengo accesible. Bueno, no pasa nada, ServletContextHolder lo tiene guardado como atributo estático, así que ahí podemos acceder a él. Pues nuevamente vaya, resulta que durante la ejecución de Config.groovy  y DataSource.groovy, ese atributo es null.

El ServletContext se le pasa a Grails en la clase Bootstrap, método init() y cuando se llama a eso, ya se han leído todas las propiedades, cargado el dataSource y establecido la conexión a la base de datos por defecto. Ni tenemos el ServletContext disponible antes, ni podemos cambiar el DataSource después.

Así que nada, la única opción transparente para posibles usuarios es meter dicho fichero de propiedades en el classpath, en el directorio classes.

Así que mi conclusión es que grails puede estar muy bien para hacer una aplicación web que tú vas a montar y de la que tú eres responsable del servidor, quizás una aplicación web corporativa o para poner al público en un dominio concreto y ya en ejecución, Pero desde luego, no parece muy amigable si tu intención es hacer un war que luego la gente en general pueda descargarse y montar en su propio servidor. Es más, muchas aplicaciones piden al usuario a través de la misma interface web la configuración de la base de datos (url, username y password). No sé si es posible hacer esto en grails, pero si lo primero que hace grails, incluso antes de tener el servletContext disponible, es liarse a cargar ficheros de propiedades y establecer las conexiones con la bd, dudo mucho que cuando se le muestre la página de bienvenida al usuario se pueda cambiar fácilmente nada de eso.

Y encima otra cosa que me preocupa, resulta que mi aplicación son tres clases de modelo, otros tres o cuatro clases de controlador, un par de páginas gsp….. y he tenido que aumentarle la memoria al tomcat para que sea capaz de ejecutarla. El war generado ocupa 26 Megas y Tomcat empezó a dar OutOfMemory con frecuencia, por lo que tuve que subirle la memoria.

En fin, dejaré el fichero de properties en el el directorio classes (ya he perdido bastante tiempo para algo que creo no tiene solución), haré un par de cosas más que me quedan pendientes y dejaré aparcado grails una temporada. Quizás lo retome si tengo que hacer una aplicación para el departamento, pero desde luego, no lo vuelvo a escoger si mi intención es hacer una aplicación que la gente pueda instalarse en sus propios servidores.

Mar 26

Jugando con los IDEs para Grails

 Cuando me puse a jugar con Grails, cogí el IDE al que estoy acostumbrado, eclipse, y me puse con él. Enseguida empecé a echar de menos los autocompletar, la sintaxis coloreada y demás comodidades a las que nos acostumbran los IDEs, así que tocaba buscar plugins adecuados.

Los plugins que encontré para groovy y para grails me resultaban más bien escasos o incluso no se dejaban instalar. Al final conseguí una sintaxis coloreada de groovy, con el compilado automático deshabilitado y sin ningún tipo de integración con Grails. No se puede arrancar la aplicación Grails ni, por supuesto, depurarla.

Siguiendo con google, por las páginas de grails y asociadas, acabas llegando a que hay un IDE basado en eclipse y con muy buena integración con groovy/grails. Este IDE es STS (SpringSource Tool Suite). Pero yendo a la página correspondiente, resulta que para bajarlo me piden el nombre, el apellido, el teléfono, la empresa, mi puesto en la empresa, el sueldo, el tercer apellido de mis abuelos (de todos) y la partida de nacimiento, así que pasé totalmente de bajarlo.

También vi por internet que Netbeans soporta bien groovy y grails sin necesidad de plugins, viene ya integrado. Me lo bajé y lo probé. Mi primera impresión fue muy buena. Hace años, cuando usaba/probé netbeans, recuerdo que tenía un arranque muy lento y pesado. La nueva versión parece que arranca en un tiempo prudente. La integración con grails bien, se pueden arrancar las aplicaciones grails (no he probado a depurar, pero supongo que sí). Me bastó con abrir el proyecto grails ya creado con grails create-app para ponerme en marcha. Sin embargo, sigo acostumbrado a eclipse y hay cosas de netbeans que no me gustan, más por gusto personal que por defectos del IDE.

Así que me armé de valor, fuí a la página de STS, puse el nombre de mi compañero de mesa en el curro, su dirección, su teléfono, su tarjeta de crédito, le engañé para que me pasara su certificado de penales que también piden y me bajé el STS. Luego, Aitortxu en twitter me comenta de una página en la que se puede uno bajar STS sin descubrirle a nadie sus intimidades.

El STS una maravilla. Es un eclipse, por lo que ya estoy acostumbrado a él, y viene "tuneado" para hacer aplicaciones web, aspectj, una cosa que se llama roo (una especie de grails, pero puramente java), jpa, etc, etc. Grails y Groovy no vienen por defecto, pero hay una pestaña llamada "dashboard" en la que con un par de clicks nos baja los plugins correspondientes y funciona todo bien.

La sintaxis coloreada, ejecución, autocompletar y demás todo bien. Viene todo lo necesario para trabajar a gusto, aunque tanto plugin hacen el arranque y la instalación un poco pesados. El autocompletar como todo autocompletar en lenguajes no tipados: si sabemos de qué tipo es la variable, bien, si no lo sabemos, imposible. Así que me quedo definitivamente con STS. Aparte, me he puesto a jugar un poco con los proyectos JPA (viene con EclipseLink) y aun a pesar de no tener ni idea, lo que he intentado me ha salido a la primera o casi, lo que quiere decir que es más o menos intuitivo y robusto ante torpes como yo.

Mar 21

Sigo jugando con GfxBuilder

 Ayer pasé parte del día entretenido con GfxBuilder he intentando hacer un gráfico estadístico para el tablero Kanban en el que ando metido.

Registro las fechas en que cada pegatina sale de la primera columna (se supone que de alguna manera se empieza a trabajar en ella) y la fecha en que llega a la última (se supone que se termina el trabajo en ella), con la intención de hacer algún gráfico que nos de idea de cuánto tarda en promedio una pegatina en recorrer todas las columnas, cuantas hay a medio hacer cada día, etc.

Así que en el momento de visualizar el gráfico, recolecto toda esa información y me pongo a echar cuentas para definir los puntos a dibujar. Una vez hecho, intento dibujar una polyline de GfxBuilder…. y me da un ClassCastException. Dice que no puede hacer cast de ArrayList a Number. Bueno, me habré equivocado, seguro que dentro de donde se espera un número he metido sin querer algún tipo de lista. Miro, remiro y reviso y nada, todo aparentemente está correcto. Así que quito mi código e intento dibujar, con copy-paste, la polyline del ejemplo. Vaya, da exactamente la misma excepción y el ArrayList que no puede convertir es el de los puntos.

Me pongo con google y acabo en el repositorio de fuentes de GfxBuilder y en concreto, en la clase PolyLineNode.groovy, que es la que se supone pinta las polilíneas. Curioso, el atributo points que es donde se supone debe estar el array de puntos se declara como double. Y ello no les impide, en otros sitios del código, hacer cosas como points.size(). No creo equivocarme, pero tiene pinta clara de ser un bug/despiste.

Y esto, aunque pueda ser un despiste, es realmente un problema. He hecho una prueba mínima y groovy compila eso sin cantar error. A pesar de estar puesto el tipo de points como double, permite llamar a size(). Desde mi punto de vista, este es el motivo por el que lenguajes que no son fuertemente tipados quedan descartados para grandes desarrollos. Todos cometemos despistes en algún momento y si somos un equipo de muchos desarrolladores en un proyecto, la probabilidad de despistes es muy alta. Y en este caso, el despiste que un lenguaje fuertemente tipado detecta en tiempo de compilado (e incluso un buen IDE en el momento mismo de escribirlo), se ha colado hasta la cocina, pasando por el repositorio y al público en general. Sí, diréis que hay que ser disciplinados, pero errar es humano y sobre todo en proyectos grandes con muchos humanos codificando. Eso sí, eso no quita que la gente de GfxBuilder haya dado por bueno un código del que ni siquiera han hecho un ejemplo básico para verlo funcionando.

Y seguimos pintando gráficos. Al no poder usar polyline, me dije, voy a pintarlo a base de muchos line. Hago el código, pruebo… y el gráfico sale vacío, sin errores ninguno, pero vacío. Reviso el contenido de los datos y es correcto, están dentro de los rangos de pixels de la pantalla y demás. Empiezo a probar cosas y en un momento dado se me ocurre dibujar junto a mis líneas una elipse usando la primitiva ellipse y curioso, me sale le elipse… y todas las líneas que antes no salían. Borro la línea de ellipse y entonces no sale nada. Pongo un circle y ya sale el círculo y las líneas. ¿Es posible que las líneas no salgan si no se dibuja además otro tipo de cosa que no sea una línea?

Bueno, pues el gráfico ya va avanzando, me ha costado más de lo debido por este tipo de cosas y seremos comprensivos con el asunto. GfxBuilder es joven y todavía está en version 0.2.3, por lo que entiendo está todavía en desarrollo y, por lo que veo, con "sus cosas".

Mar 20

Pequeños éxitos con Grails

Un dicho dice "una de cal y otra de arena" para referirse a que unas veces las cosas van bien o son buenas y otras van mal o son malas. Quería llamar al post "una de cal con Grails" o "una de arena con grails", pero como nunca he sabido si la de cal es buena o mala, ni tampoco la de arena, así que he tenido que poner un título más directo.

El caso es que llevo quejándome de Grails un par de posts, pero ayer conseguí hacer funcionar un par de cosas (aunque no he avanzado en absoluto en mi proyecto) y creo justo compartir también las cosas buenas.

Por un lado, Daniel Latorre me dio la solución para el tema de los gráficos con j2d en un comentario del post anterior. La verdad es que la solución es sencilla. Si el método renderImage() desde una action del controller se empeña en enviar su contenido completo al navegador, basta con crear un enlace en otra página, que no tenga nada que ver con esa action, hacia la action que genera la imagen. Por ejemplo, si el controller en GraficosController y la action es generaEstadisticas(), entonces bastaría con poner en una página gsp cualquiera (que no sea generaEstadisticas.gsp)

<img src=”${createLink(controller:’graficos’,action:’generaEstadisticas’)}”/>

En cuanto al tema de logging que tampoco conseguí hacer funcionar en un par de intentos rápidos. Ya está funcionando. ¿Cual era el problema?, Pues en la documentación pone que en el fichero grails-app/conf/Config.groovy hay que poner esto

Logs are named using the convention grails.app.<artefactType>.ClassName. Below is an example of how to configure logs for different Grails artefacts:

log4j = {
   debug "grails.app.controller.YourController"
}

 Así que como mi clase se llama ColumnaController, probé con 

debug "grails.app.controller.ColumnaController"

y no funcionaba. Empezando a intuir que grails es un poco raro con los nombres de los controladores y que a veces no hay que poner la palabra Controller e incluso poner el nombre con minúscula aunque esté en mayúsculas en la clase (ver el parámetro controller del ejemplo anterior del enlace al gráfico j2d), pues probé varias variantes, sin palabra Controller, con mayúscula o minúscula … y ninguna funcionó.

¿Cual es el truco entonces?. Pues es simple, en mi caso ColumnaController pertenece al paquete com.chuidiang.kanban, y también hay que poner el nombre del paquete

debug "grails.app.controller.com.chuidiang.kanban.ColumnaController"

En fin, una pequeña confusión, quizás culpa mía por no ser estricto y saber que ClassName incluye el nombre del paquete, quizás por estar acostumbrado en Java a poner paquete a toda clase que se menea, o quizás habría ayudado si la documentación hubiese puesto

debug "grails.app.controller.YourPackage.YourController"

Supongo que en grails también deben tener que ponerse paquetes a las clases, sobre todo si el proyecto tiene una cierta envergadura, ya que es imprescindible hacer paquetes para separar temas.

Mar 19

Gráficos con Grails: Plugin j2d

 Una de las cosas que me apetecía (en pasado) hacer era unos gráficos estadísticos en mi proyectito del tablero Kanban. Cosas como promedio que tarda una tarjeta desde que se empieza hasta que se termina, de tarjetas en curso, quizás algún tipo de BurnDown. Así que le pregunte a google sobre la posibilidad de hacer gráficos desde grails. Encontré un par de plugins, uno es j2d y el otro birt report. Lo de birt me sonaba a Jasper Reports y lo poquito que he jugado con ello me parecía excesivo para lo que pretendo, así que lo intenté con j2d.

En la documentación cuenta como instalarlo con un comando grails. Correcto, funciona a la primera. En la documentación cuenta un ejemplo sencillo y correcto, también funciona a la primera. Pero el ejemplo se limita a generar un gráfico y mostrarlo en el navegador, el gráfico solo, sin nada más. Yo soy un poco caprichoso y lo del gráfico solo no me gusta, querría que en la página del navegador, además del gráfico, saliera algo de texto, quizás el título del tablero Kanban sobre el que se está mostrando el gráfico, algún enlace para volver al tablero, quizás una pequeña explicación del gráfico. Así que intento, en el mismo controlador, hacer "render" de algo más. Pues bien, si intentas hacer render de algo más salta un error de que el OutputStream ya ha sido enviado (o algo así).

Vuelvo a preguntar al todo-sabedor google y veo en algún sitio/foro que el método renderImage() del plugin, el del ejemplo, efectivamente, envía todo hacia el navegador, cabecera de la petición http, contenido y todo, por lo que no puedes enviar nada más. Mirando el método ese, veo que se le puede poner un nombre de fichero para que grabe el gráfico en dicho fichero. Pues ya está, me digo, grabo el fichero y luego ya enlazaré/incluiré el fichero en la página html/gsp. Mi gozo en un pozo, fíjate que cosas, el fichero efectivamente se graba, pero se sigue enviando todo el contenido al navegador y puedo sin seguir enviar nada, ni poner una página gsp asociada al controlador ni nada.

Pues toca mirar la documentación. Desde luego, la del plugin es totalmente escasa, ya que sólo trae el ejemplo y una descripción de los posibles parámetros. Eso sí, el plugin nos redirige a GfxBuilder librería en la que se basa el plugin j2d. La documentación de GfxBuilder sí que es escasa y está muy asociada a griffon, otro framework similar a grails, pero para aplicaciones de escritorio. Eso sí, GfxBuilder nos redirige a su antigua versión GraphicsBuiler o a una tercera página que dice tener muchos ejemplos.

Mirando la documentación de GraphicsBuilder, efectivamente, hay muchos, muchos ejemplo, casi uno por cada posible primitiva de pintado. Mirando la tercera página que dice tener ejemplos, también hay muchos ejemplos, incluso algunos de ellos muy bonitos, como esferas 3d con sombreado y tazas de café, pero ……. todos, absolutamente todos los ejemplos se limitan única y exclusivamente a decir qué primitivas de pintado tienes que usar para obtener esos maravillosos dibujos. En ninguno te dice a qué clase pertenecen esos métodos, qué clase tienes que instanciar/usar para poder llamar a esos métodos ni cómo pasarle el panel, image, fichero o dónde sea que vaya a salir el dibujo.

Después de pasarme dos tardes discutiendo el asunto en intensivas reuniones con google, encuentro un ejemplo en el que alguien se digna poner el ejemplo más o menos completo, con sus import, su new de una clase GraphicsBuilder o GraphicsRender (no recuerdo, creo que hay las dos) y como hacer que te devuelva el dibujo en una clase Image. ¡¡ Alegría !!. ¡¡ A ello !! Una Image sí sé, con java, grabarla en un fichero. Duró poco la alegría, en el plugin parecen no existir los objetos GraphicsBuilder ni GraphicsRender, tengo que probar más, pero hasta ahora no he conseguido verlos.

También he intentado hacer la imagen directamente en java y grabarla en fichero. Hacerlo con una imagen tonta has sido dos minutillos (afortunadamente, de java controlo un poco más que de groovy), pero me he llevado un pequeño chasco. Arrancando la aplicación con grails run-app, se graba fuera del contexto de la aplicación (por encima de web-app), por lo que desde el navegador no podré acceder a ella. Arrancando de la misma forma, renderImage() la graba en un sitio accesible (debajo de web-app). No sé, quizás me equivoque, pero no parece muy lógico que el directorio actual sea distinto si usas clases java o clases groovy dentro del mismo proyecto.

Supongo que hoy, día del padre y festivo, dedicaré algo más de tiempo a aclararme con esto de los gráficos, pero hoy será el día tope para tener algo o dejarlo por imposible. O quizás lo intente con javascript, que he visto hay miles de librerías ya hechas para gráficos.

Mar 17

Vuelta a los viejos tiempos

Hace un mes algo cambio en el trabajo. Mi grupo, en vez de seguir adaptando nuestro software de siempre a los distintos proyectos en curso (y corrigiendo las incidencias que siempre salen), hemos pasado a realizar software nuevo. Eso me ha llevado a decidir usar TDD, y para la parte de interface de usuario probar fest-swing, y a meterme con izpack para generar los instaladores … y cogida la inercia de probar las nuevas cosas que siempre he querido aprender/aplicar y no he podido, me he lanzado a probar más cosas, en casa y sin tener nada que ver con el trabajo. Openmap primero, tText después, lo de la google app engine con python, etc.

Al final me he decidido a hacer un pequeño tablero Kanban usando Grails. ¿Por qué Grails?. Pues simplemente porque no lo conozco. ¿Por qué subirlo a github? Pues porque nunca he usado git.  Y la verdad es que me ha enganchado bastante todo esto. Llevo varios días en casa programando hasta la una o las dos de la madrugada. Para alguien como yo, acostumbrado a irse a la cama sobre las once, eso son horas realmente intempestivas. Y desde los viejos tiempos de la universidad que no me quedaba programando hasta esas horas.

¿Qué tal con Grails?

La verdad es que me ha decepcionado un poco. La primera impresión con las primeras pruebas fue muy buena, con poco tiempo y pocas líneas de código se pueden hacer muchas cosas. Pero resulta que uso Google Chrome como navegador y tengo de pantalla de inicio una en la que salen las páginas más visitadas. Pues bien, rápidamente la página que muestra las excepciones de mi aplicación se ha convertido en una de las más visitadas y es un poco deprimente.

Por un lado, groovy, el lenguaje de grails, no es fuertemente tipado, por lo que los IDE no dan un auto-completar demasiado completo, cosa imposible si en ningún sitio aparece el tipo de la variable. Esto hace que los errores de sintaxis al escribir nombres de métodos o atributos estén a la orden del día y no los descubres hasta que compilas, aparte de tener que navegar por el código para ver cómo era el nombre exacto.

Además, grails entiende/busca ciertos atributos en las clases para hacer cosas, como hasMany, allowedMethods, belongsTo, etc. Pues bien, nuevamente un error de sintaxis al escribir alguno de estos puede darte quebraderos de cabeza un rato. Compilar, compila, pero luego un tablero kanban no "hasmany" pegatinas dentro y te sale vacío.

La documentación de grails es bastante escasa. Si un tablero hasMany pegatinas, grails añade automáticamente de alguna forma el método tablero.removeFromPegatinas(). Pues bien, navegando por la documentación de grails no he encontrado ningún ejemplo de ese método, pero curiosamente, buscando en google, he llegado a un sitio de la documentación de grails donde sí pone el ejemplo (me hace la impresión de que es una documentación antigua que google encuentra, pero no está enlazada desde la documentación principal). Pues usas el ejemplo tal cual y no funciona, da errores de "deleted object would be re-saved by cascade". Buscando en los foros, veo que es un error que sale con frecuencia y no he visto en ningún foro que alguien dé una solución definitiva. Y lo peor no es que me dé ese error, porque si hago algo mal es normal que me de error, lo peor es que lo da de forma aleatoria en una misma ejecución. En una misma ejecución creo pegatinas, las borro, y unas las borra y otras falla, pero después de fallar, las vuelves a borrar y esta vez sí las borra … o no. Si grails tiene éxito y se usa, estoy seguro que algo estoy haciendo mal, pero desde luego, la documentación no ayuda a descubrirlo.

No todo es malo. Tiene muchísimas cosas que hacen el trabajo más rápido y más fácil. Por ejemplo, si una clase persistente en base de datos tiene los atributos nombre, apellidos y telefono, grails permite hacer consultas con métodos findAllByNombre(‘nombre’), o findAllByNombreAndApellido(‘nombre’, ‘apellido’) o findAllByNombreBetween(‘nombre1′,’nombre2′) y cualquier combinación larga y extraña que se te ocurra con los atributos de la clase, siguiendo ciertas reglas.

Seguiré jugando unos días con grails y la aplicacioncilla que estoy haciendo,

Mar 11

Subiendo “extraños” al repositorio de maven

 Cuando usamos maven entre varios desarrolladores en proyectos más o menos grandes, es normal que montemos un repositorio de jars, estilo nexus o archiva. Cuando ejecutamos el comando mvn deploy, maven sube nuestro jar recién compilado a este repositorio y lo hace accesible para los demás desarrolladores.

Sin embargo, es posible subir a este tipo de repositorios ficheros que no sean .jar, podemos subir cualquier tipo de fichero. El comando mvn deploy:deploy-file con los parámetros adecuados, nos permite subir un fichero cualquiera.

¿Para qué queremos subir ficheros que no sean .jar?. Supón que como parte de nuestro proyecto java usamos JNI con una librería .dll cuyos fuentes en C/C++ también desarrollamos nosotros. No parece una buena forma de compartir la .dll recién generada metiéndola en nuestro sistema de control de versiones. Aunque podríamos hacerlo así, es más elegante usar el sistema de control de versiones para ficheros fuente o de texto que generemos a mano y no usarlo para los "artefactos" que construye nuestro proyecto, como ejecutables, librerías, etc. La solución entonces consiste en subir esa .dll recién generada al repositorio de jars, aunque no sea un jar. El comando puede parecerse a esto (no pongo todos los parámetros, que sería muy largo)

mvn deploy:deploy-file -DgroupId=… -DartifactId=libreria -Dversion=1.0 -Dpackaging=dll -Dfile=libreria.dll -Durl=….

Y esto subiría la .dll al repositorio de jars. La parte interesante de este asunto está en el -Dpackaging=dll. Esto hace que maven ponga al fichero la extensión .dll para subirlo y lo subirá con el nombre libreria-1.0.dll, independientemente del nombre que tenga la .dll antes de subirla.

Y ahora viene otra parte interesante. En nuestro proyecto java podemos poner, en el pom.xml, la dependencia en runtime de esa librería que acabamos de subir

<dependency>
   <groupId>…</groupId>
   <artifactId>libreria</artifactId>
   <version>1.0</version>
   <type>dll</type>
   <scope>runtime</scope>
</dependency>

Aquí, nuevamente, la gracia está en poner <type>dll</type>, ya que esto hace saber a maven y al repositorio de jars que en realidad estamos buscando un fichero .dll, que habíamos subido previamente con -Dpackaging=dll

Por supuesto, la ejecución del comando mvn deploy:deploy-file podemos añadirla al proceso de compilado de nuestros fuentes C/C++ y podemos poner version 1.0-SNAPSHOT, de forma que se suban versiones de desarrollo nuevas cada vez que se compile y que el resto de desarrolladores puedan disponer de ellas.

Mar 06

¿Buzz tiene contenido no seguro?

 He empezado a usar Google Chrome y también Google Buzz desde Google mail (Gmail para los amigos), y me he encontrado una sorpresa curiosa: Google Chrome dice que Google Buzz tiene contenido no seguro. ¡¡ Google se descubre a sí mismo !!.

contenido no seguro en buzzcontenido no seguro en buzz

Mar 05

He leído “Kanban y Scrum – Obteniendo lo mejor de ambos”

He leído "Kanban y Scrum – Obteniendo lo mejor de ambos" que te puedes descargar en el post del enlace, hacia el final, en cristiano.

En una primera parte, comparan scrum con kanban en plan teórico. No explican scrum con detalle ni kanban, es algo que se da por supuesto, simplemente se centran en comparar qué cosas hace uno y qué cosas hace el otro.

En la segunda parte se cuenta una historia real en la que intentan implantar Scrum o Kanban en un departamento de una empresa real. Van explicando los problemas de ese departamento, analizando posibles soluciones, implantándolas y viendo las mejoras que se producen en el proceso. Para su caso concreto se deciden por Kanban y lo van adaptando hasta que se hace cómodo. El tablero Kanban se convierte en una herramienta importante para ver si hay problemas y si se solucionan.

La parte teórica de comparación es más o menos lo ya sabido y como comparación teórica está bien, hay algunos detalles que no tenía claros y se han quedado aclarados, sobre todo en la parte Kanban que quizás conozco menos o está menos documentada que Scrum.

La parte de implantación práctica no me ha gustado demasiado el cómo está escrita. Trata de explicar los problemas del departamento, las posibles soluciones, la implantación de la mismas y los resultados obtenidos, pero lo hace en muy pocas hojas y demasiado por encima para mi gusto. Al final de la lectura me ha quedado la impresión de … "¿ya está?" y de "kanban es maravilloso, fíjate como el departamento del que todo el mundo se quejaba en cuatro meses ha ganado el premio al más productivo".  Parece propaganda.

Sin embargo, si leemos entre líneas (o, al menos, no nos quedamos en los detalles), sí sacamos la conclusión de lo que es Kanban en el fondo. Y en el fondo kanban es detectar los problemas, encararlos y solucionarlos. El tablero kanban ayuda a detectar si hay o no problemas, viendo si las pegatinas se apilan en alguna columna o van fluyendo de principio a fin sin aglomeraciones. Y el tablero kanban ayuda a ver si la solución que hemos puesto al problema es efectiva o no, viendo si las pegatinas se desatascan o no. Lo realmente importante de toda esta filosofía es "ten claro tu objetivo, detecta los problemas para conseguirlo, afróntalos y solucionalos". En el libro, el uso del tablero kanban no es más que la herramienta, lo importante es que detectaron porqué no funcionaba bien el departamento, consiguieron mejorar su forma de trabajo, involucrar a la gerencia para que ayudara a solucionar problemas y mejoraron sus resultados. Todo un reto.

Mar 04

Rangos de dependencias con maven

 En maven todos estamos acostumbrados a poner las dependencias y en concreto, a poner la versión concreta que queremos de la dependencia. Por ejemplo, si nuestro proyecto depende de log4j, solemos poner algo como esto

<dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.13</version>
</dependency>

es decir, ponemos la versión concreta que deseamos de log4j, en esta caso, la 1.2.13

Pues bien, es menos conocido, quizás porque la documentación de maven es algo escasa, pero podemos indicar a maven un rango de dependencias, de forma que maven traerá la más moderna disponible. Para ello se utiliza la notación matemática para rangos de valores, donde se abre paréntesis o corchete, se pone el número de versión inicial, coma, el número de versión final y se cierra paréntesis o corchete. Un corchete indica que la versión inicial o final es válida, mientras que un paréntesis indica que no es válida. Dejar en blanco uno de los números de versión indica que no hay límite por ese lado. Así, por ejemplo

[1.2, 1.5)     Cualquier versión entre la 1.2 y la 1.5, incluyendo la 1.2 (corchete al principio), pero excluyendo la 1.5 (paréntesis al final)

[1.3, )           Versión 1.3 o superior, incluyendo la 1.3

[1.0, 2.0)     Cualquier versión 1.x.x, pero inferior a la 2.0

En realidad maven admite hasta tres números en la versión más un "cualificador". El cualificador es un nombre cualquiera que se pone detrás del número de versión separado por un guión. Por ejemplo, imagina que en nuestro proyecto entregamos una versión al cliente FEDERICO y creamos una versión congelada para ese cliente. Su número de versión podría ser 1.2.3-FEDERICO. O más común, si es una "Release Candidate", le ponemos 1.2.3-rc, o si es una beta, pues 1.2.3-beta.

No lo he probado, pero imagino que esto permite poner cosas como

[1.2, )-FEDERICO

de forma que maven traerá cualquier versión 1.2 o superior que tenga el cualificador FEDERICO, es decir, que sea del cliente FEDERICO.

Considero esto realmente interesante, porque en un proyecto grande en el que hay muchos jar desarrollados por la gente de nuestro equipo y en los que cada jar tiene sus responsables, cada responsable puede subir su número de versión cuando lo considere adecuado y los demás traerán automáticamente o no esa versión según lo que pongan en las dependencias. Si yo no quiero traerme los cambios que haga Juan en su jar, símplemente pongo que quiero la versión 1.4. Pero si me interesa traerme siempre su versión más moderna, entonces pongo [1.0, ).

Aunque supongo que es bastante conocido, aprovecho para poner aquí cual es el significado de esos tres números de versión. Si la versión es a.b.c, los números se incrementan normalmente siguiendo los siguientes criterios:

  • a se suele incrementar cuando el cambio es tan importante que hace la nueva versión incompatible con las anteriores. Si guardas datos con una versión 2.0 de un programa, posiblemente no puedas leer esos datos con la versión 1.0 del mismo programa (normalmente al revés si suele ser posible).
  • b se suele cambiar cuando no hay pérdida de compatibilidad, pero sí se han añadido nuevas funcionalidades. Por ejemplo, las versiones 1.3 y 1.4 pueden usar los mismos datos guardados indistintamente, pero la 1.4 permite imprimirlos mientras que la 1.3 no.
  • c se suele cambiar cuando se han arreglado errores respecto a la anterior. Por ejemplo, la 1.2.3 puede caerse cuando el usuario pulsa el botón A, luego minimiza la ventana y le da a la tecla de tabulador. La 1.2.4 ya no tiene ese error.

Por supuesto, esto es una convención más o menos aceptada, pero desde luego no es obligatoria.