Django y Google App Engine → (Semi) FAIL
En cierta asignatura de la facultad me tocaba como práctica implementar una pequeña aplicación web dinámica. El camino sencillo habría sido tirar por hacerla en Rails, pero mi pequeña cabeza (es un decir, ya se que tengo un cabezón y soy un cabezota) estaba ansiosa de aprender cosas nuevas, y como no estaba metido en casi ningún lio más (sí, ya, claro), me decidí que a parte de implementar la práctica debería aprender algo nuevo.
Podría haber tirado por hacer algo con Merb o mezclar Sinatra con DataMapper o Sequel (técnicamente con los dos primeros sí he hecho algo, pero no a fondo).
Sin embargo, mi espiritú explorador me llevó a redactar mi propuesta diciendo que utilizaría Google App Engine, algo que quería probar desde hace tiempo. Obviamente esa decisión limitaba mi elección de framework a alguno basado en Python. Y, claro, como siempre existe la lucha Rails vs. Django.
El proyecto en sí al final ha sido sencillo: unas 1000 líneas de código, 6 modelos y 14 “vistas” (en Django no se separan las vistas por controladores, pero en Rails serían unos 5 controladores). Para el aspecto visual decidí tirar por lo sencillo y utilizar Blueprint CSS, desde luego un gran recurso si no dispones de tiempo o capacidades. Finalmente como framework JavaScript me decidí por jQuery (aunque no hay que tener mucha decisión sobre ello), pero con el añadido de que el código tenía que ser “no obstrusivo” (un placer, aunque el código final no me agrade demasiado. Necesita un poco más de amor). Tiempo para la entrega cuando empecé: 2 semanas. Objetivo: logrado, y con buena nota.
Pero no todo ello sin sangre, a veces por Django, a veces por Google App Engine, a veces por la mezcla de los dos.
Django, debo decirlo, parece un gran framework web: es open source dispone de una agradable página web, tiene sus propias conferencias, una gran documentación (aunque algo desorganizada en algunos puntos), una compañia detrás y muchos productos utilizándolo. Lo primero que hice fue dirigirme a su “famoso” tutorial y hacerlo, sin tener de por medio el App Engine. Lo cierto es que depués del tutorial me quedé muy impresionado, sobre todo por la creacción del sitio de administración automático, una clara ganancia de velocidad, sobre todo en las primeras fases de desarrollo.
Mi primera decepción (iba a poner “desilusión”, pero me he contenido por si a Mecano le da por mandar un cease & desist) es que lo más interesante de Django no funciona en Google App Engine: su sitio de administración. Obviamente es debido a que App Engine utiliza una base de datos no-relacional, y el sitio de administración de Django no sabe funcionar en esas condiciones. Según investigaba más App Engine más restricciones se imponian sobre Django: no se pueden utilizar los Django Models, ni la mayor parte del middleware desarrollado para Django… vamos que al final utilizabas el dispatcher y el sistema de templates. Además, para empeorar las cosas App Engine incluye una versión algo antigua de Django, por lo que encima tienes que incluir con tu aplicación la tuya propia.
Por suerte, Google App Engine también cuenta con una gran documentación (aunque a veces no está muy clara, y es extensa) y sobre todo una serie de artículos muy interesantes. Entre esos artículos se encuentran aquellos que te explican como utilizar casi todo lo que has aprendido de Django en App Engine (y donde difieren las cosas).
La segunda desilusión (¡toma eso, Mecano!) de Django es su sistema de templates. Siempre había leido maravillas sobre lo poderoso y sencillo que era, pero cuando te pones con él… bueno, se queda un poco a la altura del betún. Me explico: el sistema de templates de Django está diseñado con un par de propositos: que los diseñadores no toquen el código y que no produzcan excepciones. Muy loable por su parte, pero estar tan encorsetado no permite realizar cosas tan sencillas como un if … else if … else o construcciones similares. Y por los ejemplos que he visto (de otras aplicaciones implementadas en Django) hace que muchas “decisiones” que deberían ser de la vista se tomen en el “controlador” (que Django llama “vista”… así que quizá no esté mal del todo, pero están en un archivo de código, que manejan los programadores. Que cada uno decida). De pura desesperación pasé evaluado una hora una versión de Haml implementada para Python, aunque al final decidí no utilizarla (no recuerdo porqué).
Finalmente llegamos a las quejas sobre Google App Engine. Bueno, como todos los productos Google está en beta (aunque esta vez lo llamán “Preview Release”), pero nunca he probado un producto suyo con el que me hubiera decepcionado tanto. La funcionalidad básica está bastante bien (dentro de las limitaciones que imponen), aunque no espero que piensen que tienen un producto por el que la gente vaya a pagar y acudir en tromba. La idea de escalabilidad automática (tanto en cuestiones de base de datos como de proceso) suena tentadora, pero ¿a qué coste? Un punto a su favor es el sistema de deploy, por el que habría que darles un 10.
Los problemas en App Engine empiezan por su data store, basado en las tecnologías de Google. Obviamente conocia esta ventaja/limitación cuando seleccioné App Engine, pero no conocia todos sus detalles. El primer problema es olvidar muchos de los conceptos y normas que se aprende diseñando bases de datos relaciones, y desnormalizar en casi todos lo puntos: por ejemplo, App Engine es pésimo contando (suponiendo que sus registros pueden estar en 1 o en 100 servidores diferentes, no es algo tan descabellado), por lo que muchos de los modelos se llenan de campos comment_count y similares.
Otra diferencia del data store con las bases de datos es que no puedes hacer JOINs y similares, así que tus queries están limitadas a un solo tipo de entidad. En la mayor parte de los casos esto no es problema, pero te obliga de nuevo a desnormalizar en muchos puntos. Y el problema de desnormalizar es que tienes que ser muy cuidadoso en un entorno multi-hilo… como una aplicación web. Por suerte App Engine utiliza una idea bastante curiosa de entidades padres e hijas, que a parte de suponer una relación 1 a n implica también grupos transaccionales. Ese es otro punto a su favor, aunque entenderlo lleva un buen rato y seguramente como la cagues en este punto tu aplicación acabe pasto de Digg o Slashdot.
El detalle final sobre el data store de Google App Engine es el que me volvió loco. Una restricción de las queries es que no puedes utilizar operadores de desigualdad en más de una propiedad de la entidad. En mi aplicación tenía un modelo con fecha inicial y fecha final, y quería mostrar todos los modelos cuyas fechas incluyesen la actual, algo que en cualquier otra base de datos se hubiese arreglado con un WHERE start_date <= now() AND end_date >= now(), en App Engine era imposible. Afortudamente encontre que alguién se había cruzado con el mismo problema y lo había resuelto con una ingeniosa treta: en App Engine las propiedades pueden ser una lista de valores, y las comparaciones con ellos se hacen con todos ellos, por lo que si incluyes en una sola propiedad la fecha inicial y la final y haces un WHERE date_range <= now() AND date_range >= now(). Una idea genial, que funcionaba perfecta en desarrollo, pero que no funciona (y sigue sin hacerlo, más de un mes después de haber “votado” por el bug) en los sistemas de Google. Y no hay alternativa.
Sin embargo lo que más me decepcionó no fue esos detalles, sino que estamos en el 2009, en un mundo global y los dichosos (por no poner otra cosa) programadores americanos parece que no saben que existe algo fuera de los carácteres ASCII. Como buen programador, siempre intento utilizar UTF-8 en todas las partes de la aplicación, desde la base de datos a la capa de presentación, pero los ingenieros de Google decidieron que no merecía la pena realizar su sitio de administración en el servidor de desarrollo compatible con algo más que con ASCII, porque ¿quién iba a utilizar datos UTF-8 en un servidor de desarrollo? Otros usuarios ya se habían encontrado el bug (obviamente los chinos tienen muchos más problemas que nosotros), enviado parches y “votado” al bug (yo también). Por suerte, estaba vez en la consola de administración de producción las cosas estaban bien hechas. Creía que mis problemas con UTF-8 habían finalizado, pero cuando intenté subir los datos a la base de datos de producción volví a caer en los mismos errores. Nuevo bug, nuevo parche (por suerte el fallo está en una parte de App Engine que puede ser sustituida con código del usuario) y otro “voto” (han modificado la importación/exportación de datos en las últimas versiones, así que esto puede haber cambiado).
Así que al final la experiencia (a pesar del resultado) fue un poco desastre (por eso el semiFAIL y no el FAIL completo). Si ahora mismo tuviese que elegir una plataforma para desarrollar una aplicación web diseñada para mucho tráfico desde luego no utilizaría App Engine, aunque quizá dentro unas cuantas iteraciones acaba siendo el producto que uno espera de Google.


24 de Marzo de 2009 a las 10:06
No entiendo porqué una vista no puede estar en un archivo de código. Para mi la vista es el componente que decide cómo se muestran los datos al usuario, pero no lo veo como algo ligado a una tecnología (entiendo que tú lo ves raro porque esperas un HTML con scriptlets o similar).
Creo que incluso aunque estemos hablando de una aplicación web, no tiene porqué ser así, de hecho creo que en GWT (del que he oido maravillas) todo es código Java y las vistas se crean usando un API a la AWT pero orientado a web.
Por lo demás, una entrada interesante que me ha quitado las pocas ganas que tenía de probar el App Engine (o mejor dicho, no me ha quitado las ganas, que siguen ahí, pero ha multiplicado exponencialmente la pereza de hacerlo
).
24 de Marzo de 2009 a las 12:37
Esto va a ser complicadillo de explicar…
Las limitaciones que impone Django templates provocan que el “diseñador” y el “programador” (yo tampoco veo esa separación muy clara, pero sí que creo en que hay gente más orientada hacia una cosa u hacia la otra, pero que ambos deben conocer donde se mueven y que hay más allá de sus “dominios”) tengan que transpasar “responsabilidades” de los templates a las “vistas” (y recordemos que Django las llama vistas, pero en Rails caerían dentro de lo que se denomina controladores) o a los template tags (que como creo que has utilizado JSP supondrás como son). Las vistas (lease controladores) son cosa de programadores, de forma que los diseñadores no deberían tocarlas, y los template tags implican conocimientos más allá de lo que se les supone a los diseñadores. Era eso a lo que me refería con que los diseñadores debían tocar el código de los programadores.
Lo que creo que describes tú en el siguiente párrafo es un patrón que se denomina “presentador” (Presenter, en inglés). En él se preparan y mastican todos los datos que la vista necesita, pero se deja la decisión final de como mostrarlos a la vista en sí (en forma de tabla, gráfico, etcétera). Personalmente programo de un modo bastante similar (quizá no tan estructurado como un patrón presenter real), de forma que en la vista (los archivos HAML o, si no se tiene tanta suerte, ERB) se tomen únicamente decisiones de diseño y no exista casi código. Django templates intenta algo similar, pero no proporciona el contrato intermedio entre presentación y datos, con lo que incrementa la comunicación necesaria entre esos dos componentes.
Y si tenías ganas de probar App Engine, por favor, que la entrada no te desanime, quizá tu experiencia en otros framework web te de otra visión de lo que App Engine ofrece. Me encantaría leer las experiencias de otras personas con App Engine.
24 de Marzo de 2009 a las 15:45
Estaba contestando, pero me he dado cuenta de que tenía una tasa de “supongo que” demasiado alta debido a que no conozco Python.
En realidad, lo que me apetecía era probar Python, y el App Engine parecía un buen lugar para hacerlo. Pero bueno, si ves que no lo hago no te sientas culpable, seguramente será porque el tiempo se me vaya en mis otros proyectos
.
24 de Marzo de 2009 a las 16:14
Python está muy bien. El uso del whitespace (lo que mucha gente le critica) hace que las cosas queden muy claritas. Luego tiene cosas muy chulas pilladas de los lenguajes funcionales, como las listas por comprehensión. Y luego tiene los decoradores (de lo mejorcito utilizando Django), que si bien se pueden simular en Ruby, la síntaxis integrada es muy útil.
Merece la pena aprender un poco, de hecho se aprende en un fin de semana lluvioso (se que de eso no teneís demasiados ya en España, pero bueno).