lunes, 18 de marzo de 2013

Sobre el polimorfismo en clojure y la oop

(Este post nace como comentario a esta discusión acerca de la programación orientada a objetos y la funcional)

No es mi intención "combatir" ni "batir" a la oop, aunque es verdad que algunos defensores de la programación funcional, sobre todo los recién llegados a la misma tienen la típica actitud de los herejes conversos de atacar con ferocidad aquello que defendían. Sin embargo 20 años de hegemonía casi absoluta y un tanto arrogante en algunos momentos de la oop se merecen señalar, al menos durante una temporada, sus limitaciones.

La oop supuso un avance respecto a la programación estructurada aunque para "batirla" tuvo que hacerle concesiones. Por ejemplo es perfectamente posible escribir programación estructurada con java y me atrevería a decir que la gran mayoría del uso de java dentro del mundo enterprise tiene mucho (¿demasiado?) de estructurada.

De la misma manera la oop y la funcional pueden combinarse, siendo scala uno de los mejores ejemplos: para algunos sus características funcionales son las que precisamente le permiten superar esas concesiones a la programación estructurada y llevar la oo mas lejos que java. Por otro lado clojure también comparte algunos elementos (¿concesiones? :-P) que son claves en la oop y que os seran familiares.


Uno de estos elementos es el polimorfismo. Uno de los ejes de la defensa de la oop que no es en absoluto exclusiva de la misma aunque hay que reconocer que ha sido el primer paradigma que le ha dado una papel central y lo ha popularizado. Al igual que con la encapsulación son conceptos "ortogonales" a la oo: lenguajes no oo lo tienen, incluso lenguajes anteriores a la oop.

En el debate que originó este post se han tratado dos temas que tienen que ver directamente con el polimorfismo. El ejemplo trata sobre la "entidad" usuario y un método de expiracion que debe modificar el estado del usuario y guardar ese cambio de forma permanente:
  1. Una de las cuestiones es donde "vive" el código que expira al usuario (o tal vez cualquier cosa que se pueda expirar). Esto esta relacionado con el tema del "modelo anemico" y la tensión entre la programación estructurada y la oop. @Alfredocasado propone una solución dinámica en la que el código vive en un sitio pero se inyecta temporalmente al usuario ya que en determinados contextos ahí es donde parece (o se espera) que deba estar. @jmarranz prefiere una situación mas estática en la que es explicito en tiempo de compilación que código se esta usando. Segun su punto de vista ese código no debiera pertenecer al "espacio de nombres" del usuario, sino a otro que tome al usuario como parámetro. Un punto de vista más "estructural" pero también más funcional.
  2. Otra es como unificar y simplificar el espacio de nombres de las funciones/métodos para evitar cosas como write-to-db, write-to-file o peor, write-to-db(data,flag1,flag2,...) 
En cuanto al punto primero sin saber más del contexto de expire no se muy bien donde lo pondría. Tiendo a pensar que no en un módulo donde haya funciones que tengan que ver con el usuario sino en uno que tuviera que ver con el objetivo de expirar un usuario o cualquier otra cosa (si hay mas cosas que se puedan expirar) O sea en el módulo que se encargara de agrupar las funciones que actuan sobre "éso" donde que algo haya expirado o no tenga sentido.
En cuanto al segundo en clojure (y cualquier otro lenguaje funcional moderno) tienes varias opciones para hacer polimórfica una función: multimétodos y protocolos.

Multimétodos

Los multimétodos pueden ser polimórficos en función de cualquier combinación de cualquiera de los valores (no solo el tipo) de sus parámetros. Esta forma de polimorfismo es estrictamente mas genérica y mas poderosa tiene una serie de ventajas que la hacen más flexible que ciertas implementaciones del polimorfismo en la oop. En estas el dispatch se realiza solo en función del tipo (clase) del primer argumento del método que muchas veces es implicito (this). 

Se puede indicar cual es el método que se usa por defecto si no hay uno definido para unos valores particulares y cual es el preferido si existen dos definiciones de métodos que choquen.

Protocolos

Los protocolos son algo así como interfaces pero más flexibles: cualquier tipo puede extenderse hacia un protocolo estaticamente o al vuelo, incluso los que no han sido definidos por el programador. Los protocolos se añadieron en clojure porque los multimetodos eran mas lentos que el dispatch usando interfaces de la jvm y para que los recien llegados de la oop estuvieran mas comodos :-P

Referencias

Otra cuestión es que el código que llama a write tiene que tener un "writer" o "repositorio". Este puede estar definido estaticamente importando el módulo adecuado (o módulos si se quieren diferentes tipos) O también se le puede asociar dinamicamente al usuario:

O se pueden usar variables globales al módulo que pueden ser dinamicamente redefinidas:

Anda, ¿es que entonces se pueden modificar variables globales en clojure?. Pues sí, pero como comente anteriormente la mutación es por defecto segura concurrentemente. En el caso de las variables globales (o vars) estas pueden ser redefinidas por "binding" solo dentro del ámbito lexico de ese binding y dicha redinifición es local al thread que ejecuta ese bloque de código.
Y ya que nos ponemos y las funciones en clojure se guardan en variables globales, ¿por qué no modificar la funcion write misma? Pero eso tal vez en otro capitulo.

Nota: recientemente he leido en el blog de un importante miembro de la comunidad que el uso de variables globales dinámicas tiene una serie de limitaciones en cuanto a la concurrencia y otros aspectos. Para evitarlas recomienda siempre exponer una llamada con el recurso como parámetro para que el llamador tenga la opción de llamar de una u otra forma. Así la habia escrito yo aunque sin ser consciente de todas las limitaciones que lo hacen necesario.

domingo, 2 de diciembre de 2012

Idas y vueltas entre aplicaciones web

Una vez al año no hace daño.

Cuando se trabaja en un entorno en el que conviven varias aplicaciones es natural que tarde o temprano se comuniquen entre ellas o incluso que desde un principio estén diseñadas para ello. El objetivo es conseguir un sistema modular en el que se duplique la mínima cantidad posible de información y de esfuerzo de los desarrolladores y mantenedores de las aplicaciones.

Esta comunicación puede hacerse a muchos niveles y de muchas formas pero lo ideal es que las dependencias sean lo mas flexibles posibles y no haya acoplamientos rígidos, que el sistema sea distribuido y que use protocolos estándar no propietarios.

 En los últimos tiempos hay una arquitectura en alza que parece puede cumplir esos objetivos en mayor medida que otras alternativas mas aparatosas: hablamos de REST, claro esta. Sin embargo cuando hablamos de aplicaciones con interfaces gráficas surge la aspiración de extender esa reutilización hasta la misma interfaz y no quedarse solo a nivel del API. Así a bote pronto se me ocurren pocas alternativas para reusar dinamicamente, en tiempo de ejecución, interfaces graficas complejas de diferentes aplicaciones web: portlets tal vez. Si conoceis alguna no dudeis en apuntarla, si es posible con sus ventajas e inconvenientes.

En mi caso inspirandome en el flujo de una autenticación vía http del tipo oauth opté por lo que me pareció una solución directa y sencilla (demasiado tal vez), al menos a simple vista: hacer una llamada estándar http de una aplicación a otra  con el objetivo de presentar el html servido por la segunda. Este html no es embebido ni transformado: simplemente la pagina servida por la otra aplicación se carga en el navegador. En la llamada la aplicación "cliente" o llamadora incluiría en los parámetros la url (que puede ser de la misma aplicación cliente) y parámetros de vuelta. La aplicación servidora los utilizara en determinados puntos para que el usuario pueda volver a la aplicación original o a la url siguiente en el flujo de la operación, añadiendo mas información en los parámetros si es necesario.

Por ejemplo tenemos el típico caso en el que una aplicación tiene que elegir un recurso o recursos de otra para completar una operación. Una llamada al API teniendo su identificador es muy sencilla pero para conseguirlo de una forma cómoda pueden hacer falta varias pantallas de filtro y navegar entre varios recursos y pantallas. Es lógico querer reutilizar toda ese flujo y la interfaz y que la aplicación cliente no dependa de si cambia la lógica tanto de negocio como de la presentación. La llamada tendría este esquema:

http://server/aplicacion-tramitacion/expediente/201001?select=informe.inicial&ciudadano.id=dni&client.urlback=/aplicacion-atencion-ciudadana/peticion/&client.urlback.params=usuario=x


Para ello la aplicación servidora debe estar preparada para gestionar esas peticiones externas, modificando ligeramente su propia interfáz para añadir los puntos donde el usuario puede volver a la aplicación originál (o a cualquier otra), bien seleccionando uno o varios recursos o cancelando la selección. El usuario navega entre el filtro, los listados y los detalles de los recursos hasta encontrar el deseado y volver usando "client.urlback"

http://server/aplicacion-atencion-ciudadana/peticion/3?informe.inicial=12&usuario=x


Este es justamente el caso en el que efectivamente lo he usado. Sin embargo no estoy totalmente seguro de los posibles inconvenientes de esta solución, sobre todo a la hora de generalizarla a otros casos diferentes y como puede escalar en función de la complejidad de las llamadas. Tampoco tengo una referencia de posibles alternativas con las que comparar y evaluar los pros y los contras. Por ejemplo el número de parámetros de las llamadas puede hacerse inmanejable y en cualquier caso no es muy elegante, al menos superficialmente (aunque siempre pueden usarse llamadas de tipo POST para ocultarlos)

lunes, 12 de septiembre de 2011

Abracadabra: componiendo criterios de hibernate en grails.

"Como decíamos ayer..."  Fray Luis de León, Miguel de Unamuno et alii
En la ultima aplicación que estoy escribiendo en el trabajo he tenido la suerte de usar grails como plataforma de desarrollo. Pese a todos los problemas que nos encontramos, casi todos originados en ser una tecnología relatívamente joven y que esta en continuo desarrollo, ha supuesto para nosotros un salto en el tiempo de ocho años. Hasta ahora estábamos usando la JDK 1.4, J2EE 1.4, struts 1 y persistencia manual en java y SQL, con lo que el cambio ha sido cualitativo.

En mis primerizos intentos de conseguir que el código sea reutilizable y evitar su duplicación no siempre he encontrado facilidades en la librería, o, lo mas seguro, no he sabido usarla de la forma correcta.

Uno de los puntos donde he encontrado dificultad ha sido a la hora de separar en elementos manejables las closures estáticas que contienen llamadas a métodos que forman un minilenguaje (o DSL) en si mismos. Estos métodos normalmente no existen en el contexto sintáctico donde están esas closures sino que pertenecen a algún otro objeto (normalmente un "builder"), aunque puede también usar las variables y métodos definidos en su ambito sintactico. En algún momento la librería "introduce" a la closure dentro del contexto del builder (por ejemplo con with) con lo que los métodos ya tienen sentido, la closure esta totalmente cerrada y puede ser ejecutada. Un ejemplo, usado en grails, es el uso de las Criteria de hibernate para definir consultas sobre entidades en la base de datos:


No tiene mala pinta pero una vez que te pones a usarlas te encuentras algunas limitaciones, una de ellas es que no puedes componer facilmente las closures para poder separar los diferentes criterios y hacerlos genéricos para no repetirlos una y otra vez. Si usas directamente el api de Criteria puedes componer los criterios creando instancias de los mismo y añadirlos a la instancia misma de la Criteria. Sin embargo en la solución de grails esto no es posible ya que aunque es mas breve y expresiva no expone los métodos para añadir dinámicamente criterios (o al menos no he encontrado la manera de hacerlo). Mi objetivo final era conseguir algo así:


O sea poder componer la closure final con closures mas pequeñas y manejables. También quería conseguir poder parametrizarlas tanto con datos externos como con los valores de la instancia en la que están definidas, consiguiendo un filtro que usa los campos de la instancia sobre la que es llamada como datos de ejemplo para realizar la consulta. En mi caso los métodos genéricos que encapsulan los criterios están en la superclase:



Solamente se añade el filtro de cada propiedad si esta informado y el carácter del filtro es lo mas abierto posible, usando "ilike" en los campos de cadena, "in" en los campos que definen relaciones uno a muchos con otras entidades, etc. También quiero subrayar que las entidades "maestras" se recuperan de forma recursiva, reutilizando el filtro definido en su clase correspondiente.

La pieza que falta para completar el puzzle es el operador ">>>" que se esta utilizando en el código para combinar las closures. Este operador no existe como tal en la versión actual de groovy. De hecho hace relativamente poco que en groovy (en la versión 1.8) se han añadido operaciones y métodos funcionales que actúan sobre las closures, tales como su aplicacion parcial y su composición. Supongo que la reciente recuperación del paradigma funcional (con lenguajes como Clojure, Scala o Haskell) ha favorecido que finalmente estén disponibles. En mi caso todavía estoy usando la versión 1.7 y tenia que añadir la operación de composición. Sin embargo al copiarla de la versión actual la cosa no marchaba. Lo vemos en este ejemplo que simula el comportamiento del builder de grails y la composición oficial de la versión 1.8:


Como se puede comprobar en la consola de groovy se produce un error ya que al componer ambas closures no se propaga el contexto de ejecución de la closure resultante a las closures que la componen, por lo que groovy busca los métodos "eq" e "in" en el contexto mas amplio que es el script mismo donde estamos escribiendo el código. Al no encontrarlo en ningún nivel nos devuelve el consabido error.

La closure se liga al contexto de un objeto usando la propiedad delegate de la misma. Para poder conseguir la ligazón tuve que implementar un método de composición que propagara esa propiedad de la closure resultante a las que están siendo compuestas:


Como se puede observar en el código "simplemente" se crea una nueva closure que llama a las dos que están siendo compuestas, a las que previamente les ha asignado su propio delegate para introducirlas en el contexto de computación. La implementación no esta muy cuidada y tal vez tenga errores, vamos, que no hay garantías.

La verdad es que no acabo de sentirme cómodo con la solución a la que he llegado, aunque en el camino he aprendido algo del funcionamiento interno de las closures, me parece que es demasiado enrevesada para lo que quería conseguir. En principio soy contrario al monkey patching más aun si se hace sobre clases básicas y al uso de la sobrecarga de operaciones. Seguramente se puede hacer de una manera más sencilla, aunque no la he encontrado. Como siempre vuestros comentarios tal vez puedan arrojar un poco mas de luz sobre el asunto.

Hasta mañana.

jueves, 9 de diciembre de 2010

Primeros pasos con Clojure

La documentación de Clojure igual no es la mejor del mundo. En un lenguaje joven y mucha información esta repartida entre los blogs de los cada vez mas numerosos entusiastas del lenguaje. Sin embargo se ha dado un paso mas para que los principiantes tengan un referente principal a la hora de instalar y configurar Clojure de una forma sencilla. Todo ello gracias a la labor de Stuart Halloway, autor de un interesante blog y del primer libro sobre Clojure: Programming Clojure.

La pagina principal de la wiki es esta. En ella hay una lista de enlaces a concisos tutoriales sobre las posibles formas de instalar y usar Clojure, según el IDE o editor que mas rabia nos de:
Como veis hay donde elegir. También tanto Stuart Halloway como el creador de Clojure, Rich Hickey han publicado un proyecto base pensado para aprender e iniciarse en Clojure con lo todo lo necesario: labrepl.

ACTUALIZACION

Afortunadamente los recursos para iniciarse con clojure crecen dia a dia. Entre los mas interesantes que han aparecido despues de este post estan los siguientes:
  • Una repl interactiva online done probar clojure sin instalar nada: try-clojure
  • Un pagina excelente para practicar clojure, con problemas de diferentes dificultad y la posibilidad de competir por escribir el codigo mas breve: 4clojure.
  • Una forma que se ha puesto de moda ultimamente es aprender los principios de un lenguaje con los koans, en esta pagina te guian como empezar con ellos con ruby, javascript y como no clojure.
  • Una pagina en las que se intenta centralizar todos los recursos utiles para aprender cojure, desde como instalarlo a listas de tutoriales, libros, etc. Imprescindible si quieres aprender el lenguaje: learn-clojure.com
  • Recursos en la web con documentacion y ejemplos acerca de Clojure: clojuredocs.org y clojure-examples.appspot.com
  • Una guia rapida de las funciones del nucleo de clojure.
  • Tutoriales acerca de como instalar y dar los primeros pasos en clojure: clojure-notes.rubylearning.org y si eres valiente, tienes un mac o linux y ganas de pegarte con las cosas how-to-setup-clojure-from-scratch, si tienes un ubuntu tambien hay un post especifico

domingo, 21 de noviembre de 2010

Pruebo, luego programo.

He tenido la suerte de poder participar en el code retreat que se celebro el Sábado en Donosti. ¿Que es un code retreat? Pues es una reunión de programadores que ejercitan sus conocimientos y aprenden y mejoran con ese ejercicio y con su puesta en común entre todos. Una buena forma de aprendizaje a través de la practica y la colaboración. Pero no solo esto, otro de los objetivos es replantearse los propios conocimientos y practicas y para ello la dinámica estaba orientada:
  1. Los ejercicios se llevan a cabo en parejas, para potenciar la programación colaborativa.
  2. El problema a resolver o representar en código es el mismo para todos y cada intento de hacerlo duraba estrictamente 45 minutos (osease un pomodoro). En nuestro caso el problema a resolver fue el juego de la vida de Conway. Aunque el objetivo real no era resolver el problema por supuesto.
  3. Después de cada sesión había que borrar todo el código escrito antes de compartir entre todos la experiencia.
  4. Como principio general se estableció el desarrollo guiado por las pruebas.
  5. Aparte se pusieron restricciones sorpresa para evitar entrar de ninguna manera en una rutina.
Todo ello para conseguir una nueva visión de la programación y para romper los esquemas, el bagaje que muchas veces te hace ser mas rígido y te impide aprender y avanzar. Y para conseguirlo de forma radical es necesario medidas radicales.
Por supuesto contar con un maestro de ceremonias adecuado es casi imprescindible y Enrique lo hizo a la perfección compartiendo sus valiosos conocimientos de forma totalmente desinteresada. El acto no pudo haber existido sin el tiempo y el esfuerzo de los organizadores y de los patrocinadores. Desde aquí mi reconocimiento a su generosidad. Finalmente pero no menos importante también hay que reconocer el papel de todos los asistentes al acto ya que entre todos ayudamos un poco a que fuera un éxito.
Nunca había practicado ninguna de las técnicas que he descrito y solo tenia cierto conocimiento teórico de lo que había podido leer en blogs y artículos. Un conocimiento totalmente inútil y que intente olvidar para limpiar la mente de prejuicios.
El objetivo claro fue hacernos mejores programadores o sea que nuestro código fuera mas elegante, mas simple, mas fiable y mantenible. La prueba desde ese punto de vista pierde su valor como elemento externo al programa, muchas veces escrito a posteriori y se convierte en el medio para alejarnos del código real y mirarlo desde fuera incluso cuando aun esta en nuestra mente luchando por salir y apoderarse de nuestros dedos. La prueba nos aleja de el para mirarlo con ojos nuevos y sospechosos.

Sí, nuestro código siempre es sospechoso.

A la vez la prueba nos hace seguir pegados al objetivo y al propósito del código todavía no escrito y no nos separa totalmente de lo que es la programación ya que es en si misma código. Esa es su ventaja y su inconveniente ya que hay otras maneras de alejarnos del código: haciendo dibujos o simplemente no haciendo otra cosa que pensar en el. La desventaja de la prueba es que sigue siendo código en el que podemos regodearnos, dándole mas importancia de la debida y que puede acabar siendo tan imperfecto o mas que el código real que todavía no hemos escrito (y que puede acabar siendo empobrecido por la prueba y no al revés).

Sí, se corre el riesgo de escribir dos veces un código mal hecho. Nadie dijo que la tdd fuera mágica.

Aprendizajes y collejas varias

Para evitarlo Enrique nos daba collejas virtuales, tanto en mitad de los ejercicios como en las retrospectivas posteriores para sacarnos de nuestros raíles, viejos o los que íbamos creando en el momento. Borrar el código antes de hablar de el, tener que consensuar los nombres y el siguiente paso a seguir, cortar el ejercicio justo cuando la cosa empezaba a calentarse. Todo orientado a alejarnos del código y volverlo a mirar con otros ojos.
La prueba bien hecha no se deja arrastrar por el código todavía no escrito que pulula en nuestra cabeza, lo domina y lo encierra y le obliga a seguirla:
  • Le debe obligar a ser mas simple: para ello Enrique nos obligo a escribir todo el código necesario dentro de la prueba y solo darle entidad propia en cuanto detectaramos repeticiones reales en las pruebas. En otro momento nos obligo a que las funciones o métodos no fueran de mas de cuatro lineas.
  • Debe usar los nombres mas "adecuados" (totalmente autodescriptivos,no ambiguos, lo mas cortos posible) a la lógica de negocio y al problema que va a resolver. En cada retrospectiva Enrique incidía y cuestionaba los bautizos que hacíamos.
  • Le debe dar justo la responsabilidad que necesita para hacer bien su trabajo sin dependencias innecesarias y lo mas alejadas de la implementaciones concretas. El mismo hecho de hacer la prueba te conduce a ello ya que probar un fragmento de código es mas difícil y costoso cuanto mas dependencias externas tienes que manejar en la prueba (uso de mocks e inicializaciones costosas). Enrique nos prevenía de la implementación concreta que luchaba por salir de nuestros dedos y que amenazaba con encerrar y anclar nuestro diseño antes de tiempo.
  • La prueba debe contagiar al código de su carácter declarativo, para lo que obviamente debe ser ella misma lo mas declarativa posible. Enrique nos prohibió usar números en las pruebas para intentar hacernos ver que la mejor forma de que la prueba nos dijera lo que quería es darle un nombre que lo expresara de forma totalmente descriptiva. No lo consiguió y tuvo que borrar nuestro código (otra colleja) y señalarnos con el dedo (y aun asi nos costo asumirlo). Cuando vimos: public class TestCelulaCuandoEstaViva { public void muereCuandoTieneMenosDeDosVecinos () {assert(true)}} el código lleno de ifs, operadores de comparación y números que habíamos guardado celosamente en nuestras cabezas y que guiaba secretamente nuestras pruebas murió un poco mas. Tell, dont ask, my friend.
  • Debemos poder hacer las pruebas tanto desde arriba hacia abajo como al revés y elegir el camino adecuado en cada momento (o combinarlos, primero hacia abajo y luego de vuelta como nos mostró Enrique). La elección debe ser cuidadosa y debe tener en cuenta el dominio, las herramientas, el lenguaje con el contamos, etc.
Un tesoro nos llevamos de Donosti, seguro que hubo mas enseñanzas que se me han olvidado o que ni siquiera capte pero estoy contento. Pero, espera un momento, yo ya conocía todos esos preciosos principios y buenas practicas en teoría e incluso intento con mayor o menor éxito aplicarlos en mi código. Geniales programadores los llevan a la practica todos los días sin hacer un test. Se alejaran del código y como paso previo pensaran en el teniendo en cuenta todas estos principios y algunos mas. Incluso estoy seguro que el primer código que piense gente como Enrique ya sera cristalino (al menos comparado con el mio).
Como otra opción para los programadores de a pie queda el hacer prototipos del código y repensarlo y reescribirlo las veces que haga falta. Equivocarse una y otra vez y aprender de los errores.

Entonces, ¿para que las pruebas?

Buena pregunta ya que, en mi opinión, no hay que aceptar las metodologías sin mas ya que también son sospechosas (igual que lo es el código). Igual me perdí algo en el code retreat que eliminara todo mi escepticismo. Dejare a mis comentaristas la oportunidad de contestar aunque puedo adelantar que en primer lugar aparece el valor original de la prueba que hasta ahora habíamos obviado: monitorizar el código de forma automática y aumentar nuestra confianza en el, describir y documentar los casos de uso y la lógica de negocio. El hacer la prueba primero tiene la consecuencia obvia de que seguro que la haces. Por otro lado te obliga de forma metódica a pensar en el código antes de escribirlo (cosa que no suele hacerse siempre a no ser que tengas una gran disciplina) Seguro que se os ocurren mas ventajas.

Clojure y el TDD

Por supuesto fui con mis paréntesis a la sesión con un poco de miedo que provocaran urticaria y dispuesto a amoldarme a cualquier lenguaje sobre todo desconocido para mi como oportunidad para aprender. Debí haber previsto que todos venían dispuestos a aprender sin prejuicios y no les importo o incluso estuvieron encantados (¡cuando @jmbeas empezó a recordar sus tiempos de emacs y common lisp tuve que seguirle yo a el!) de usar clojure para los ejercicios, @kinisoftware también acepto sin problema hacerlo en clojure a la vez que me guiaba por mis primeros balbuceos en los tests. Eso tal vez sesgo un poco el objetivo principal pero creo que pude mostrar unas pinceladas del lenguaje sin olvidarnos del todo de el.
Hay gente que cuestiona la pertinencia de la TDD en un lenguaje funcional como Clojure, pero dentro de la comunidad también hay opiniones contrarias y al menos el testing tiene su lugar ya en el mismo núcleo del lenguaje. Aparte hay varias librerías magnificas para ponerlo en practica. Personalmente creo que aunque no tiene el mismo significado o importancia en un lenguaje orientado a objetos y dinámico (en el que casi es una locura programar sin hacer tdd) que en uno funcional y que promociona la inmutabilidad y evita el estado, si que cumple su papel. No hay mejor referencia que los posts que ha escrito @unclebob sobre clojure y tdd o los de @marick.
Fue curioso como la orientación de objetos fue, en mi opinión, mas un estorbo que una ayuda para las sesiones. Los objetos (todos con mayúsculas Célula, Tablero, Juego,Dios) que modelaban el problema, sus relaciones y sus responsabilidades rondaban la cabeza de los asistentes y creo que tiraban de los tests anclandolos y no dejandolos fluir. En mi caso era las estructura de datos simples la que me rondaban y las funciones para transformarlas (vectores, mapas) pero creo que esa diferencia iba a mi favor pues con elementos tan simples y genéricos (que hay mas abstracto,generico, componible y simple que una funcion o un mapa) no necesitas crear abstracciones a posteriori ni mocks para aislar los tests del diseño e implementación concreto. ¡¡¡Corregirme si me equivoco!!!

martes, 28 de septiembre de 2010

Scala vs y Clojure (Round 1)

Un lenguaje escalable: tanta complejidad como necesites.


Una ventaja de que por la península vayamos retrasados en esto de lo tecnológico es que sea mas difícil que un post como este pueda iniciar un guerra. Pero por si acaso quiero aclarar que aunque mi lenguaje preferido en la intimidad sea Clojure, también aprecio Scala, al menos en lo que ha acercado a la JVM elementos de lenguajes como Haskell y la familia de los ML.
Ambos lenguajes comparten ciertos aspectos pero difieren lo suficiente como para no ser excluyentes dentro de los nuevos lenguajes funcionales que corren sobre la JVM. El mismo creador de Scala, Martin Odersky defendía esta postura en esta entrevista: para que "gane" uno de ellos no tiene porque perder el otro.
Y la diferencia fundamental esta en las razones que ambos surgieran y en su misma filosofía, antes incluso de las diferencias técnica. Esa diferencia se traduce también en sus respectivas comunidades, en lo que te exige como programador y aprendiz y en lo te puede dar.
En general estoy convencido que un lenguaje no es absolutamente mejor a cualquier otro sino mejor o mas adecuado a un contexto determinado, incluido java o cobol.

Scala desde sus orígenes ha querido ser "un mejor java", algo así como un java++. Y aunque ultimamente no es la imagen mas popular, efectivamente lo es. Eso supone que desde su creación se ha caracterizado por tener una sintaxis similar a la de java y unas construcciones parecidas pero mejoradas en cuanto a ser orientado a objetos de una forma mas consistente y expresiva que java. Incluso ha integrado en el lenguaje varios de los patrones de diseño que ya se han establecido casi como norma en java, de una forma sencilla y expresiva.

Como ejemplo podemos echarle un vistazo a este código que declara una típica clase de una aplicación empresarial:



No tiene nada de mala pinta para un programador en java que se acerca al lenguaje.

Por otro lado desde el origen Scala ha tomado como ejemplos lenguajes populares en el ámbito universitario de la "ciencia computacional": Ocaml y Haskell. Tal vez tenga algo que ver que tanto Odersky como Scala están fuertemente asociados a la Escuela Politécnica de Lausanne. Estos lenguajes (incluido el mismo Scala) están en la vanguardia de la investigación en los lenguajes de programación lo que ahora mismo es equivalente a decir que profundizan en el paradigma funcional unido a sistemas de tipado basados en su inferencia. Abstracciones como las Monadas o los Funtores son poderosas y atractivas intelectualmente, incluso tienen su aplicación real aunque tal vez no sea evidente a primera vista. Sin embargo su uso en Scala requiere cierta formación teórica y un conocimiento mas profundo de su sintaxis. Un código es Scala que hace un uso intensivo de estos elementos puede parecer tal que así:



Viendo este código el mismo programador que antes asentía pondrá los ojos en blanco.

Scala es un híbrido y su filosofía es darle todas las opciones posibles al programador aunque suponga hacer el lenguaje mas grande y complejo. Puedes programar orientado a objetos de forma imperativa o funcional, usando datos inmutables o no, usar la evaluación perezosa o no. Es por esto que lo han comparado a c++ ya que parece que también este lenguaje nació un poco con esa filosofía. Odersky tuvo que defender a su lenguaje de esa fama de complejo pero sin negar que lo fuera, sino defendiendo esa complejidad interna y la "escabilidad" del lenguaje, ya que cada uno puede usar Scala a su manera en cada momento y solo usar la parte mas compleja cuando se necesite construcciones mas poderosas. También es verdad que el mismo hecho de aglutinar paradigmas y opciones tan diferentes y el ser "escalable" y flexible añade su propia dosis de complejidad en el computo global sea el uso que sea el que le quieras dar.

El problema de muchos programadores provenientes de java con Scala me parece que es que llegan enganchados al cebo de su sintaxis y semántica básica parecida y su ligera curva de aprendizaje inicial pero cuando quieren dar un paso mas allá y usar las partes mas avanzadas el nivel de exigencia y de dificultad aumenta de forma exponencial, al menos en una segunda fase. Después de todo si te has cambiado de lenguaje es porque se quería usar algo diferente. Hay que ser pacientes y usar poco a poco esas características si no se tiene experiencia anterior o un solida base teórica en lenguajes funcionales tipados. Esa frustación aparece como una de las causas que Scala no se haya hecho mas popular, y se haya agravada por el hecho de que los miembros mas influyentes de su comunidad escriban sobre el lenguaje desde el punto de vista de su parte funcional y sobre el uso mas sofisticado de su sistema de tipado y que establecen casi de facto que ese uso del lenguaje es el estándar.

Según mi forma de ver Scala puede ser un lenguaje apropiado para entornos de programadores java con ganas de aprender pero que quieren empezar con una sintaxis y unas construcciones cercanas y añadir progresivamente elementos mas poderosos cogidos del paradigma funcional. También es una buena opción si se quiere un lenguaje que te permite usar un sistema de tipado estático sofisticado y que gracias a su inferencia te ahorra el tener que escribir muchas de las anotaciones de tipos. La gente que no se encuentren cómodos con los lenguajes dinámicos y echen de menos la velocidad de ejecución que te proporcionan los tipos (Scala es al menos tan rápido como java puro) o la posibilidad de validar/documentar tu programa de forma logica con los tipos, valoraran mas el sistema de tipado de Scala. Mas todavía si tenemos en cuenta que este sistema es mas flexible, rico y breve en código que el de java.

Clojure parte desde un punto de vista totalmente diferente que veremos en la entrada siguiente del blog, pero podemos adelantar que aunque la sintaxis sea totalmente ajena a los lenguajes derivados de Algol (c,c++,java,Scala,etc,etc) y suponga para muchos un handicap inicial casi insalvable en realidad es mucho mas sencillo que Scala, tanto en la sintaxis como en la semántica al centrarse y casi obligar a adoptar desde un principio a las característica funcionales casi puras: inmutabilidad de los datos, separación entre estos y los algoritmos que los tratan, evaluación perezosa, separación entre el valor (inmutable) de un dato y las referencias que nos permiten modificarlo en el tiempo de forma segura en lo que respecta a la concurrencia, etc. La curva de aprendizaje es inversa a la de Scala, muy empinada al principio pero mas leve en cuanto se ha comprendido los principios fundamentales del paradigma funcional y se ha acostumbrado uno a los benditos paréntesis. Pero no hay marcha atras una vez que entras en los paréntesis, mmm, ¿o tal vez sí?

((TO BE CONTINUED))

lunes, 14 de junio de 2010

Clojure por las nubes (Google AppEngine)

Uno de los campos donde se mas se mueven los programadores en Clojure es en el de la programación web en la "nube". En concreto la alternativa que ofrece google es bastante popular desde que soporta aplicaciones en java y cualquier lenguaje que pueda ser compilado para la jvm.

La ventaja esta clara, no hay que preocuparse acerca de los recursos de computación necesarios para que tu aplicación funcione, ni anchos de banda, ni cpu o espacio en disco. Puedes desplegar una aplicación de forma gratuita y pagar justo por el espacio de disco, memoria ram y ciclos de cpu que uses a medida que tu aplicación crece. Vamos como si fuera la factura de la luz.

También tiene su lado malo, la aplicación tiene que ajustarse a las limitaciones sobre las librerias estandar de java y usar las librerias propias de la AppEngine para operaciones básicas asi como la base de datos que ellos te proporcionan. Ademas el kit de desarrollo necesario para desarrollar tu aplicacion no tiene el codigo abierto. Hay que modificar o programar la aplicación para hacerla dependiente de la plataforma.

En todo caso es una opción bastante atractiva para aplicaciones de prueba e investigación.


Entre las referencias que pululan por la red la mas atractiva es las de una empresa autogestionada por un grupo de "hackers" amantes del lisp, que han usado Clojure para programar y Google AppEngine para publicar una interesante aplicacion de gestion de "tareas pendientes" orientado a programadores, con ciertos elementos de inteligencia artificial para ayudar a priorizar las tareas y estimar los tiempos que tardaremos en completarlas. La aplicación esta en http://the-deadline.appspot.com

En este video la banda nos explica las razones de usar Clojure y GAE:



En su blog ha varios posts que no hay que perderse sobre aspectos técnicos del desarrollo con Clojure y GAE. El que escribe también ha subido el "hello world" de la GAE, un libro de visitas básico (aqui el codigo) que combina un servlet en java cogido de la aplicación de demostración que viene con el kit de desarrollo y un "servlet" en clojure usando Compojure como framework web y otras librerias de ayuda para el desarrollo en la GAE.

Asi que si quieres programar en Clojure y ver tu aplicacion por las nubes de forma relativamente sencilla esta puede ser tu opción.