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".