Hace poco terminaba el pequeño tutorial sobre compojure que he estado escribiendo y que me ha servido para hacerme una idea de cómo se desenvuelve un lenguaje funcional en aplicaciones «normales».
Es cierto que he dejado sin cubrir partes importantes y necesarias en la mayoría de aplicaciones, como es el acceso a bases de datos (SQL o NoSQL), la autenticación y autorización, test unitarios, etc., pero creo que tengo la base suficiente como para empezar a buscar y valorar soluciones a cada uno de esos problemas por separado cuando llegue el momento.
Pese a esos aspectos que quedan en el aire, ha llegado la hora de hacer balance sobre lo que supone usar clojure para el desarrollo de aplicaciones web.
Las partes buenas
Sin duda, lo que más me ha gustado es la simplicidad y naturalidad con que encaja todo.
Para poder trabajar con compojure no hace falta comprender un montón de abstracciones y conceptos nuevos. Al final todo se reduce a definir funciones que reciben maps con las peticiones y devuelven maps con las respuestas.
Aquí además se nota mucho el uso de estructuras de datos sin esquema tan frecuente en clojure. Esto, unido a las opciones de desestructurado de clojure hace que sea muy sencillo obtener los datos que necesitamos de las peticiones para generar las respuestas.
Al trabajar con algo tan básico como funciones y maps, si necesitamos algo nuevo sólo necesitamos decorar nuestras funciones con middlewares
como veíamos en el caso de recibir datos con JSON.
Esto además permite tratar todo de una forma mucho más homogénea si lo comparamos, por ejemplo, con ASP.NET MVC, donde el pipeline de proceso de peticiones es más complejo y debemos distinguir entre cosas como ActionFilters, HttpHandlers, Controllers, ModelBinders, ValueProviders, Results, etc., a la hora de decidir cómo implementar algo.
Otro aspecto que me ha gustado mucho es la forma en que se genera HTML usando Hiccup. Poder generar HTML usando el mismo lenguaje en el que estamos programando la aplicación hace que muchos de los problemas que hay que resolver con otros sistemas de plantillas directamente no existan en Hiccup.
Por ejemplo, el uso de controles/helpers para encapsular HTML es algo que se resuelve sencillamente creando una función que devuelva el HTML que necesitamos. Algo similar pasa con los layouts, no hace falta recurrir a nuevas abstracciones para resolver el problema porque estamos usando el mismo lenguaje en el que desarrollamos, por lo que las mismas técnicas que se usan para reutilizar código, las podemos aplicar en la generación de HTML.
Lo más parecido que he visto en C# son fluent builders para generar el HTML, pero aunque tienen la ventaja de tener tipado estático (y todo lo que ello conlleva a nivel de tooling), la sintaxis de C# mete demasiado ruido y acaban siendo poco legibles.
Las partes menos buenas
Nada es perfecto y hay algunas cosas que me han parecido más incómodas, algunas de ellas genéricas de clojure y otras específicas de algunas de las librerías que he usado.
Por una parte, la sintaxis hay veces que se hace un poco cuesta arriba. La simplicidad de conceptos que mencionaba antes tiene un coste: todo son funciones, todo son paréntesis. A veces se hace complicado seguir qué va dentro de qué, especialmente cuando se construyen estructuras complejas como las que se usan para generar HTML desde Hiccup.
Parte de esto se puede solucionar mediante tooling, pero tampoco es fácil. Parece que la forma canónica de escribir clojure es usando emacs y alguno de los cientos de configuraciones personalizadas para clojure, pero la verdad es que aprender a manejar emacs no es cosa de dos días y cuesta acostumbrarse, y no sólo por el paso de un IDE tipo Visual Studio a un editor más ligero, sino porque la filosofía de trabajo es bastante distinta.
Hiccup está muy bien y supone un cambio en la forma de pensar en la generación de HTML, pero si pretendes que te lo genere alguien que sepa diseñar páginas bonitas, se va a volver loco. De todas formas, que esto sea grave depende de cómo trabajes. La mayoría de las veces que he trabajado con diseñadores, no tenían acceso al código fuente y trabajaban «por libre». Nos daban HTML y nosotros nos encargábamos de generarlo usando WebForms, Razor, o lo que tocase, por lo que puede que este punto no sería crítico.
En general, la documentación es un poco escasa y gran parte está repartida en posts e hilos de discusión desactualizados (como seguramente estarán estos posts dentro de unos meses). La parte positiva es que el código fuente tanto de compojure como de hiccup es bastante fácil de seguir, incluso aunque no seas un experto en clojure, como es mi caso.
Conclusiones
Desde mi época de estudiante siempre me ha atraído la programación funcional, pero nunca había intentado ponerla dentro de un contexto actual. Siempre la había percibido como algo académico y teórico, más enfocado a la experimentación y solución de problemas más «algorítmicos» que al mundo real.
Cuando desarrollo con C# hago bastante uso de las características funcionales del lenguaje (que no están mal), pero no dejo de estar en un entorno orientado a objetos con pinceladas funcionales. Al final lo que mandan son los objetos y la estructura de la aplicación está dictada por ellos.
Desarrollar la mini aplicación web del tutorial de compojure me ha permitido comprobar que realmente se puede llegar muy lejos con un lenguaje funcional en aplicaciones cotidianas. Me ha encantado la naturalidad y simplicidad con que se resuelven algunos problemas, sin necesidad de construir capas y capas de abstracción.
Interesantes los comentarios, revelador (no por esperarlo me resulta menos revelador) que la sintaxis en ese contexto sea un freno (busco desde hace tiempo conciliarme con la sintaxis lisp, creo que nunca lo lograré).
Hecho en falta algún comentario sobre el tratamiento de la inmutabilidad ¿o no la mantienes?.
Saludos! ;)
Lo de la sintaxis supongo que será cuestión de acostumbrarse, pero a veces cuando se empiezan a anidar listas de listas de vectores de maps de listas de vectores… es fácil perderse.
El tema de la inmutabilidad es interesante. En una aplicación web SPA como la del tutorial, casi todo el estado mutable queda en el cliente, que en este caso está hecho con Javascript donde la mutabilidad es algo normal e idiomático (con ClojureScript sería otra historia).
En la parte servidor lo único mutable es la parte del modelo y, realmente, está metido con calzador para poder tratarlo en el tutorial usando atoms. En la vida real eso seguramente estaría una BD y sería la que se encargaría de lidiar con los cambios, con lo que desde clojure solo verías datos que lees de la BD y datos que mandas a la BD y ahí puedes usar estructuras de datos persistentes (posiblemente maps o records) y mantener la inmutabilidad.
De todas formas, en la mayoría de aplicaciones web, que son en un 80% CRUD, hay muy poco estado mutable que se mantenga en el servidor web, como mucho la sesión (y puede que hasta eso acabe una base de datos), por lo que creo que afecta poco en este contexto.
Me congratulo de que cada vez aparezca mas material del calidad en castellano sobre clojure.
Solo apuntar un par de cosas:
* Mas que acerca de compojure, me parece que el tema central seria «ring», que es la especificacion que define el midleware, adapters, etc. Compojure es una opcion (entre otras) para definir en ring la rutas.
* La sintaxis de lisp es peculiar y diferente a la que estamos acostumbrados, exige cierto esfuerzo acostumbrarse a ella para disfrutar de sus ventajas. Sin embargo clojure es el lisp con la sintaxis menos «radical»: las funciones predefinidas suelen exigir menos anidacion que otros lisps y ademas tiene sintaxis especifica para las estructuras de datos con lo que estas se identifican rapidamente en el codigo.
Cierto es que casi es obligatorio usar paredit, que es la extension para emacs que te autocompleta/elimina/anida/desanida los parentesis de forma automatica. Usar emacs te da otra serie de ventajas que hacen el desarrollo de lisp tan comodo como el de java en eclipse o c# en vs. Sin embargo el soporte para clojure en eclipse (counterclockwise) y otros ides va mejorando y creo que no tardara demasiado en alcanzar a emacs.
Hace poco relei un articulo sobre el desarrollo web en clojure bastante completo y resumido y valido pese a tener algun año:
http://brehaut.net/blog/2011/ring_introduction
En el habla de otras alternativas para cada uno de los componentes: por ejemplo moustache para el routing o sobre todo enlive para las plantillas, que permite separar completamente el html de la logica que lo usa parfa generar las vistas.
Una referencia muy util para buscar documentacion en clojure es:
http://clojure-doc.org/
en la que se puede encontrar el articulo anterior. Una pena que no suela aparecer en las busquedas sobre clojure en google.
Gracias por las observaciones. Tienes razón en cuanto a que realmente en el post se habla más de ring que de compojure, pero puesto que llegué a esas conclusiones a partir de los post sobre compojure, parecía razonable enlazarlo con eso.
Sobre las distintas alternativas para routing y templates, es una de las cosas que iba a poner en el post, pero no estaba seguro de si me gustaba o no: la variedad de alternativas. Pasa lo mismo en Javascript, hay cosas para las que tienes 10 librerías, ninguna domina claramente sobre las demás, y es dificil elegir. En clojure se hace incluso más dificil porque al ser más minoritario es complicado encontrar opiniones/documentación que te ayuden a saber el grado de madurez de cada una. A cambio, ganas flexibilidad y tienes un entorno mucho más personalizable que, por ejemplo, .NET.
No conocía http://www.clojure-doc.org, y te aseguro que en las últimas semanas he hecho unas cuantas búsquedas en google. Deberían cuidar más el SEO :-P
«Hay cosas para las que tienes 10 librerías, ninguna domina claramente sobre las demás, y es dificil elegir.»
Lo bueno: si has separado correctamente las partes, suele ser cambiar un par de funciones y puedes ir probando librerias diferentes a ver como tiran.
En otros lenguajes esto seria muy lento (recompilar, meter muchos cambios, etc.)
Guillermo, es cierto lo que dices, si el diseño es adecuado las librerías no deberían impactar mucho la aplicación, tanto en clojure como en otros lenguajes. En lo que sí ayuda clojure es que muchas librerías trabajan con tipos básicos (maps y seqs) por lo que las funciones no tienen dependencias sobre tipos definidos en las propias librerías y por tanto son más fáciles de portar.
Lo malo es que a veces hay aspectos de la aplicación que son bastante «invasivos» en cuanto a que no puedes aislar su uso en uno o dos puntos (el caso del sistema de plantillas para generar html es uno de ellos).