Archivo de la categoría: Programación

Charla en MadridJUG/Madrid GUG sobre tipos algebraicos en Java 21

El pasado 24 de octubre dí una charla sobre el soporte completo que se ha dado en Java 21 a los tipos algebraicos. Estuvo muy bien, sobre todo por el debate que se estableció durante la charla y en el networking posterior.

Diapositivas presentación: Tipos algebraicos en Java 21

El repositorio de código:

  https://github.com/logicaalternativa/algebraictypes

y también el video del directo de la charla

Charla Commit Conf 2023 sobre programación funcional y patrones funcionales

El pasado 21 de abril di una charla sobre programación reactiva y como tener conocimiento de los patrones funcionales pueden ayudar a entender mejor este tipo de programación.

En la charla también introduzco el concepto de DSL (Domain Specific Language) que permiten de una manera real abstraer nuestro código de la tecnología escogida.

En otro orden de cosas, para mí fue un honor que la organización del Commit Conf confiara en mí para ser ponente.

Aquí están las diapositivas de la presentación

Presentación Commit Conf 2023Diapositivas presentación: Programación reactiva y patrones funcionales

y el vídeo de la charla

Vídeo y diapositivas de la charla de Commit Conf

Los días 23 y 24 de noviembre ha tenido lugar en Madrid la primera edición del Commit Conf, uno de los eventos más importantes que se tiene en lengua castellana.

En su momento presente mi charla sobre Akka Sharding y su relación con DDD al “call for papers” con ilusión pero sin grandes esperanzas de que fuera aceptada. Hay que tener en cuenta que hasta ese momento no tenía experiencia presentando charlas en eventos públicos aunque afortunadamente si que tengo cierto callo en exponer ideas en público ya que mi trabajo me lo exige.

Así que cuando me aceptaron la presentación me lleve una enorme alegría porque consideraron el tema de mi charla interesante. Alegría, pero también responsabilidad por toda la confianza depositada.

Recuerdo con una sonrisa la primera presentación que hice a  a tres compañeros de trabajo que me hicieron de beta testers. Para mi alivio les resultó interesante y fue curioso, porque cada uno tenía una visión diferente de lo que le había gustado de la presentación. Uno se decantó más por las posibilidades que ofrecía este paradigma, otro puso más interés como se implementaba y el otro las implicaciones operacionales que tenía el despliegue de un sistema distribuido. El problema fue el tiempo: se fue más de hora y media.

Luego he tenido la increíble oportunidad de presentar la charla en otros foros como puede ser en el ScalaMAD (el 31 de octubre) a los que estoy agradecido y que me permitió pulir la charla.

Al final creo que la presentación en el Commit fue bastante bien, aunque recortada estuvo un poco justa de tiempo, … me faltaron unos minutos, un problema endémico por intentar tener en cuenta todos los conceptos, pero si que la gente se mostró participativa en la tanda de preguntas lo cual es muy bueno.

En resumen la sensación fue muy positiva, una experiencia intensa pero muy bonita de la que guardaré un buen recuerdo. Para terminar, lo prometido, estos son el vídeo y los enlaces de la charla y el repositorio del github de los notebook de Jupiter con la demo.

Presentación: Akka Sharind y su relación con DDD

Código: Repo GitHub

Futuros y promesas,… y también monadas. Implementando el patrón

«Los modelos NIO no bloqueantes y la programación asíncrona y reactiva son paradigmas que poco a poco van adoptándose y utilizando más

Los modelos NIO no bloqueantes y la programación asíncrona y reactiva son paradigmas que poco a poco van adoptándose y utilizando más. No creo que diga una tontería al afirmar que muy probablemente serán la norma en un futuro cercano. La razón es clara: aunque no se obtiene un rendimiento mejor que los modelos tradicionales sincrónicos, si son modelos mucho más eficientes. Obtienen el mismo rendimiento con menos recursos al tener un mejor control de los hilos, uno de los recursos más preciados en un sistema operativo.

Futuros y promesas

Futuros y promesas

Para poder articular una programación asíncrona y reactiva es necesario utilizar patrones adaptados a este tipo de programación. Puedes utilizar el patrón observable o las señales,  pero casi podríamos decir que tu camino te llevará irremisiblemente al patrón futuro en cuando tienes que integrar varios resultados asíncronos. Si además nuestra implementación del patrón futuros-promesas cumple con las propiedades de las monadas se nos abre un mudo de posibilidades. Con la programación funcional, la composición de futuros se podrá hacer de una manera elegante obteniendo un código más legible.

Esto permite realizar DSL’s (Domain Specific Language) y separar la lógica de negocio de los efectos de lado. Por ahora “… ahí lo dejo”; prefiero no perder foco en el objetivo de este artículo, pero en mi mente esta tratar todo esto en una nueva reseña. En este artículo entraré a desarrollar todos estos nuevos conceptos intentando desmitificarlos, porque al principio todo lo de “Futuros”, “Promesas” y “Mónadas” puede que suene “muy místico”. Lo haré apoyado en mi propia implementación del patrón Futuros y promesas que está disponible en mi GitHub.

[Logo GitHub] AlternativeFuture

La implementación está basada “fuertemente” en el Api de Scala de futuros y sólo recordar que Akka en su versión de Java la exporta directamente y que además los futuros de Scala son también monadas. Cuando digo que me apoyo en el Api de Scala me refiero a seguir la definición de su contrato, de hecho, no me interesaba el código fuente y si hacer el ejercicio de, a partir de su interfaz, realizar mi propia implementación en Java. El código que podéis ver y utilizar es todo mio. Hecha esta aclaración es el momento de empezar a entrar en faena.

Intentaré hacer un acercamiento de dentro a fuera. Primero pondré el foco en las ideas principales para ir después abriendo el zoom y conseguir tener la imagen completa.

Futuros

«¿Qué es un futuro?» Pongámonos en contexto. Imaginemos dos procesos: uno será el principal que llamará a un método que devuelve un futuro de un valor. El otro será el que calcule realmente el valor de manera asíncrona ejecutado en un segundo plano con respecto al principal. Voy a poner un ejemplo para hacerlo más didáctico. Ana (el hilo A, el principal) le dice a Bartolo (el hilo B) que haga la colada (llamada al método)

Llamada asíncrona

1. Llamada asíncrona

El proceso principal obtiene un futuro como resultado de llamar a un método que se lanzará en segundo plano gracias al hilo B. En el ejemplo Bartolo manda una nota (representa el futuro) a Ana que le permitirá apuntar lo  que se quiere que se haga con la colada cuando haya terminado Bartolo. El hilo A no queda a la espera del resultado de la acción ejecutada por el hilo B y queda liberado para realizar otras operaciones. En el ejemplo Ana no espera a que Bartolo termine y  puede seguir haciendo otras tareas.

2. Se devuelve un futuro

2. Se devuelve un futuro

Este futuro es en realidad un artefacto que permite asignar, desde el proceso principal una función callback. En el siguiente paso, Ana decidirá que es lo que quiere hacer cuando termine la colada, es decir, asignará la función callback que se ejecutará cuando se obtenga el resultado del segundo proceso ejecutado por Bartolo.

Asignar callback

3. Asignar callback

Cuando, gracias al segundo proceso, se haya calculado finalmente el valor, se ejecutará la función de regreso al que se le pasará como argumento el valor final obtenido. En el ejemplo tenemos la función «planchar la ropa» y el resultado del proceso: «la ropa lavada».

Resultado del futuro

4. Resultado del futuro

Contextos de ejecución

La ejecución de las funciones callback con el valor final como argumento se hará dentro de lo que se llama un contexto de ejecución. Este no es más que un pool de hilos que permite independizar la ejecución de la función con el valor final tanto del hilo principal como del segundo proceso, es decir, se ejecutarán en un tercer hilo “reutilizable”. En el ejemplo que estamos siguiendo es Carlos (el hilo C) el que plancha la  ropa.

Ejecución de la función callback con el valor del futuro

Ejecución de la función callback con el valor del futuro

En la implementación del patrón que he propuesto a cada una de las funciones callback y de orden superior definidas en el interfaz futuro se le puede pasar un contexto de ejecución.

Más cosas de los futuros

A grandes rasgos, esta es la esencia: el futuro permite configurar desde la ejecución principal que hacer cuando finalmente exista el valor. Y se hace sin tener que bloquear hilos porque sino arruinamos la asincronía.

Teniendo esto en mente y sin perder de vista lo simple de este concepto, base de todo, voy a ir añadiendo nuevos conceptos e ideas que nos permitirá ir completando la visión general del patrón.

Dos caminos

Añadiendo una nueva capa a las funciones callback. El resultado de la ejecución de cualquier método puede ser, o bien su valor, o bien que su ejecución se haya saldado con un error, luego el resultado final que contiene un futuro puede ser:

  • un valor correcto
  • o también una excepción.

¿Por qué no contemplar esta circunstancia con dos caminos? Un camino para cuando el valor sea correcto con su correspondiente función callback (el método onSuccess) y otro que nos permita definir otra función de regreso cuando se produzca un error (el método onFailure)


Signatura de un onSuccess y onFailure de AlternativeFuture[T]:

onSuccess

void onSuccesful( final Consumer<T> function, final Executor executor );

El argumento function es una función cuyo argumento es de tipo T (es el tipo del valor final del futuro) y resultado void.

function: T => void

Esta será la función que se ejecutaría cuando de resultado final del futuro ha ido bien.

onFailure

void onFailure ( final Consumer<Throwable> function, final Executor executor );

En este caso el argumento function es una función cuyo argumento es un Throwable (la excepción que se reportaría si se produciría un error) y resultado void.

function: Throwable => void

Está será la función que se ejecutará cuando el futuro se haya solventado con un error.


¿Cuando se ejecuta la función callback?

Para dar respuesta a esta pregunta nos debemos fijar en que existan las dos cosas necesarias para la ejecución de la función: que exista la función y que exista el valor. Hay entonces dos posibilidades:

  • Puede que ya haya asignada una o varias funciones callback al futuro, entonces la ejecución de las mismas será cuando se obtenga el valor.
  • O bien puede ser que se obtenga primero el valor y el disparador de que la función se ejecute será la propia asignación de la función callback.

Es importante tener en mente que un futuro (“barra” promesa, esto lo explicaré más adelante), sólo se le puede asignar el valor una vez, además otra característica es que una función callback sólo se ejecutará una vez. Sin embargo se puede asignar al futuro, a lo largo del tiempo, todas las funciones callback que se deseen.

Promesas

Si has llegado hasta aquí probablemente ya te habrá asaltado la duda: ¿Cómo se da valor al futuro? ¿Cómo se le asigna un valor? La respuesta: a través de la promesa.

Podemos decir que la promesa y el futuro son las dos caras de la misma moneda y que una promesa está relacionada con un futuro. La idea básica que debemos tener en mente es la siguiente:

  • el futuro permite asignar la función callback para tomar decisiones una vez se haya obtenido el valor
  • la promesa permite dar valor a ese futuro.

Si volvemos al ejemplo anterior, será más sencillo de entender. Si recordamos el proceso principal llamaba a un método que permite en un segundo proceso calcular un valor de manera asíncrona en un tiempo indeterminado (puede ser antes o después). Mientras que el proceso principal tiene como herramienta al interfaz futuro que le permite indicar que es lo que se debe de hacer una vez se haya calculado el valor, el interfaz de la promesa será el instrumento que poseé  el segundo proceso encargado de calcular el valor para asignar el valor a ese futuro. En síntesis Ana usaría el futuro y Bartolo la promesa.

Diagrama de flujo Promesa-Futuro

Diagrama de flujo Promesa-Futuro

Diagrama de secuencia Promesa-Futuro

Diagrama de secuencia Promesa-Futuro


Implementación

Si echáis un vistazo al código, podéis observar que sólo existe una implementación que implementa las dos interfaces: la promesa y el futuro.

La clase AlternativePromiseImp tiene un atributo que permite almacenar el valor del futuro. Este se asignará gracias a los métodos que expone el interfaz promesa AlternativePromise.

Existen dos atributos más en AlternativePromiseImp que son del tipo de cola FIFO (el primero que entra será el primero que sale). Permiten almacenar las funciones callback gracias a los métodos expuestos por el interfaz AlternativeFuture.

Una de las colas guardará las funciones que se van a ejecutar cuando mediante la promesa relacionada se asigne un valor correcto al futuro. Las funciones se van añadiendo a esta cola utilizando el método ‘onSuccesful‘ del interfaz AlternativeFuture.

La otra cola FIFO almacenará las funciones callback que se ejecutarán cuando la promesa relacionada se resuelva con un error. De la misma manera, se van añadiendo estas las funciones gracias al método ‘onFailure‘ del interfaz AlternativeFuture.

Bien cuando se asigna un valor a la promesa o bien cuando se añade una función callback al futuro se comprueba que existan los requisitos necesarios (la función y el valor del futuro). Si es así se ejecutará las funciones callback incluidas en la cola de callbacks con el valor final. Según se vayan ejecutando las funciones se eliminarán de la cola.


El Futuro como mónada. Programación funcional con AlternativeFuture

Se puede dar una vuelta de tuerca más y seguir añadiendo capas a la cebolla. El patrón Futuro/promesa permite adoptar un nuevo patrón funcional: la monada. Este artículo ya es lo suficientemente extenso, quizás con ya demasiados conceptos así que dejo pospuesto introducir la composición mónadica con AlternativeFuture y os emplazo a un siguiente post continuación de este.

M.E.

Actores tipados, Akka por ejemplos

«Tercer y último artículo sobre Akka explicado mediante ejemplos.

En los dos anteriores se basó en como funcionan la cola de mensajes de un actor, que es un router, como se envían mensajes entre actores. Después se trató temas como la supervisión y el bus de eventos.

Ahora me centraré en los actores tipados.«

Entrada anterior: Akka por ejemplos. Sobre supervisión, bus de eventos, …

Todo el código fuente relacionado con esta serie de posts está disponible en mi repositorio de GitHub

[Logo GitHub] AkkaActorsAndFutures


Actores tipados

Los actores tipados son una funcionalidad que ofrece Akka recubriendo un actor no tipado en un interfaz java. Con un actor tipado el programador realiza llamadas a un método de una clase normal ‘sin preocuparse‘ (y pongo esto entre comillas por lo que veremos más adelante) de lo que está detrás es un actor de Akka.

[Actor tipado]

[Actor tipado]

Permite unir los dos mundos, código java estándar con el mundo de los actores. En la documentación de Akka puedes leer que tienen su nicho, pero hay que ‘usarlos con moderación‘. Recomiendan que si lo que buscas es una arquitectura de alta escalabilidad utilizar estos actores no es la solución más sencilla. Por ejemplo en este caso, aunque se puede, no es tan natural la supervisión y la monitorización padre-hijo.

Para los actores tipados, Akka utiliza el patrón de Objetos Activos y proxys de Java. Para levantar un actor tipado es necesario una interfaz y una implementación. Simplificando, en los actores tipados no existe el método ‘onReceive()‘ y se utilizan como un clase más de Java haciendo llamadas a los métodos que exporta la interfaz.

En realidad lo que hay detrás es un actor no tipado. Akka monta un proxy en el que el interfaz será la fachada y el ‘contrato público‘ que podrá utilizar el resto del código java. Los atributos de los métodos de ese interfaz serán los mensajes que se enviarán al actor y la implementación será la que dicte el comportamiento. Por lo demás se cumple con el modelo de actores que asegurá que no habrá más de un hilo ejecutando el actor.

Todo esto, que haya un actor detrás de este interfaz, hace que tenga un comportamiento diferente al esperado en una clase java, y hay que tenerlo en mente cuando se utilizan actores tipados.

Para los ejemplos se ha utilizado una clase TypedActorDummyImp que implementa el interfaz TypedActorDummy con una serie de métodos sencillos que permitirán ver con facilidad el funcionamiento de los actores tipados.

He creado dos test, uno TypedActorDummyImpTest.java que comprueba el comportamiento en una llamada normal a un método con diferentes tipos de retorno y otro TypedActorDummyImpExceptionsTest.java para ver cual será su comportamiento si se produce una excepción.

Comportamiento según el tipo de retorno.

Un método puede devolver tres tipos de respuesta: o bien es un método que no devuelve nada (void), o devuelve un objeto, o bien devuelve un futuro de objeto.

Cuando un método devuelve no devuelve nada: void

Cuando un actor tipado el tipo de respuesta es ‘void‘, lo que está ocurriendo es que se está mandando un mensaje del tipo dispara y olvida (‘fire-forget‘). En realidad se está enviado un mensaje ‘tell‘ al actor que hay por detrás, y no se espera respuesta.

Esto hace que tenga un comportamiento un poco ‘diferente‘ del esperado y es algo que se puede comprobar en los dos ejemplos.

Test 1: Llamada normal

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpTest#testReturnVoidWithSleep test

En este test se levanta un actor tipado que tiene un método que devuelve void. Se simula una operación costosa con un “Thread.sleep”.

Se comprueba que no se espera a la ejecución del método, sino que se continua inmediatamente con la siguiente orden. El mensaje se ha encolado al actor y este ejecutará la implementación en segundo plano, sin ningún tipo de espera en el hilo principal.

Test 2: Cuando se produce una excepción

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpExceptionsTest#testRuntimeExceptionVoid test

Como consecuencia de que el mensaje es enviado al actor, ejecutándose en un segundo plano, el hilo principal no es capaz de saber si ha ocurrido un error en la ejecución. Si se produce una excepción no será recogida desde la llamada al método.

El test anterior permite hacer esta comprobación y es bastante didáctico.

Cuando un método devuelve un futuro

Test 1: Llamada normal

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpTest#testFutureEcho test

Cuando se llama a un método de un actor tipado que devuelve un futuro, el comportamiento sería el mismo que si se enviara un mensaje de petición y respuesta no bloqueante. Es el equivalente al envío de un mensaje con ‘Patterns.ask(…)’ de un actor no tipado.

Por lo tanto la respuesta se recogerá cuando se resuelve el futuro y no desde la llamada al método. El hilo principal continuaría su ejecución sin esperar.

Test 2: Cuando se produce una excepción

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpExceptionsTest#testRuntimeExceptionFuture test

Lo mismo pasaría si se produjera una excepción, sería devuelta en la resolución del futuro y no sería recogida en la llamada al método tipado. Esto entra dentro de lo lógico si pensamos que cuando se produce el error es en el momento en el que se procesa el mensaje por parte del actor.

Cuando un método devuelve un objeto

Test 1: Llamada normal

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpTest#testEcho test

Test 2: Cuando se produce una excepción

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpExceptionsTest#testRuntimeExceptionString test

Cuando se llama a un método de un actor tipado que devuelve un objeto, el comportamiento es ‘parecido‘ al esperado. Y digo ‘parecido‘ porque en realidad lo que se está haciendo es enviando el mensaje al actor y esperando la respuesta (siguiendo un patrón de petición-respuesta bloqueante)

Por lo tanto desde la llamada al método de un actor tipado hace que hilo de ejecución principal espere la respuesta (aunque por detrás se esté enviando un mensaje ejecutándose en otro ‘hilo’). Por lo tanto el comportamiento es ‘el mismo’ al acostumbrado (ver el ejemplo 1). En este caso si se produce una excepción si será recogida en la llamada al método (Ver test 2)


Como conclusión final de esta serie de posts decir que aunque el modelo de actores y Akka presentan nuevos conceptos, estos una vez aprendidos son sencillos de asimilar.

A cambio ofrece un modo elegante y sencillo de codificar aplicaciones que soporten programación paralela  que sean escalables, robustas y  de alta disponibilidad.

Espero que os sirva.

M.E.

Akka por ejemplos. Sobre supervisión, bus de eventos, …

Esta es la segunda entrega de Akka por ejemplos. La primera trató sobre cual es el funcionamiento de la cola de mensajes de un actor, que es un router y como se envían mensajes entre actores.

Ahora se tratarán temas como el control de fallos y la supervisión de actores, el bus de eventos de Akka y sobre los ‘Dead Letters’

Entrada anterior: Akka por ejemplos

Sin más vamos con los ejemplos.

Todo el código fuente relacionado con esta serie de posts está disponible en mi repositorio de GitHub

[Logo GitHub] AkkaActorsAndFutures


Control de fallos: Supervisión y monitorización.

[Supervisión padre-hijo en Akka]

[Supervisión padre-hijo en Akka]

En Akka la robustez a fallos se basa en la supervisión de actores con jerarquía padre-hijo. El actor que delega tareas en los actores que crea es el que ‘supervisa‘ y decide que hacer cuando se produce un fallo en alguno de sus hijos.

Se crea así una jerarquía en forma de árbol en la que la que los actores padres supervisan a los actores hijos. El actor ‘user‘ de Akka será el padre de primera generación de actores que hayamos creado.

Esto es realmente lo que te da la robustez (‘resilence‘)  que un sistema reactivo necesita. Esta robustez se pierde cuando se intenta en vez de tener esta jerarquía, ir a un esquema con una mentalidad más tradicional de inyección de dependencias y se cae en la tentación de inyectar actores a otros actores.

Cuando un actor falla y se produce una excepción, su supervisor puede hacer, o bien reiniciar el actor, parar el actor, escalar la excepción o absorber la excepción y continuar con la ejecución.

El sistema de supervisión de Akka permite tener la posibilidad de diferente respuesta del supervisor dependiendo del tipo de excepción y si esta afecta a todos los actores supervisados o sólo al que ha fallado. Esto junto con lo anterior permite implementar fácilmente patrones,  por ejemplo de tipo ‘circuit breaker‘, si uno de los actores falla.

Akka tiene la posibilidad de establecer eventos o disparadores en el ciclo de vida de un actor. Por ejemplo antes de crearlo, antes y después de reiniciarlo y cuando se para.

Ademas del concepto de supervisión, en Akka existe el de monitorización. Cualquier actor, puede ‘monitorizar‘ a cualquier otro, lo haya creado o no. El primero obtiene un mensaje ‘Terminated‘ cuando el monitorizado ha terminado. Esto permite modificar su comportamiento o cambiar su estado. En los ejemplos siguientes el actor supervisor también hace de ‘monitor‘ de sus hijos.

Para poder mostrar con ejemplos como es el comportamiento de las diferentes estrategias a seguir, he creado en el proyecto dos actores: ActorNoTypedDummyCheckLifeCycle y ActorNoTypedLetItCrash.

ActorNoTypedDummyCheckLifeCycle se utiliza para comprobar los eventos que se disparan y por los ‘estados‘ que pasa un actor cuando es supervisado con diferentes estrategias. Concatena en un atributo ‘state‘ los diferentes pasos por los ‘hooks‘ del ciclo de vida de un actor:

  • Método ‘aroundPreStart‘: Primer evento que se dispara cuando se inicia un actor. Sólo se ejecuta cuando se inicia un actor por primera vez.
  • Método ‘preStart’: Se lanzan cuando se inicia un actor o después de que se haya reiniciado.
  • Método ‘aroundPreRestart’: Cuando un actor va a ser reiniciado, se dispara antes de parada el actor.
  • Método ‘preRestart‘: También se ejecuta antes de parar el actor cuando va a ser reiniciado. La llamada es después de la del método ‘aroundPreRestart
  • Método ‘postStop‘: Evento que se llama, o bien cuando se para el actor, o bien antes de reiniciarlo (en este último caso justo después de que se llame al método ‘preRestart‘)
  • Método ‘postRestart‘: Se lanza después de reiniciar el actor.
  • Método ‘aroundPostStop‘: Se realiza la llamada justo antes de parar definitivamente el actor.

El actor ActorNoTypedLetItCrash es el que creará y hará de supervisor de ActorNoTypedDummyCheckLifeCycle. En su constructor,  permite definir por parámetro la estrategia de supervisión. Su comportamiento será en de hacer de proxy en el envío de mensajes a  ActorNoTypedDummyCheckLifeCycle hasta que este el actor hijo se pare o cuando el mismo se haya reiniciado.

Para mostrar el comportamiento de las diferentes estrategias y cual es el ciclo de vida especifico de los actores (cuando se llama a los diferentes ‘hooks‘) he codificado en el proyecto los siguientes ejemplos.

Estrategia de supervisión por defecto

Test: ActorLetItCrashTestDefault.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestDefault test

Si se produce un excepción en un actor hijo, la estrategia por defecto en Akka es la de reiniciar el actor hijo, excepto si es un error irrecuperable:

  •  cuando se ha producido una excepción al inicializar el actor (ActorInitializationException)
  • cuando ya se había parado el actor(ActorKilledException)

Esta estrategia cobra sentido cuando se quiere mantener un sistema estable. La idea subyacente es que cuando se produce un error el sistema debería volver a un estado consistente y esto se consigue reiniciando el estado del actor.

En este ejemplo, los pasos son:

  1. Se envía un primer mensaje ‘state‘ al actor ActorNoTypedLetItCrash. Este hará el reenvío del mensaje al actor hijo (ActorNoTypedDummyCheckLifeCycle) que devolverá la concatenación de los diferentes métodos por los que ha pasado hasta ese momento.
  2. Después se envía un mensaje con una excepción para que el actor hijo provoque la excepción.
  3. Por último se vuelve a enviar un mensaje ‘state‘ para ver por los eventos que se ejecutan cuando se reinicia el actor.
  4. Finalmente para poder ver todo el flujo, se para el actor.

El ejemplo permite comprobar el flujo completo del paso de los diferentes eventos a lo largo de la vida del actor hijo. En este caso con la estrategia de supervisión por defecto, es este:

Se llama al constructor
 => Llamada a aroundPreStart
  => Llamada a preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPreRestart
     => Llamada a preRestart
      => Llamada a postStop
       => Llamada al constructor (Se vuelve a crear el actor)
        => Llamada a aroundPostRestart
         => Llamada a postRestart
          => Llamada a preStart
           => Llamada a aroundPostStop
            => Llamada a postStop

Estrategia de supervisión: Escalar la excepción

Test: ActorLetItCrashTestEscalate.java

Commando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestEscalate test


¿Qué ocurre cuando se elige una estrategia de supervisión de tipo ‘escalate‘? En este caso la excepción en el actor hijo provoca el error también en el actor supervisor. El comportamiento final depende entonces de la propia estrategia de supervisión de este último.

El ejemplo puede ayudar a verlo más claro. En este caso se configura el supervisor (ActorNoTypedLetItCrash) para que la estrategia de supervisión sea la de escalar la excepción. Cuando se provoca una excepción en el actor supervisado, el resultado es el mismo que si se hubiera producido en el supervisor.

El este caso el supervisor tiene la estrategia de supervisión por defecto, que lo reinicia, volviéndose a crear el actor hijo.

En el test se comprueba este hecho cuando se valida todo el ciclo de vida del actor hijo. Se arranca y después de la excepción, se para, para después volver a arrancar sin reinicio. Esto último provocado porque al reiniciarse actor supervisor, el hijo se para y se vuelve a crear:

Llamada a constructor
 => Llamada a aroundPreStart
  => Llamada a  preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPostStop
     => Llamada a postStop
      => Llamada al constructor (Se vuelve a crear el actor)
       => Llamada a aroundPreStart
        => Llamada a preStart
        => Llamada a aroundPostStop
         => Llamada a postStop

Estrategia de supervisión ‘resume’: ‘Absorber’ la excepción.

Test: ActorLetItCrashTestResume.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestResume test

Si el supervisor adopta una estrategia de ‘resume‘ si se produce un error la excepción no produce ni el reinicio, ni la parada del actor supervisado. Aunque se haya producido el error, sigue levantado a la espera de procesar nuevos mensajes.

El test ayuda a comprender este tipo de supervisión. Se comprueba que cuando se produce una excepción al procesar un mensaje, no se hace ninguna llamada a los métodos del ciclo de vida, ni tampoco se escala la excepción. El siguiente mensaje lo procesa correctamente.

El ciclo de vida del actor supervisado con este tipo de supervisión será:

Llamada a constructor
 => Llamada a aroundPreStart
  => Llamada a preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPostStop
     => Llamada a postStop

Estrategia de supervisión ‘stop’: Parar el actor supervisado.

Test: ActorLetItCrashTestStop.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestStop test

En este caso, se para el actor supervisado cuando al procesar un mensaje ocurre una excepción.

En el ejemplo se fuerza esta situación. Si se provoca una excepción en el actor supervisado se comprueba que el actor no se vuelve a reiniciar. De hecho si se le vuelve a enviar un mensaje de estado, este se envía a la cola de ‘Dead Letters‘ porque la referencia al actor ya no apunta a un actor válido.

El ciclo de vida del actor es el siguiente:

Llamada a constructor
 => Llamada a aroundPreStart
  => Llamada a  preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPostStop
     => Llamada a postStop

Los mismos pasos que con la estrategia ‘resume‘. Pero en este caso no ha sido necesario parar el actor en el test porque ‘muere‘ después de provocarse la excepción.

Bus de eventos interno de Akka

Test: PublishSimpleSuscribeTest.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.bus.PublishSimpleSubcribeTest test

Akka poseé un bus interno que permite el envío de mensajes siguiendo el patrón publicador-suscriptor. Un ‘publicador‘ envía un mensaje sin saber quien van a ser los receptores. Los actores que quieran recibir ese tipo de mensajes deberán suscribirse a esa publicación.

[Bus de eventos de Akka]El paradigma cambia. En vez de enviar un mensaje a un actor concreto, es decir, “(Por favor) haz esto”, cuando se publica un mensaje en el bus se está diciendo “(A quien pueda interesar) ha ocurrido esto

En este caso el ejemplo muestra un uso sencillo del bus de Akka para mostrar este patrón.

Se levantan dos actores suscriptores (del tipo ActorNoTypedLogEvent) que se suscribirán a mensajes de tipo Integer. La implementación de este actor es sencilla: registra los mensajes del tipo a los que está suscrito y si se le envía un mensaje ‘lastMessage‘ devolverá el último mensaje que ha registrado.

En el test después de levantar a los dos suscriptores se envía un mensaje al bus de Akka. Después se comprueba que el mensaje le ha llegado a ambos.

Dead letters

Test: DeadLettersTest.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.bus.DeadLettersTest test

Un ‘dead letter‘ se produce cuando no se ha podido entregar un mensaje a un actor. Un caso típico es cuando el actor receptor del mensaje ya no existe. El ‘dead letter‘ contiene el mensaje enviado, la referencia al actor que lo envía y la del que lo iba a recibir.

Por defecto Akka informa en el log de la aplicación los dead letters que se producen (esto es configurable). También pública esta información a través del bus de eventos de Akka, lo que permite que una aplicación tenga la posibilidad de una gestión específica de estos mensajes perdidos.

En el ejemplo para poder provocar un dead letter se crea un actor del tipo ActorNoTypedDummy pararlo para a continuación enviarle un mensaje. Este mensaje ‘se pierde‘ y es recogido como ‘dead letter‘.

Por otra parte en el ejemplo se está utilizando un actor del tipo ActorNoTypedLogEvent configurado para que suscriba en el bus de eventos de Akka los mensajes del tipo DeadLetter.

Cuando se manda un mensaje de ‘lastMessage‘ al actor ActorNoTypedLogEvent este devolverá la información del mensaje perdido en forma de DeadLetter.

Como comprobación final del test se validará la información contenida en el objeto DeadLetter: el mensaje y la referencia al actor receptor.


Hasta aquí este segundo artículo de Akka por ejemplos. El próximo y último artículo de esta serie será sobre actores tipados.

Espero que os sirva.

M.E.

Akka por ejemplos

«Akka representa muchos conceptos nuevos que al principio cuesta asimilar. Para poder entenderlo mejor, he ido creando, poco a poco, una serie de ejemplos que me han permitido comprender mejor el paradigma que conlleva.

[Akkapor ejemplos]

Este artículo trata sobre esto, intentar tener una prueba de código de cada nuevo concepto que permita ver cual es su comportamiento y función.»

Entrada siguiente: Akka por ejemplos. Sobre supervisión, bus de eventos, …

Akka es un framework basado en el modelo de actores que permite dar solución al problema de la programación concurrente. Además de formar parte de Scala de manera nativa existe como librería en Java.

Permite diseñar aplicaciones que sean escalables horizontalmente de manera transparente, con alta toleracia a fallos y basada en eventos que permite cumplir el ‘manifiesto reactivo‘.

Este será el primer de una seríe de artículos explicando conceptos clave que se utilizan en Akka mediante ejemplos. En esta primera parte trataré como funciona las colas de mensajes de un actor, que es un router y las diferentes maneras de como se pueden enviar mensajes entre actores.

En próximas entregas trataré sobre el sistema de supervisión de los actores en Akka, como funciona el bus de eventos y que son los actores tipados.

Esta entrada es eminentemente práctica, te invito a descargarte el proyecto y a que eches un vistazo y ejecutes los ejemplos. Se entenderá mejor lo que quiero explicar en este artículo. Todo el código fuente relacionado con esta serie de post está disponible en mi repositorio de GitHub

[Logo GitHub] AkkaActorsAndFutures

Sobre los test

La idea fundamental a la hora de realizar los test ha sido la de realizar implementaciones dummy y ‘ad hoc‘ y, gracias a ellas, montar test que permitieran ver con facilidad cual es el funcionamiento de la pieza que interesa.

Por otra parte, he buscado que el código incluido en los test puedan servir de ejemplo uando se quiera implementar ese mismo concepto en una aplicación real.

Es por esto por lo que he evitado utilizar el framework de Akka de test ‘akka-testkit’ y en algunos momentos puede parecer que me he complicado la vida realizando las validaciones cuando se completan los futuros y utilizando agentes de Akka para compartir estados entre actores.

Mucha de la funcionalidad común a todos los actores, como crear el sistema de actores y métodos de utilidad se ha llevado a test base (TestBaseTestBaseTypedActor ) de los que heredan todos los test.

Prólogo: Los agentes

Ya que en los test utilizo agentes, antes de entrar a explicar los test, intentaré hacer una breve introdución de lo que es un agente en Akka.

Un agente de Akka permite almacenar un valor y actualizarlo sin problemas de concurrencia. Tienen la particularidad que la actualización se realiza de manera asíncrona, pero se puede leer el valor de manera síncrona.

Su funcionamiento es similar a un mailbox de un actor. Se basa en encolar los nuevos valores de tal manera que el valor interno se va actualizando en orden de llegada. No existe concurrencia y por eso su actualización es asíncrona.

Hay que tener en cuenta que cuando se pide su valor de manera síncrona devuelve el valor ‘actual‘ no el valor ‘futuro‘ que tendrá cuando se procesen todos los valores encolados hasta ese momento.

Vamos entonces con los test.


Como funciona la cola de mensajes de un Actor

Test: ActorQueueTest.java

Commando maven:
mvn  −Dtest=com.logicaalternativa.examples.akka.queue.ActorQueueTest test

[Un actor, un mailbox]

Un actor, un mailbox

El modelo de actores nos asegura que no puede haber más de una ejecución concurrente de un actor. Es decir, no puede haber más de un hilo ejecutando el código de actor. Los mensajes que se envían al actor se encolan en su ‘inbox‘ de tal manera que se ejecutan de uno en uno.

En este ejemplo se está levantando dentro del sistema de actores, un actor del tipo ActorNoTypedDummy. Este tiene una lógica muy sencilla: si se envía un mensaje tipo Long la ejecución se espera los milisegundos indicados en el valor del mensaje. Si el mensaje es de tipo String devuelve un eco del mensaje.

En el test ActorQueueTest se envía un primer mensaje tipo Long para que se realice una espera y después 10 mensajes de tipo String.

En en la ejecución del test, se puede observar de que aunque se envían todos los mensajes sin esperar la ejecución del actor, en realidad estos se encolan. El actor no procesa el siguiente mensaje hasta que no ha terminado la ejecución anterior.

El resultado es que los mensajes son procesados por orden de llegada ya que este actor tiene la implementación por defecto de ‘mailbox‘ (existen otras implementaciones que permiten prioridades de mensajes). Con lo que realiza la espera del primero de ellos y después el eco del resto.

En este test para comprobar el orden de los mensajes que se están ejecutando en el actor se está utilizando un agente de Akka para guardar el estado de manera asíncrona.  El agente almacena la concatenación de los mensajes tipo cadena que se envían al actor.

Para verificar que el orden de los mensajes enviados es el mismo orden de los mensajes que se han procesado se comprueba que estas dos cadenas son iguales.

Cómo funciona un Router

Test: ActorQueueRouteRoundRobinTest.java

Commando maven
mvn  −Dtest=com.logicaalternativa.examples.akka.queue.ActorQueueRouteRoundRobinTest test

Akka permite el concepto de ‘Router‘. Esto permite asociar en una misma referencia de un actor envolver un grupo de actores del mismo tipo.

Se basa en el mismo concepto que tenemos todos en mente de que es un Router: un frontal al que se envían los mensajes y que se encarga de reenviarlos a sus ‘routees‘ para que estos los procesen y devolver la respuesta.

Permite un procesamiento en paralelo mayor, al existir más instancias de un actor, pero con la comodidad de tener una referencia única a la que enviar los mensajes.

[Concepto de router]

Router

Cada miembro del router es de hecho un actor y tiene su propia cola. La estrategia del envío de los mensajes a los miembros del enrutador se define al crear este. En el test de ejemplo se está utilizando la estrategia de envío secuencial de mensajes (‘RoundRobinPool’): se envía un mensaje a un actor del grupo, el siguiente al siguiente actor y así sucesivamente. En la documentación de Akka puedes ver que existen y se pueden utilizar otras estrategias.

El ejemplo levanta un sistema de actores. Se crea un router de 5 actores del tipo ActorNoTypedWhoIam. Este actor tiene una implementación muy sencilla. Se limita a responder en un Map con el mismo mensaje que le envían y su nombre de actor.

Al router se le envían 10 mensajes. En la resolución de cada futuro de respuesta se comprueba que el mensaje es el mismo que se ha enviado. Por otra parte, gracias a la nombre del routee, se guarda la información de que routee ha procesado el mensaje.

Por último se comprueba que a cada actor del grupo del router le ha llegado el mismo número de mensajes (estrategía de envío RoundRobinPool). En este caso son 2 ya que el router lo forman 5 actores y se mandan 10 mensajes.

En las trazas se puede comprobar que el actor con el nombre ‘a‘ le llegan los mensajes ‘0‘ y ‘5‘, al ‘b‘ el ‘1‘ y el ‘6‘ y así sucesivamente.

Como se pueden enviar mensajes entre actores

Test: ActorProxyTest.java

Comando maven
mvn  -Dtest=com.logicaalternativa.examples.akka.message.ActorProxyTest test

Fundamentalmente los actores se pueden enviar mensajes de dos maneras diferentes: tipo ‘fire & forget‘ (dispara y olvida) utilizando la función ‘tell‘ o bien seguir un esquema petición-respuesta utilizando la función ‘ask‘.

Por otra parte un actor puede crear otros actores a los que necesita enviar mensajes. Es muy común que existan actores cuya tarea sea la de orquestar o supervisar el trabajo de los actores que ha creado (‘actores hijos’), y que una parte de esta tarea sea la de reenviar a sus hijos los mensajes que les llegan. Para estos cosos es muy útil utilizar la función ‘forward

El ejemplo se crea un actor ActorNoTypedProxy que crea un actor hijo del tipo ActorNoTypedDummy. Recordemos que este último devuelve un echo de los mensajes que se le envían.

ActorNoTypedProxy hará de proxy para mostrar las diferentes formas de enviar y reenviar mensajes entre actores. Recibe los siguientes mensajes tipo cadena:

forward‘, redirigir el mensaje

Commando maven test 'forward'
mvn -Dtest=com.logicaalternativa.examples.akka.message.ActorProxyTest#testForward test

Cuando recibe un mensaje de este tipo ejecuta llamada al método ‘forward‘ del actor hijo, con el mismo mensaje. El actor hijo (ActorNoTypedDummy) recibirá el mensaje como si el emisor hubiera sido el que emitió el mensaje al actor ActorNoTypedProxy.

redirect‘ dispara y olvida

Comando maven test redirect
mvn -Dtest=com.logicaalternativa.examples.akka.message.ActorProxyTest#testRedirectMessageToChild test

El actor que hace de proxy redirecciona el mensaje llamando a la función ‘tell‘ del hijo indicando que el remitente es el del mensaje original que le llega al proxy. Aquí también el actor hijo (ActorNoTypedDummy) recibirá el mensaje como si el emisor hubiera sido el que emitió el mensaje a ActorNoTypedProxy.

[forward o 'redirect']

forward o ‘redirect’

 ‘future‘, petición-respuesta no bloqueante y asíncrona

Comando maven test 'future'
mvn -Dtest=com.logicaalternativa.examples.akka.message.ActorProxyTest#testFutur test

Este es un ejemplo de comportamiento no bloqueante y asíncrono utilizando los futuros de Scala que ofrece Akka. ActorNoTypedProxy utiliza la función ‘ask‘ para con el mismo mensaje que le ha llegado, preguntar al actor hijo ActorNoTypedDummy y obtener el futuro de la respuesta. Este futuro se envía al remitente del mensaje original.

Al ser este un futuro, si fuera necesario, se puede desde el actor que hace de proxy, operar con él o realizar cualquier tipo de transformación. Por ejemplo se puede registrar un callback, realizar alguna transformación operando con el de manera funcional, etc…

Para simplificar en el test se espera el resultado de la respuesta y como esta también es un futuro, se espera también a este para obtener el resultado.

 ‘await‘, petición-respuesta bloqueante y síncrona

Comando maven test 'await'
mvn -Dtest=com.logicaalternativa.examples.akka.message.ActorProxyTest#testAwaitFutur test

Sigue el mismo esquema que el test anterior pero esperado la respuesta de una manera síncrona.

En el actor proxy realiza la misma llamada ‘ask‘ y a continuación se utiliza la función ‘Await‘ que espera la resolución del futuro. Se obtiene así un comportamiento bloqueante y síncrono de petición-respuesta.


Hasta aquí llega esta primera parte de esta serie de artículos centrados en explicar como funciona Akka con ejemplos. Conceptos como la supervisión entre actores, el bus de eventos y que son los actores tipados serán material de futuras entregas.

Espero que os sirva.

M.E.

Entrada siguiente: Akka por ejemplos. Sobre supervisión, bus de eventos, …

Pruebas de robustez y rendimiento, sobre cache y simple cache en PHP y más…

(más => simular concurrencia, modelo de actores, de “pull request”,…)

[Robustez y rendimiento]“Este artículo trata sobre la importancia de las pruebas de robustez y de rendimiento y su relación directa con la calidad del software, y lo importante que es medir y representar los datos en una gráfica.

Un caso práctico, un sistema de cache PHP simpe basado en almacenamiento en ficheros. En teoría lento ¿verdad? ¿pero lo has comprobado?”

Introducción, Cache…

Cachear no es que sea nuevo, pero si está de rabiosa actualidad. El cacheo es una técnica fundamental dentro de los paradigmas de escalabilidad y rendimiento que se están implementando en la actualidad. Sus ventajas son claras a la hora de evitar tráfico en los cuellos de botella de una arquitectura, típicamente la base de datos. Las arquitecturas con cache compartida (con sistemas como Memcached o a otro nivel Redis) y colas de mensajes pasan a ser “la nueva forma” de hacer las cosas.

Está presente también en las tendencias actuales de arquitecturas basadas en microservicios. Algunas siguen la máxima “cache everything” (“Cachea todo lo que se mueva..” 🙂 )

Y a otro nivel, también hay un debate abierto con la movilidad y en el que ha entrado de lleno Linus Torvalds (1). Defiende que añadir más procesamiento en paralelo (más cores a los procesadores de los móviles) no es la solución y que las caches grandes son eficientes.

El cache también tiene sus problemas intrínsecos complejos. Por ejemplo, la invalidez de los valores cacheados. Si no se hace correctamente se puede trabajar con datos ‘antiguos’ y perder información. Problema antiguo… Martin Fowler (2), ha hecho famosa la cita de Phil Karlton

“There are only two hard things in Computer Science: cache invalidation and naming things.”

El caso práctico, cache simple en PHP

El objetivo de este post no es tan ambicioso como para meterse de lleno en este problema. En su tiempo para el post “Dar valor a los tweets: Interés, difusión, audiencia,… trasteando con el API de Twitter” necesitaba una librería para cachear los resultados del api de Twitter. Me decanté la librería php-cache de Emilio Cobos, me pareció sencilla, fácil de utilizar y configurar y suficiente para lo que necesitaba. Desde entonces llevo usándola también en otros proyectos.

El almacenamiento en memoria es lo más rápido para una cache. Esto, que en Java es sencillo de implementar, basta con almacenar el valor en un atributo estático de una clase para que este accesible en todos los hilos de ejecución, en PHP es necesario usar extensiones externas al core de PHP o utilizar memoria compartida. Esto último honestamente no creo que sea lo más se adecue dentro de este contexto en donde lo que busqué es la máxima sencillez.

[Cache]La finalidad de la librería es tener un sistema de cache sencillo sin necesidad de instalación de extensiones como apc ni ni servicios como memcache. Tan sólo es necesario que el usuario del apache tenga permisos de escritura, cosa que es lo más común. Por esto es ideal para “alojamientos compartidos” de páginas web.

Su funcionamiento similar a otras librerías de este tipo. Está basada en la serialización de las variables, y su almacenaje en ficheros de texto. El código fuente es sencillo, ordenado y muy fácil de seguir.

Después de decirme a usarla y ver como funcionaba, me surgieron dos dudas. En su momento, en anteriores proyectos, tuve problemas de concurrencia en PHP cuando más de un proceso leía/escribía en el mismo fichero a la vez. Además que el acceso a cache tuviera acceso a disco «¿cuánto estaba penalizada la velocidad este motivo?»

Estas dos preguntas fueron la excusa para adentrarme en el mundo de las pruebas de rendimiento y de robustez. Otra pata importante dentro del desarrollo que aporta valor a la calidad del software. El resultado de todo esto está reflejado en lo que viene a continuación.

Adelanto que propuse unos cambios en el código y Emilio Cobos a tenido a bien aceptar mi ‘pull request‘, por lo tanto he pasado a ser un humilde, pero a la vez orgulloso contribuidor de php-cache.

Pruebas de robustez, concurrencia lectura/escritura de una clave de la cache

php-cache utiliza para cada clave de la cache un fichero donde almacena el valor «serializado«. Para probar la concurrencia cuando varios procesos leen/escriben en una misma clave de la cache diseñe dos test.

El primero de ellos, robustness-rw.test.php, lanza 10 procesos concurrentes, simulando 10 clientes ejecutando las mismas operaciones a la vez. Cada uno de ellos graba un valor en una clave de la cache y a continuación obtiene el valor de la misma clave de la cache. Estas dos operaciones las realiza cada proceso 50 veces (un total de 500 operaciones de escritura/lectura en total) cambiando cada vez el valor grabado de 3 posibles.

El valor obtenido de la cache tiene que ser igual a alguno de los tres valores posibles. Si es diferente o es nulo el valor se considera como invalido.

El segundo de los test de robustez, robustness-rw2.test.php es similar al anterior. En este caso además de guardar y obtener el valor se realiza una tercera operación de borrado de la clave de la cache. En este caso, el valor obtenido de la cache tiene que ser igual a alguno de los tres valores posibles o nulo. En cualquier otro caso se considera como inválido.

Los dos test están el directorio test repositorio principal de la librería ya que estaban incluidos en el ‘pull requestaceptado. En el README.md del directorio test está explicado más en profundidad lo que hacen y como se lanzan.

[Logo GitHub] Repositorio GitHub Cache.php

Simulando los clientes concurrentes, esquema basado en el modelo de actores

¿Cómo simular los clientes/peticiones concurrentes? Hay que tener en cuenta que el soporte multihilo no viene habilitado en una instalación tipo de PHP. El esquema que he seguido para simular la concurrencia he seguido en el paradigma de “modelo de actores”.

El script principal (actor principal) se encarga de lanzar los demás actores (procesos secundarios). En este caso son procesos PHP, en realidad una copia del mismo test que tiene un comportamiento diferente si “actúa” como actor secundario. Los secundarios se encargan cada uno de de hacer las 50 peticiones de escritura/lectura o escritura/lectura/borrado en una misma clave común.

Una vez lanzado los actores secundarios, el principal espera a que todos terminen para recoger los resultados y calcular la información estadística de los errores que se hayan podido producir.

Los mensajes entre el actor principal (el proceso) y el resto de actores (los procesos secundarios) los he montado utilizando también la librería php-cache.

Este es el flujo seguido:

[Concurrencia utlinzando modelo de actores]

  1. El proceso principal crea los actores pesándoles como parámetro una clave auxiliar de la cache (diferente para cada proceso) en la que escribirán el resultado. Los actores secundarios una vez hayan terminado su trabajo escriben en esa clave de la cache sus resultados.
  2. El proceso/actor principal se encarga de preguntar el estado de los actores lanzados, comprobando si existe la clave auxiliar en la cache que ha asignado a cada proceso.
  3. Una vez haya leído todas las claves auxiliares (todos los procesos hijos han terminado) calcula las estadísticas y muestra los resultados.

Los mensajes son inmutables, los actores secundarios sólo escriben en la clave asignada y el principal sólo lee las claves que ha asignado.

Resultado de los test de robustez y modificación del código

Al lanzar los test de robustez comprobé que en estos casos extremos de concurrencia la librería podía devolver la lectura de datos corruptos.

Hice una pequeña modificación en el código. Ahora siempre que se almacena un valor de una clave se escribe en un archivo temporal. Si la escritura es correcta, el fichero temporal se renombrará al definitivo utilizando la función rename de PHP. Esta función, es atómica si se realiza en el mismo sistema de ficheros. Este es el caso ya que se trabaja en el mismo directorio.

Volviendo a lanzar los test con este cambio ya no se obtienen datos corruptos y tanto la lectura se ejecutan sin errores.

Después de hacer un ‘fork‘ del repositorio y propuse los cambios lanzado un ‘pull request‘. Esta petición ha sido aceptada y los esta modificación está ya en el repositorio oficial de php-cache en GitHub

Pruebas de rendimiento. Mini benchmark

php-cache es una librería basada en lectura/escritura de ficheros, así que su velocidad depende de lo rápido que sea el acceso a disco y su velocidad de lectura.

En el repositorio de GitHub he subido un pequeño script (benchmark.test.php) que permite realizar medidas del acceso a un valor de la cache y cual sería el tiempo medio por respuesta.

Además como referencia se calcula el valor medio que se tarda en recuperar el objeto de su representación en cadena cuando sus datos están en memoria sin acceder a disco. Es decir, el valor teórico ideal que se alcanzaría si el coste de tiempo de acceso a disco fuera cero.

La información que devuelve el test es tanto el coste real como el teórico, número de peticiones realizadas, tiempo total y las estadísticas con datos sobre la media de milisegundos que ha tardado en hacer una petición y el cálculo de las peticiones por segundo.

… Dibujando y sacando conclusiones

Las conclusiones se pueden pueden ver de las siguientes gráficas:

En la primera (Gráfica 1) se muestra la información de los datos de las peticiones por segundo de los dos procesos, el real y el teórico. Si se observa con atención, para objetos de poco peso el  valor del  número de peticiones es  muy dispar entre las dos gráficas. Sin embargo, según va aumentando el peso del objeto guardado en cache, los dos valores se acercan hasta que casi el valor real es igual al ideal … Pero « ¿por qué puede pasar esto?»

Para poder poner un poco de luz en el asunto he creado la Gráfica 2. Se muestra la velocidad en MB por segundo en obtener el objeto. Una de las líneas es la velocidad de las peticiones reales, otra es como sería el calculo ideal y la línea amarilla es la velocidad que tarda en leer de fichero, es decir el tamaño del objeto dividido por la diferencia de los dos tiempos (real menos teórico).

Se puede observar, que mientras las velocidades de los procesos teórico y real tienden a ser constantes, la velocidad de lectura crece. En proporción, cuanto más grande es el objeto menos tarda en leerlo.

Con los objetos más grandes, al ser el proceso de lectura mucho más rápido que el proceso de «des-serialización«, el peso del primero pasa a ser despreciable en comparación con el segundo. Es la velocidad del proceso más lento (la «des-serialización«) la que marca la velocidad al obtener un valor de la cache.

La librería php-cache también tiene la posibilidad de guardar los datos en «crudo» sin serializar para almacenar cadenas, por ejemplo, para cachear la salida html directamente. Las siguientes gráficas (Gráficas 3 y 4) son los datos obteniendo un valor de la cache en «crudo«. Muestran mejor a la conclusión que quiero llegar.

En este caso la velocidad de lectura aumenta según lo hace el tamaño del objeto a leer y tiende a un máximo.

Y vuelvo a repetir «¿Por qué pasa esto?» Sorprendente, …o no tanto.  La respuesta es que el sistema operativo viene al rescate y entra en acción el buffer cache del disco (3).

El acceso a disco es mucho más lento que el acceso a memoria. El buffer cache del disco del sistema operativo sirve de colchón amortiguador de esta diferencia de velocidades de acceso. Mantiene en memoria (cache, …su cache) aquellos datos que leen la misma parte del disco varias veces durante periodos relativamente cortos de tiempo. Con respecto a este punto también he hecho pruebas realizando un sleep de dos segundos entre peticiones y la velocidad era la misma por lo que el los datos se conservaban en el buffer.

Recordar que este buffer no realiza cache de archivos, pero sí de bloques. Cuantos más bloques del fichero están en cache más rápido será la lectura y también añadir que el buffer de lectura de disco es transparente y lo gestiona el sistema operativo.

Resumiendo, cuanto mayor sea el tamaño del objeto a cachear y mayor sea el número de lecturas, php-cache pasa de ser un sistema cache basado en disco, «a priori» lento, para convertirse de «facto» en un sistema de cache basado en memoria y pasar a ser rápido. Y recordemos que estas circunstancias, objetos grandes y costosos de calcular con cierta carga de lectura, son precisamente una de las razones por las que se valora adoptar un sistema de cache.

Conclusiones

Siempre que se evite la optimización prematura evitando complicar innecesariamente el software  (optimizar es un vicio, cuando se empieza no se sabe como parar), las pruebas de robustez y de rendimiento pueden ser unas herramientas muy útiles.

Permiten valorar como se comportará el producto que estás desarrollando o como lo hará el que estás pensando en adoptar… Sabemos que en muy pocas ocasiones los errores que surgen en un entorno de producción son reproducibles,  pero que duda cabe que estas pruebas dan un plus de confianza en el software desarrollado. Y puede, como en este caso concreto, que te lleves una sorpresa para bien y se comporte mucho mejor de lo que en un principio podías esperar.

Otra conclusión, siempre que se mide se debe dibujar. Es importante reflejar los datos en un gráfico. Esto ayuda a vislumbrar una tendencia en los datos y obtener respuestas.

Y por último romper una lanza en favor de PHP. En algún sitio he leído que si «PHP fuera un arma se podía comparar con la manguera que pones al escape del coche para intentar suicidarte«…

No pienso así, PHP es un lenguaje al que tengo especial cariño y su simplicidad y potencia está demostrada con esta clase php-cache. Con unas pocas líneas tienes un sistema de cache muy competente y fiable que puedes usar sin problemas en proyectos sencillos y en el que puedes almacenar un montón de valores en la cache… tantos como espacio tengas en el disco duro.

Espero que os sirva.

M.E.

Referencias

  1.  [Linus: The whole «parallel computing is the future» is a bunch of crock] (highscalability.com)
  2. [TwoHardThings] (martinfowler.com)
  3. [El Buffer Cache] (tldp.org)

Mocks… o el TDD y yo

… segunda Parte de TDD is dead? … o yo y el TDD

[Mock y test]Este es el segundo y último artículo de la serie que completa el anterior post TDD is dead? … o yo y el TDD.

Trataré de explicar como defino y codifico mis propios objetos ‘mock‘, y de como los uso tanto para pruebas unitarias, como también en pruebas de integración entre clases.

Y siendo más especifico mostrar como se pueden codificar tres tipos de mock utilizados habitualmente:

  •  Simular la capa de persistencia a base de datos.
  •  El que se utiliza para comprobar que se ha llamado a la interfaz que representa desde el objeto que nos interesa probar.
  • El utilizado simplemente para poder pasar las pruebas y que no nos interesa su comportamiento.

Y como dijo el maestro:

“… hablar es barato, vamos a ver un poco de código…”

Demo

Para ilustrar el ejemplo utilizaré una aplicación web que mediante un formulario html sencillo llamará con ajax a un servicio REST. Consiste en dar de alta códigos de promoción de una web.

[Pantallazo de la Demo Ejemplo Mock]

[Pantallado de la demo]

Los datos que se piden son la promoción, el nombre, el correo electrónico y el código de promoción. Se validará que el correo electrónico no esté ya utilizado y si todo es correcto se enviará el correo a la persona y se mostrarán los datos de los códigos ya dados de alta.

La demo es completamente operativa y se puede usar. Se puede descargar el código aquí:

[Logo GitHub]MoksExample en GitHub

Los detalles de como funciona y como se puede probar están en el archivo README.md

La parte de servicios REST es Java, montada sobre Spring. En el ecosistema de Spring, Spring-Data es el mediador con la capa de persistencia de datos. En el ejemplo se usará como interfaz con la base de datos. Como framework de tests unitarios usaré Junit. Maven será la herramienta de compilación, ejecución de test y construcción del proyecto. Como es una demo para estos fines se usa Hsqldb, base de datos en memoria.

Simular la capa de persistencia de BBDD

En la demo existen dos entidades PROMOTION y PROMOTION_CODE. La primera es el maestro de promociones y en la segunda se almacenarán todos los códigos de promoción relacionados con las primeras. Los objetos de negocio que las definen son los beans: Promotion y PromotionCode

Spring-Data se basa en el patrón repositorio. A grandes rasgos y simplificando, Spring-Data implementa la interfaz de las operaciones CRUD y el resto de consultas que se pueden realizar para cada entidad de la capa de persistencia (usualmente una tabla de una base de datos).

Existen por tanto dos interfaces definidos en el pakage com.logicaalternativa.ejemplomock.repository cuya misión es definir las operaciones CRUD de las entidades

En este caso los dos extienden del interfaz de Spring-Data JpaRepository.

Con Spring-Data sólo tienes que definir la interfaz con las diferentes operaciones de consulta, inserción y modificación que se van a realizar de la entidad y este se encarga de implementar la interfaz. Esto hace que resulte muy fácil codificar tus propios mocks. Después para los test se inyectarán por inversión de control al objeto de negocio.

Para los test he implementado los dos mock de cada uno de los interfaces. Están en el package com.logicaalternativa.ejemplomock.repository.mock .

Las dos clases son muy similares y siguen la misma línea. Sólo se ha implementado las operaciones necesarias para realizar los test. La idea es esa codificar sólo lo estrictamente necesario. Se añadirá o se modificará código cuando toque, si para un futuro test es necesario implementar algún otro método más.

Centrándome por ejemplo en el mock PromotionCodeRepositoryMock, el ‘quid de la cuestión‘ está en que he definido un atributo lista de tipo PromotionCode.

1
public class PromotionCodeRepositoryMock implements PromotionCodeRepository {
2
   private List<PromotionCode> promotionCode;
3
...
4
}

Este es accesible mediante los métodos públicos:

1
public class PromotionCodeRepositoryMock implements PromotionCodeRepository {
2
...
3
   public List<PromotionCode> getPromotionCode()
4
...
5
   public void setPromotionCode(PromotionCode...promotionCode)
6
...
7
}

He codificado los métodos CRUD para que operen con esta lista. Por ejemplo, así he codificado el método que sirve para obtener un código de promoción a través de su clave primaria.

01
public class PromotionCodeRepositoryMock implements PromotionCodeRepository {
02
...
03
  public PromotionCode findOne( final String email ) {		
04
    int index = findIndex( email );		
05
    if ( index != -1 ) {
06
      return clone( getPromotionCode().get( index ) ); 
07
    }	
08
    return null;
09
  }
10
...
11
}

Que lo que hace es encontrar el índice de la lista de códigos de promoción con el mismo email. Si lo encuentra devuelve una copia de ese objeto. Para entrar más en detalle te invito a revisar los métodos findIndex, clone y el resto de métodos que he implementado de PromotionCodeRepositoryMock

Otro ejemplo es el método saveAndFlush:

01
public class PromotionCodeRepositoryMock implements PromotionCodeRepository {
02
...
03
  public <S extends PromotionCode> S saveAndFlush(S promotionCode ) {
04
    if ( getPromotionCode() == null ) {
05
     this.promotionCode = new ArrayList<PromotionCode>();
06
     getPromotionCode().add( promotionCode );
07
     return promotionCode ;
08
    }
09
    final String email = promotionCode != null ? promotionCode.getEmail() : null;
10
    int index = findIndex( email ) ; 
11
    if ( index == -1 ) {
12
     getPromotionCode().add( promotionCode );
13
    } else {
14
     getPromotionCode().set( index, promotionCode );
15
    }
16
    return promotionCode;
17
  }
18
...
19
}

Que busca en la lista el objeto con el mismo email. Si lo encuentra actualiza el objeto de la lista y sino, lo añade a la lista.

¿Cómo se usa?

El test AddCodeBusinessImpTest prueba el objeto de negocio AddCodeBusinessImp.

La clase de negocio (AddCodeBusinessImp) comprueba que existe el código de promoción en la BBDD y utiliza para ello PromotionRepository. En el método setUp() del test se inicializa un objeto PromotionRepositoryMock con el objeto Promotion deseado y este mock se inserta por inversión de control a la instancia de AddCodeBussinessImp.

01
public class AddCodeBusinessImpTest {
02
  ...
03
  private AddCodeBusinessImp addCodeBusinessImp;
04
  ...
05
  private PromotionRepositoryMock promotionRepositoryMock;
06
  private PromotionCodeRepositoryMock promotionCodeRepositoryMock;	
07
  private Promotion promotion;
08
  ...
09
  @Before
10
  public void setUp() throws Exception {
11
    promotion = new Promotion();
12
    promotion.setIdPromotion( 1 );
13
    ...    
14
    promotionRepositoryMock = new PromotionRepositoryMock();
15
    promotionRepositoryMock.setPromotions( promotion );
16
    ...  
17
    addCodeBusinessImp = new AddCodeBusinessImp();
18
    addCodeBusinessImp.setPromotionRepository( promotionRepositoryMock );
19
    ...
20
  }
21
  ...
22
}

promotion, promotionRepositoryMock, addCodeBusinessImp son atributos privados de AddCodeBusinessImpTest.

Internamente AddCodeBusinessImp llama al método findOne de PromotionRepository con el identificador de la promoción (el del maestro de promociones) del nuevo código que se quiere insertar.

Si queremos testear que ocurre si no encuentra la promoción en la BBDD, simplemente se hace lo que en el método testPromotionNotBbDd de AddCodeBusinessImpTest:

01
public class AddCodeBusinessImpTest {
02
  ...
03
  @Test
04
  public void testPromotionNotBbDd() {
05
    try {
06
      promotionRepositoryMock.setPromotions( ( Promotion[] ) null ); 
07
      addCodeBusinessImp.validateAndAdd( promotionCode );
08
      ...
09
  }
10
  ...
11
}

Si la lista de promociones en PromotionRepositoryMock es nula no se podrá encontrar la promoción (El método findOne devolverá nulo).

En este mismo test también se utiliza PromotionCodeRepositoryMock. Inyectado también por inversión de control a la instancia de AddCodeBusinessImp, en este caso, sirve para comprobar que se ha insertado el código de promoción. Se hace en el test testOk

01
public class AddCodeBusinessImpTest {
02
  ...
03
  @Test
04
  public void testOk() {
05
    try {
06
      addCodeBusinessImp.validateAndAdd( promotionCode );
07
      final List<PromotionCode> promotionCodeBbDCodes = promotionCodeRepositoryMock.getPromotionCode();
08
      boolean result = promotionCodeBbDCodes != null
09
                && promotionCodeBbDCodes.size() == 1
10
                && promotionCode.equals( promotionCodeBbDCodes.get( 0 ) )
11
               ;
12
      ...
13
  }
14
  ...
15
}

Para tener una visión más clara de cual es la idea, lo mejor es revisar cada uno de los test Junit de AddCodeBusinessImpTest Creo que puede ser de gran ayuda para tener una visión global de lo que quiero plantear . He intentado que sean claros y autoexplicativos.

Mock de comprobación de llamada a interfaz y datos correctos.

Lo que interesa en este caso es comprobar que un objeto de negocio hace la llamada a un interfaz con los datos correctos. Lo que se hace es ‘mockear‘ esa interfaz capturando los datos de la llamada para comprobar después de que estos son correctos.

En la demo existe un objeto de negocio, SendMailCodePromotionImp, que a partir de una dirección de correo manda el código de promoción por email. Este objeto de negocio realiza internamente una llamada a la interfaz JavaMailSender que implementa Spring (JavaMailSenderImpl) para enviar el correo electrónico.

JavaMailServerMock, que implementa también el interfaz JavaMailServer, es el mock que va a recoger los datos de la llamada. En este caso sólo me interesaba saber la dirección de correo a la que se envía el correo electrónico. Para ello he implementado el método send:

01
public class JavaMailServerMock implements JavaMailSender {
02
  ...
03
  private String sendTo;
04
  ...
05
  @Override
06
  public void send( MimeMessage mimeMessage ) throws MailException {
07
    String[] to = null;
08
    try {
09
      to = mimeMessage.getHeader("To");
10
    } catch (MessagingException e) {
11
      logger.error( "[send] ".concat( e.getMessage() ), e );  
12
      to = null;      
13
    }
14
    setSendTo( to != null && to.length > 0 ? to[0] : null );
15
  }
16
  ...
17
  public String getSendTo() {
18
    return sendTo;
19
  }
20
  public void setSendTo(String sendTo) {
21
    this.sendTo = sendTo;
22
  }
23
}

Se recoge del argumento de entrada la cabecera “To” para almacenarla en un atributo de la clase.

¿Cómo se usa?

En el test SendMailCodePromotionImpTest se utiliza este Mock. En el método setUp(), se instancia y se inserta por inversión de control al objeto SendMailCodePromotionImp.

01
public class SendMailCodePromotionImpTest {
02
  ...
03
  private SendMailCodePromotionImp sendMailCodePromotionImp;
04
  ...
05
  private JavaMailServerMock javaMailServerMock;
06
  ...
07
  @Before
08
  public void setUp() throws Exception {
09
    ...
10
    javaMailServerMock = new JavaMailServerMock();
11
    ...    
12
    sendMailCodePromotionImp = new SendMailCodePromotionImp();
13
    ...
14
    sendMailCodePromotionImp.setJavaMailSender( javaMailServerMock );
15
    ...
16
  }
17
  ...
18
}

El test testOk de SendMailCodePromotionImpTest sirve como ejemplo para comprobar si se ha realizado correctamente la llamada:

01
public class SendMailCodePromotionImpTest {
02
  ...
03
  public void testOk() {
04
    try {
05
      sendMailCodePromotionImp.sendMailCodePromotion( email, locale );
06
      final String sendTo = javaMailServerMock.getSendTo();
07
      boolean res = sendTo != null
08
              && sendTo.equals( nameUser.toUpperCase() + " <" + email +">"  );
09
    ...
10
  }
11
  ...
12
}

Donde después de hacer la llamada al método sendMailCodePromotion del objeto de negocio se obtiene el atributo de sendTo del mock para comprobar que se envía a la misma dirección de correo electrónico.

En este mock sólo se comprueba la cabecera ‘To‘. También se podría comprobar el texto del mensaje o cualquier otro dato enviado desde el objeto de negocio.

Mock para pasar las pruebas

En la demo he codificado MessageSourceMock que implementa el interfaz MessageSource, utilidad que tiene Spring para la internacionalización. Este mock sólo me interesa para poder probar otras funcionalidades. Ha sido necesario codificado porque el objeto de negocio lo necesitaba, pero, en este caso, el resultado de su llamada era irrelevante. Solamente se ha codificado el método getMessage :

1
public class MessageSourceMock implements MessageSource {
2
  ...
3
  @Test
4
  public String getMessage(String arg0, Object[] arg1, Locale arg2) throws NoSuchMessageException {
5
    return arg0;
6
  }
7
  ...
8
}

Que como puedes comprobar, devuelve directamente la entrada.

¿Cómo se usa?

En el test SendMailCodePromotionImpTest se utiliza este Mock. En el método setUp()Se instancia y se inserta por inversión de control al objeto
SendMailCodePromotionImp.

01
public class SendMailCodePromotionImpTest {
02
  ...
03
  private SendMailCodePromotionImp sendMailCodePromotionImp;
04
  ...
05
  private MessageSourceMock messageSourceMock;
06
  ...
07
    @Before
08
  public void setUp() throws Exception {
09
    ...
10
    messageSourceMock = new MessageSourceMock();
11
    sendMailCodePromotionImp = new SendMailCodePromotionImp();
12
    ...
13
    sendMailCodePromotionImp.setMessageSource( messageSourceMock );
14
  }
15
  ...
16
}

Ya ahora al hacer la llamada getSendTo del objeto de negocio no aparece la tan temida NullPointerException 😉

Conclusiones

Como se puede ver, con un poco de ingenio es relativamente sencillo crearte tus propios objetos mock sin tener que recurrir a Frameworks. La creación de los mock me ayudan a comprender mejor como funciona la aplicación y ver las clases involucradas como verdaderas cajas negras. Esta es la gracia del paradigma de la orientación a objetos.

No necesariamente tiene que llevar demasiado tiempo el codificarlos. Sólo se debería ‘picar’ lo que necesitas cuando lo necesitas y mucho es reaprobechable. Al final del proyecto seguro que tienes un buen juego de objetos mock para pruebas.

Otra ventaja, es que no hay reflexión, no existe bbdd en memoria para los test, ni ha sido necesario levantar un entorno para pruebas… el resultado es que los test van ‘volaos‘.

M.E.

P.D.: Para esta demo, de esto que te vas liando y liando… y poco a poco me ‘currado’ un framework MVC hecho en JavaScript. Cuando lo organice un poco será material para próximos post.

TDD is dead? … o yo y el TDD. Primera Parte

Test-driven development (TDD)”, en la lengua de Cervantes “Desarrollo guiado por pruebas”… Palabras malditas para algunos… Últimamente se dice que está muerto… “TDD is dead?”.


Actualización:
La segunda parte de este artículo es «Mocks… o el TDD y yo»


¿Qué es?

A grandes rasgos, consiste en primero diseñar y realizar los test de una determinada funcionalidad (lo usual es una clase de negocio). En este punto los test no pasan => Test ‘en rojo‘.

[Esquema TDD]A continuación se codifica, centrándonos en que pasen todos los test. Una vez que todos están ‘ok’ (Test en ‘verde‘) se refactoriza el código. Se da un repaso final para que quede todo correcto y pulir los flecos que quedan.

Estos test serán siempre independientes. No debe importar el orden en que se lancen. Se añaden a la herramienta de integración continua para que se pasen en cada compilación/build y asegurarse así que no ha habido ‘efectos colaterales’ en cada modificación de código fuente.

«TDD is dead?«.. el debate.

Si partimos de este enfoque ¿es todo ‘testeable‘? ¿Se ve condicionado tu diseño del software poder hacer este tipo de pruebas? ¿Cuanto tardan tus test? ¿Es asumible este tiempo?

Todo esto y más argumentos se han puesto encima de la mesa. Hay quien opina que que en el TDD puro sólo es para entornos académicos y blogs y que en el mundo real no se puede llevar al extremo. Hay pruebas que no se pueden replicar tan fácilmente y que dependen de un entorno desplegado (terceros sistemas).

Tampoco es recomendable que se condicione el diseño y la arquitectura para poder realizar los test. Debe ser al contrario los test se deben adaptar al diseño.

El TDD se basa en pasar continuamente los test, por lo tanto deben ser lo más rápidos posible. En algunos casos el tiempo de lanzar toda la batería de test no es despreciable. En este punto los Frameworks de ‘mock‘ basados en generación de clases por reflexión están en el punto de mira.

Y a pesar de todo esto, esta forma de desarrollar me ha hecho la vida más sencilla. Lo intento explicar:

Mi Kung-fu, Mi TDD

He llegado a esta metodología tarde. No fue hasta que empezando con un proyecto desde cero, que me puse en serio a seguir este paradigma. Mi conversión ha sido tal, que confieso que ahora ya casi no sé prescindir de los test al enfrentarme a tirar código. Primero me planteo los tests y después implemento. Aunque esto no es siempre así, tengo bastante flexibilidad.

Si tengo claro ‘lo que hay que hacer‘ hago todos del tirón. Repaso todos los casos de uso, las posibles entradas, salidas y los errores y cada caso lo reflejo en un test.  En estos casos lo más normal es que tarde más en diseñar los test que en codificar. El proceso es, de manera iterativa, terminar una parte de la codificación e ir pasando los test, hasta que no quede ninguno con error y la funcionalidad esté terminada.

En los casos que no tengo tan claro lo que tiene que hacer la clase, quizás porque, por ejemplo, tenga que ‘repartir’ la responsabilidad en otra clase, empiezo realizando los test que si tengo claro, validando entradas y resultados parciales. Codifico y logró que se pasen los test. Me replanteo o no la  estructura y vuelvo a codificar los nuevos test y terminar de implementar la parte que queda. Todo también de manera iterativa.

En cualquier caso siempre habrá uno o varios test con las entradas y la salida correctas. Los pongo al principio de la clase de test y me sirve de documentación. De un vistazo se puede saber el comportamiento y el control de errores realizado.

Sobre los ‘mock’

Para poder realizar los test ‘mokeo’ las clases que necesito para probar la funcionalidad. Empecé realizando mis propios objetos Mock porque no quería que mi foco se perdiera en el aprendizaje de un nuevo Framework de ‘mokeo‘.

En la arquitectura en la que suelo trabajar Spring y Spring-Data para acceso a base de datos, en lo que todo es un interfaz, es supersencillo crear el Mock que genere la salida que necesitas. Estos objetos son reaprovechables, ya que en un proyecto normalmente las clases están relacionadas, y utilizas el mismo Mock para varios test.

Esto en realidad no va en contra de ‘la máxima‘ de que los test no puede ser un desarrollo en sí, ya que ‘sólo codifico la parte que necesito‘. Si en un segundo test necesito más funcionalidad completo el comportamiento del Mock.

Resulta que después, leyendo post como este  («When to mock«) en el Blog de Uncle Bob Martin me di cuenta que no iba tan mal encaminado.

Estoy preparando un segundo artículo donde intentaré explicar con ejemplos como hago los ‘mock‘.

Qué he ganado

Sobre todo una nueva visión de enfrentarme al desarrollo, para mi más enriquecedora. Ahora lo primero que pienso son los parámetros que voy a pasar a la clase y que salida quiero obtener. Valoro que entradas podrían causar error y como quiero realizar este control de errores. Esto hace que tenga una idea mucho más clara de lo que va hacer la clase y de que parte de la funcionalidad va a ser responsable.

Para simular la base de datos utilizo mis propios ‘mock‘ implementando los interfaces de Spring-Data y no uso una BBDD en memoria. Esto también me ha ayudado a entender mejor que datos necesito y tener mucho más claro el modelo.

He ganado en seguridad. Casi consigo que el 100% del código sea testeable. Gracias a los test estoy seguro de que se ha pasado por cada uno de los ‘if’ del  código.

Es significativo que ahora uso mucho menos el ‘debug‘ para saber que está fallando y corregir errores. Puede resultar paradójico pero en muchos casos, con los test consigo comportamientos que es difícil de obtener para obtener el mismo resultado en una prueba de integración. Normalmente hago pocos ajustes en el código cuando lo pruebo desplegado en un servidor de aplicaciones, contra una base de datos de verdad, …

Tengo menos bug y más control de la interrelaciones que tiene el código. Si hay alguna modificación de uan parte del código que afecta a otra, los ‘test’ pueden evitar muchos de estos problemas de interrelación. Problemas que suelen surgir, ‘como siempre pasa’ (ley de Murphy), en producción.

Como contrapartida se tarda más en el desarrollo y el proceso de generación de los test no es ‘tan divertido‘ como puede parecer. De todas maneras las ventajas que he obtenido me salen a cuenta y doy el tiempo por bien invertido.

Reflexiones

Realmente en mis proyectos, y a pesar de integrarse con más de un sistema de terceros no he tenido muchos problemas en generar los test. No he sentido que el diseño del software se haya visto condicionado.

Al hilo de esto, estoy acostumbrado a trabajar con Spring y su inversión de control. Hay quienes le ‘chirría’ tener que definir un interfaz aunque sólo haya una implementación.  A mí definirlo me parece más limpio indicando así el api pública de la clase.

Esto para los test viene muy bien. En muchos casos por cada interfaz existirá la implementación de la funcionalidad y otra ‘mock‘ para simular el comportamiento para los test de otra clase.  Insisto no lo veo como un condicionante de diseño para facilitar los test. Hubiera definido el interfaz de todas maneras incluso en el caso de que no hubiera hecho los test.  Sobre esto me parece interesante este post How tdd affect my designs«)

El hecho de implementar mis propios ‘mock‘ y que estos no sean creados utilizando reflexión y sólo haya que instanciarlos, hace que la lentitud no sea un problema.

Así que, en la práctica, no me he encontrado muchos problemas técnico/filosóficos a la hora de utilizar el TDD. Queda pendiente la segunda parte de este artículo de ejemplos de ‘mock’ que estoy utilizado.

Espero que os sirva.

M.E.

Aprendiendo Grunt a partir de Ant

Prólogo

Hace unos años, unos 8 ya …

[Grunt logo]En un proyecto me tocó realizar una ‘builtool‘. Era una herramienta común que utilizarían todos los demás proyectos no importando su tecnología, PHP,.Net, Java, etc. Obtenía el código del sistema de control de versiones compilaba, paquetizaba y subía la build compilada a otra rama del control de versiones. En realidad era un pre-Maven porque obligaba a una cierta estructura de directorios en los proyectos pero no tenía ni su control de dependencias, ni sus arquetipos para nuevos proyectos. La herramienta estaba hecha en Ant.

Realmente nunca me llegó a apasionar ese proyecto, siempre me ha gustado más programar. Pero me ayudó a tener conciencia de la importancia de saber montar el ‘Control de la configuración‘ de un proyecto y también, como podéis imaginar, a tener bastante soltura con Ant.

Capitulo I

… en la actualidad

Para el Front del nuevo proyecto, con mucha carga de JavaScript, teníamos que generar la build  y realizar el despliegue. Para hacer menos pesada y más rápida la descarga necesitamos comprimir html, jasvascript y css y en el caso de estos dos últimos unificarlos en un sólo fichero.  Este proceso también lo  utilizaríamos para hacer despliegue continuo en nuestro entorno de preproducción, utilizando Jenkins.

Grunt se ajustaba perfectamente a nuestras necesidades y además se unificaba las tecnologías. La elección de Grunt en vez de Gulp, otra herramienta similar, fue porque el primero está incluido en Yeoman, que viene a ser en Javascript lo que Maven es a Java. Una herramienta de gestión de dependencias, arquetipos, generación de buidls, test, etc.., que al igual que Maven permite gestionar todo el ciclo de vida de las builds. Elegí Grunt como un primer paso del camino que muy probablemente nos lleve a Yeoman.

Me enfrente al reto aprendiendo algo nuevo desde la perspectiva de algo conocido. Utilizando como punto de apoyo, sin que lo conocido conllevara  a perjuicios iniciales. Estas son las semejanzas, las diferencias y las conclusiones a las que he llegado.

En que se parecen…

Ant tiene ya mucho recorrido, o dicho de otra manera ya es bastante ‘viejuno‘. En cierta forma fue la respuesta de Java al Make de C. Surgió de la necesidad de crear una herramienta que pudiera compilar, generar ejecutables y que no dependiera del sistema operativo donde se ejecutara. Permite también la generación de test, despliegue, generación de documentación, etc.

Grunt está dentro del ecosistema Javascript, es un ‘ejecutor de tareas‘ y se usa fundamentalmente para realización de builds, su testeo y su despliegue.

Arquitectura y configuración

Para utilizar Ant es necesario primero tener instalado Java y después la distribución de Ant. Algo similar ocurre con Grunt para poder usarlo es requisito tener instalado node.js y el cliente de Grunt.

Tanto en Ant como en Grunt la configuración de la build del proyecto se hace a través de un archivo. Su nombre por defecto en ‘build.xml‘ en Ant y ‘Gruntfile.js‘ en Grunt

Tareas y objetivos

En esencia tanto en Ant como en Grunt se utilizan las tareas disponibles (‘tasks‘) para definir objetivos (‘target‘). Los objetivos contienen la configuración de nuestro proyecto utilizando estas tareas… ‘Copia estos ficheros‘, ‘borra los ficheros de este tipo‘, etc..

En Ant un target pueden depender de otros. Se ejecutarán los targets de los que depende antes que él y lo harán en el orden indicado. Esto permite crear un flujo de ejecución de tareas.

1
<project name="Ejemplo de build" default="ejecutar">
2
...
3
 <target name="ejecutar" depends="clean,crearDistro,crearWar"/>
4
...
5
</project>

En este caso ‘ejecutar‘ sería el target por defecto.

En Grunt se definen ‘alias‘ para el mismo resultado.

1
...
2
grunt.registerTask('default', ['clean', 'copy','uglify', 'concat','cssmin']);
3
..

Eso no significa que no puedas ejecutar targets individuales. Por ejemplo en Ant para lanzar el target clean sería, ejecutando en el directorio donde está el ‘build.xml

1
$ ant clean

o en Grunt, ejecutado en el directorio donde está el ‘Gruntfile.js

1
$ grunt clean

Variables externas

Tanto en Ant como en Grunt se pueden pasar variables al archivo de configuración desde línea de comandos, lo que resulta muy útil a la hora de configurar varios entornos del mismo proyecto en el Jenkins.

En Ant

1
$ ant −DdirEntorno=prepro

Usando así la variable en el buid.xml

1
<target name="clean">	
2
 <delete dir="${dirEntorno}"/>
3
</target>

En Grunt:

1
$ grunt −−dirEntorno=prepro

Y el Gruntfile.js

1
clean: {
2
 main: {
3
  src: ['<%= dirEntorno %>']
4
 }
5
}

… y en que se diferencian

Xml o Json/Javascript

Ant utiliza xml para definir la configuración. Esto hace que, sobre todo al principio, y con archivos de build complejos, que sea bastante rígido y engorroso.

Grunt en este aspecto utiliza json, un formato mucho más liviano. Además está embebido en un archivo javascript permitiendo utilizar este lenguaje con toda su potencia. Este aspecto le da mucho más flexibilidad que Ant. Aquí es donde se le notan los años a Ant y como muestra Gant,una alternativa en el mundo Groovy que ‘pasa’ del xml

Gestión de dependencias de las tareas

La filosofía de las dependencias de las tareas es completamente diferente. Ant ,de serie, trae diferentes tareas que ya se pueden usar. Esto no significa que se puedan utilizar otras tareas de terceros. Para esto se usa la tarea ‘typedef‘.

La gestión de dependencias de las librerías que son necesarias para ejecutar estar tareas es completamente ‘a mano’. No te queda otra que bajarte la librería he incluirla, o bien en tu distribución de ant (en el directorio ‘lib’) o bien dentro de tu home (en el directorio ‘.ant/lib‘)

En esto Grunt si que gana por goleada. Por defecto no viene con ninguna tarea predefinida, por lo que eres el que elige cual vas a utilizar, seleccionandola de su página de plugins. Probablemente existan varias posibilidades a la tarea que estás buscando. Después, para poder utilizarla, Grunt utiliza la potencia del gestor de paquetes de node.js, npm.

Por ejemplo, para instalar la tarea ‘uglify‘ que se utiliza para comprimir archivos js, se ejecuta el siguiente comando en el directorio donde este el Grutfile.js

1
$ npm install grunt−contrib−uglify −−save−dev

Esto incluye las dependencias en el ‘package.json‘ (Este fichero se crea al iniciar el proyecto ejecutando ‘npm init’)

Y para pode usar la tarea hay que añadir al Gruntfile.js:

1
...
2
grunt.loadNpmTasks('grunt−contrib−uglify');
3
...

Fácil y cómodo, aunque tampoco falto de problemas. Por ejemplo la tarea clean de repente dejo de funcionar en Windows, mientras que el Linux no había problema. El problema, una de las dependencias subió de versión… y dejo de funcionar. La solución fue añadir la dependencia a la versión que funcionaba directamente en el archivo ‘package.json‘. Espero tener tiempo para explicarlo mejor en otro post.

Epílogo, Conclusiones

Si eres de Back ,tienes algo de experiencia en Ant y quieres montar tu control de configuración para el Front que está basado en Javascript, trabajar con ‘Grunt’ te va a resultar muy familiar.

Son tecnologías diferentes, algunas tareas serán similares y otras más específicas  no encontrarás en Ant, pero la esencia es la misma, así que sin miedo.

Espero que os sirva.

M.E.

Vert.x: Mucho más que trabajar en Java como en node.js.. y en groovy, ruby,…

Prueba de concepto: Gateway con websockets y Gtalk utilizando Vert.x

[Vert.x Logo]La primera vez que oí hablar de Vert.x fue en la charla sobre el nuevo lenguaje Ceylon basado en la JVM que dio Gavin King  (la mente pensante detrás de Hibernate) el pasado febrero en MadridJUG. Comentó que para la web estaban enfocando sus esfuerzos en un framework asíncrono basado en Vert.x.

«¿Asíncrono…?» Ya se me levantó la ceja a lo ‘Sobera’ .. y lo que me dio ya la puntilla es cuando se puso a picar en directo un servidor web (puro live coding :-)) me olía todo tenía un aire a como se trabaja con node.js,.. Así que me dije…»esto de Vert.x me lo tengo que mirar«.

He de reconocer que con el título del post me he pasado… He estado dándole vueltas a uno que tuviera ‘punch‘… y me parece que he tirado por lo fácil. En realidad Vert.x es mucho más que un servidor web… Su ‘misión‘, ‘visión‘ y ‘valores‘ es soportar millones de conexiones concurrentes usando un número mínimo de hilos del sistema operativo (¿¿?? así lo asegura en su documentación), imposibles en un esquema multihilo típico.

¿Qué es Vert.x?

Vert.x es un framework basado en eventos que corre en la máquina virtual de Java. Hecho para que sea fácil de escalar y soporte a tolerancia a fallos. Pensado para que existan de una manera sencilla varios cores en diferentes JVM y que se intercomuniquen entre ellos. Vert.x resuelve la concurrencia siguiendo el modelo de actores y además asegura que no existirán bloqueos entre hilos. Otra de sus características es su ‘bus de eventos‘ que permite desacoplar tu aplicación en módulos y comunicarse entre ellos a través de mensajes. Y todo de manera asíncrona.

Vert.x es ‘Políglota‘, soporta JavaScript, Ruby, Groovy, Java o Python y con vista a soportar Scala, Clojure e incluso PHP. Ejecuta código fuente por lo que, por ejemplo, existe la posibilidad de arrancarlo con ficheros ‘.java’ sin necesidad de compilarlos.

Simple hilo ó multihilo

Llegaréis a la conclusión y la compartiré de que con el título lo he simplificando demasiado ¿Pero porque he hecho esta comparación? Porqué Node.js y Vert.x tienen funcionamientos similares.

En JavaScript no existe la concurrencia. Aunque esta afirmación pueda ser no del todo cierto, porque en html5 y en el cliente existe los workers, en JavaScript sólo existe un hilo y las operaciones que bloquean se ejecutan con llamadas asíncronas.

Y quizás esto, lo que parece su debilidad, es su virtud es esto lo que hace que node.js este valorado como un servidor con poca latencia cuando existe mucha carga .

La diferencia fundamental entre node.js (o Vert.x) y un sistema tradicional multihilo es que la máquina virtual de node utiliza un sólo hilo para atender todas las peticiones. El hilo se limita a recibir la petición y realizar llamadas asíncronas. No espera el resultado de la petición y continua con la siguiente. Más tarde recogerá el resultado para devolverlo al cliente.

Por el contrario en un sistema multihilo, por ejemplo en un despliegue tradicional de Java, existe un hilo para cada petición. Este se queda bloqueado mientras espera el resultado de una operación. Esto hace que bajo mucha carga existan muchos hilos y parte de ellos esperando, lo que repercute en la latencia.

Vert.x trabaja de igual manera, en este caso utilizando el modelo de actores en el que cada uno de los actores será un ‘verticle‘. En la documentación lo definen con una partícula de Vert.x y en la práctica es la manera de definir el código desplegado. Los ‘verticles‘ se pueden agrupar en módulos (lo más usual cuando la aplicación deja de ser trivial) y estos se pueden reutilizar.

…Y la prueba de concepto

Con Vert.x es muy sencillo crear servidores y clientes socket, ssl, http y websocket.

Necesitaba poder familiarizarme con la herramienta y tenía que hacer algo. Es entonces cuando recordé la presentación y demo muy, muy chula que hizo Iván López en MadridGUG utilizando una cuenta de Gtalk como boot. Así que basándome en esa idea he creado una prueba de concepto realizando un Gateway con WebSockets y Gtalk utilizando Vert.x. El proyecto es un proyecto Java.

Se utiliza una cuenta de Gtalk para poder crear una sala de chat entre usuarios que se conectan por Gtalk y usuarios que se conectan con un navegador mediante websockets.

Este ejemplo no explota todas las posibilidades  de Vert.x como el escalado y el bus de eventos pero si que despliega servidores web y de websocket. Me ha permitido conocer como se genera, se configura y se ejecuta un módulo. En definitiva, ha conseguido mi objetivo que como he dicho más arriba era familiarizarme con el framework

El proyecto lo he subido a GitHub y que es lo que hace y como está explicado en el README.md .

[Logo GitHub] Prueba de concepto: Gateway WebSockets y Gtalk utilizando Vert.x

README.md

Espero que os sirva.

M.E.

Mis primeros pasos de ‘newbie’ en AngularJs

Logo de AngularActualmente estoy involucrado en un proyecto en el que la arquitectura es un Backend de servicios web Rest (Java) y como Frontend una aplicación de una sola página (SPA Single-page application) hecha en AngularJs, utilizando el patrón MVC en el navegador.

Siempre he tenido ganas en saber algo más de como funciona este framework y no podía perder la oportunidad de echar una mano en el Front.

Para poneros en antecedentes, vaya por delante que en mi anterior trabajo apenas se utilizaba JavaScript en la vista. Así que ahí estaba yo, leyendo un manual de AngularJs con muchas ganas, intentando asimilar todos los nuevos conceptos de la herramienta y del lenguaje.

Aquí van mis primeras conclusiones sobre Angularjs de un ‘newbie’ que todavía tiene mucho que aprender.

Single-page application

La primera y quizás más importante es que me ha encantado el concepto. Te plantea una aplicación web de una manera diferente. Ya no piensas en peticiones web, formularios, etc, sino que piensas en eventos.

Al ser una aplicación de una sola página pasas de pensar en una aplicación web al uso a una que se parece más a .NET. La página se carga una vez (index.html) y es Angular quien se encarga según la url (en realidad ficticia con un ancla #) la que carga las diferentes ‘plantillas’ (vista, código html parcial) y los diferentes ‘controladores’ (funciones javaScript) que hace que se convierta en diferentes ‘páginas’.

No se carga una página por petición por lo que no es necesario guardar variables ‘volátiles’ en sesión, simplemente la almacenas en memoria. De hecho nosotros solamente almacenamos en cookies las credenciales de acceso.

A nivel de controlador defines las funciones que responderán a los diferentes eventos. El apretar un botón, un enlace, el cambio de foco de un campo de formulario,etc… Te centras en programar la lógica del evento, sin preocuparte como propagar el cambio para dibujar el resultado al usuario. De eso se ocupa Angular…

Conexión vista-controlador-backend ¿Programación reactiva?

Dos cosas me han llamado la atención para bien. Primero, la conexión entre la vista y el controlador.

Es directa. Si desde el controlador se cambia una variable esta se propaga directamente en la vista y se produce un cambio en lo que está viendo en usuario. También en el otro sentido, se puede saber cuando se ha modificado una entidad por el usuario y procesar este cambio en el controlador.

Si tenemos en cuenta que los campos de un formulario pueden constituir una entidad en su conjunto, es fácil imaginar lo sencillo que es propagar los cambios también al backend. No se si se puede llamar ‘Programación Reactiva‘ pero se le parece mucho… Un cambio realizado por el usuario se puede propagar al backend y un cambio en el backend se puede propagar y que lo vea el usuario.

Inyección de dependencias

La segunda es la inyección de dependencias que implementa Angular. Una aplicación se divide en módulos y en estos hay controladores, directivas (estas enfocadas más a la vista y a sus validaciones) y servicios. Todas las dependencias, por ejemplo, de un servicio que necesita un controlador, se definen a nivel de módulo de aplicación.

Siguiendo el ejemplo, para poder utilizar el servicio en tu controlador es tan sencillo como tener como argumento en la definición de tu función controlador un objeto servicio. Angular se encarga de instanciar correctamente el servicio que necesita el controlador resolviendo a su vez todas las dependencias.

A nivel de modulo se pueden definir, factorías, servicios y proveedores… Seguro que quien se han pegado en Java con Spring esto les suena algo…

Más cosas

Angular es un framework muy completo. En el core viene con directivas, filtros, y servicios predefinidos (como su propia implementación del patrón ‘promise‘ [$q]) que te hace la vida más fácil para un novatillo en el lenguaje y en el concepto como yo.

Tiene ‘interceptadores‘ que son parecidos a los filtros de Java que te permiten capturar la petición al servidor y por ejemplo enviar las credenciales de conexión sin tener que hacerlo en cada petición.

Angular está orientado a TDD. Es sencillo tanto hacer test unitarios como test de integración.

Conclusiones Pros y Contras

Ventajas

En esta fase de aprendizaje Angular me lo ha puesto sencillo. Me ha definido un marco estándar de trabajo y me ha ayudado a no tener la sensación de estar haciendo las cosas no también como debería.

Además me he encontrado con que la documentación es buena y en este momento ya hay mucha gente trabajando con él por lo que puedes encontrar solución a casi cualquier problema en Stackoverflow.

Otra de las ventajas es su rapidez de ejecución. Las peticiones al servidor son sólo llamadas ajax y plantillas parciales html. Realmente es destacable la rapidez con que se muestran todos los cambios.

Este tipo de arquitectura es fácilmente cacheable al ser todo archivos estáticos por lo que la escalabilidad del Front casi deja de ser un problema.

Por lo que escrito más arriba. El dinamismo que le da a la web es difícil de superar en otra arquitectura.

Contras

La dudas que me surgen es que cuando la aplicación empiece a crecer en ficheros js cuanto va a ser de pesada en la primera carga. A lo mejor cuando llegue habrá que plantearse una librería como RequireJs. Por rendimiento realmente no es necesaria, ya que Angular sólo carga en memoria lo que necesita.

Otra de las pegas es de usabilidad. Es muy común que en un mismo controlador manejes, por ejemplo, dos formularios y que juegues con su visibilidad para mostrar uno u otro. Si en el proceso el usuario aprieta el botón de ‘Atrás’ del navegador lo más probable es que le lleve a una sección de la web que no se corresponde con el anterior paso. Estas cosas hay que tenerlas en cuenta en el diseño de la aplicación.

Otro punto a tener en cuenta es a indexación por parte de los buscadores. Al ser todo javaScript y dinámico probablemente Google no podrá indexar la web.

El problema de IE8. Es el único navegador que no soporta HTML5 y que actualmente aún lo usa mucha gente, aunque afortunadamente cada vez menos. Para que Angular soporte IE8 hay que hacer ‘unas movidas’, que hace que es mejor plantearse indicar al usuario que utilice otro navegador.

Y por último es un cambio de concepto en el diseño de una página web. Por las inercias de las empresas, esto lleva a no pocas reticencias para que alguna se atreva a realizar su proyecto en Angular.

Para una web que siempre requiera un registro, y muy dinámica tipo red social, para mi las ventajas supera con mucho a los inconvenientes.

Espero que os sirva.

M.E.

Java versus JavaScript

Java versus JavaScript, reflexiones

Con la aparición de Node.js y la posibilidad de programar JavaScript en servidor se palpa entre los “javeros” cierta, no se encontrar la palabra, …¿preocupación?. La sensación es de “…nos están cambiando el agua…” y el comentario más oído es “… parece que es lo que se lleva ahora, no me gusta, pero habrá que aprenderlo…

A este desasosiego no ayudan post como los de PayPal (enlace ) en el que en resumen dicen que se pasan a JavaScript entre otras cosas porque es más rápido, necesitan menos gente y además se tira menos código. En respuesta a este post ha habido otros que han salido en defensa de Java y para poner coherencia en el tema (enlace)… y es que es lo que tienen casi todos los benchmark que pecan de partidistas.

En todas las ingenierías, pero mucho más en informática, tienes que estar en continua formación y estar al tanto de lo que se está haciendo. Es cierto que no podemos negar que también va todo un poco por modas y que es todo es cíclico. Parece que más tarde o más temprano siempre volvemos al mismo sitio que nos estamos moviendo en un circulo cerrado. Yo prefiero verlo más como una espiral… si la ves verticalmente parece que estás en el mismo punto,… pero que si la ves horizontalmente te das cuenta que estás en un nivel superior. Un ejemplo de esto son las nuevas bases de datos NOsql. Puede parecer que vuelven a las bases de datos pre-relacionales pero en realidad aportan muchas más cosas (escalabilidad, rapidez, big data y su explotación).

Pasa lo mismo con JavaScript hace mucho mucho tiempo que ha dejado de ser un lenguaje que sirve para poco más que hacer validaciones y hacer las “cosas bonitas” en la capa de presentación.

El gran problema de los “javeros” que dan sus primeros pasos en JavaScript, entre los que me incluyo, es que a la hora de enfrentarse al nuevo lenguaje piensan “… al final será algo como Java, con tipado dinámico y bueno con callbacks... ” y nada más lejos de la realidad, JavaScript es otra filosofía y en realidad casi casi comparte con Java poco más que el nombre y algunas palabras reservadas.

Creo que en el aprendizaje hay que enfrentarse con una actitud diferente y positiva. Me parece muy interesante el trabajo que ha realizado Micael Gallego en su blog (enlace), en el que explica su viaje en el aprendizaje del lenguaje desde el punto de vista de un programador Java y como a lo largo de los diferentes artículos va entendiendo la filosofía de JavaScript. A mi me ha ayudado mucho su lectura, así que no puedo más que recomendarla.

Reconozco que no soy experto en JavaScript y no puedo opinar en profundidad. Pero desde fuera creo que lo bueno y lo malo de JavaScript es que debido a su dinamismo, se pueden hacer las cosas de varias maneras. En Java por el contrario que es todo más cuadriculado.

De todas maneras creo que lo mejor es ser práctico, intentar conocer las debilidades y las fortalezas de cada lenguaje… Por ejemplo no me platearía hacer una aplicación de escritorio para Widonws en Java, para eso creo que es mucho mejor .NET. Por la misma razón me encontraría más a gusto, en aplicaciones de Backend en un proyecto con un equipo de trabajo numeroso, en un arquitectura Java que en una JavaScript, ya que al ser Java más “estricto” el código tendería ser más uniforme.

Lo que es cierto es que JavaScript permite hacer nuevas arquitecturas muy escalables y derivando gran parte de la responsabilidades al cliente. Angular.js es un framework que sigo muy de cerca. Sé que en algunos aspectos puede ser limitado pero prefiero la seguridad de basarme en algo estándar para montar una arquitectura MVC en el cliente.

Además JavaScript, junto con HTML5 se está convirtiendo en la única opción en la parte de navegador. Debido a las restricciones de seguridad que se están poniendo a los applets de java y a las extensiones y plugins. Son un autentico quebradero de cabeza por los agujeros de seguridad encontrados. Un ejemplo, Firefox a partir de su versión 26 no vienen habilitados por defecto los plugins excepto el de Flash.

Por eso en cosas “especiales” en la capa de cliente que por inercia antes te planteabas hacerlas con un applet o una extensión ahora enfocas tus esfuerzos en hacerlas en JavaScript… y se pueden hacer cosas muy, muy chulas.

Espero que os sirva.

M.E.

Configuración de entornos flexible en Spring utilizando SpEL

Introducción

En general cuando desarrollas una aplicación de cualquier tipo te enfrentas al reto de:

1) Configurar la aplicación de una manera sencilla

La configuración tiene que ser cómoda de modificar y tiene que estar centralizada (evitando que este desperdigada en multitud de ficheros de configuración las rutas, parámetros de conexión etc…)

2) Que un mismo ejecutable (jar o war en el caso de java) sirva para diferentes entornos.

Evitar tener que hacer un build para diferentes entornos (Además probablemente en un entorno corporativo no tengas acceso a las contraseñas y a las rutas de los recursos, etc.. de producción) A esto es a lo que me refiero con externalizable.

Spring es una poderosa y elegante herramienta que permite configurar una aplicación y establecer las dependencias entre sus clases a través de anotaciones o mediante archivos xml.

Pero esta potencia también puede llevar al peligro de que si no somos cuidadosos tengamos los parámetros de conexión, contraseñas, URL y rutas desperdigadas en varios archivos.

Para esto Spring ofrece herramientas que permiten cargar propiedades y valores de archivos ‘.properties‘ y además estos archivos pueden encontrase fuera del jar o del war e incluso pueden estar cifrados. Con esto se soluciona la centralización y la externalización.

El problema

Hecha la introducción paso a explicar el problema: Había que configurar una aplicación web en Spring en diferentes entornos en una misma máquina (un entorno en un Jetty y otro en un Tomcat), por lo que había que externalizar la configuración y además al estar en la misma máquina no servía que la ruta al fichero de configuración fuera fija (de estilo ‘/home/usuario/aplicacion.properties‘)

La solución

Ha sido utilizar el bean ‘PropertyPlaceholderConfigurer‘ de Spring y utilizar SpEL (Spring Expression Language) de esta forma:

01
<?xml version="1.0" encoding="UTF-8"?>
02
<beans xmlns="http://www.springframework.org/schema/beans"
03
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
05
 >
06
...
07
 <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
08
  <property name="locations" value="#{systemProperties['aplicacion.config'] != null ? 'file:' + systemProperties['aplicacion.config'] :'classpath:'}application.properties"/>
09
 </bean>
10
 ...
11
 </beans>

Código 01. Configuración xml de ‘propertyConfigurer’

La clave está en la línea 8. Si está definida la propiedad del sistema ‘aplicacion.config‘ buscará en el sistema de ficheros, el archivo de configuración ‘aplicacion.properties‘ en la dirección que indica su valor. Si no, busca el ‘aplication.properties‘ en el classpath (es decir dentro del war), por lo que este sería el archivo de configuración de la aplicación por defecto.

Un ejemplo del contenido de ‘aplicacion.properties‘ podría ser

1
...
2
aplicacion.config.pathfiles=/home/miguel/aplicacion/tmp
3
...

Código 02. Ejemplo de contenido de aplicacion.properties

Y la manera de usarlo dentro de la configuración xml de Spring sería:

01
<?xml version="1.0" encoding="UTF-8"?>
02
<beans xmlns="http://www.springframework.org/schema/beans"
03
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
05
 >
06
...
07
 <bean id="utilFichero" class="com.logicaalternativa.ejemplo.UtilFicheroImp"> 
08
  <property name="directorio" value="${aplicacion.config.pathfiles}"/>
09
 </bean>
10
 ...
11
 </beans>

Código 03. Ejemplo de como se utilizan los valores definidos en el archivo de configuración

Ya sólo me queda indicar como se define esa propiedad. En el Tomcat un buen sitio es el ‘catalina.properties de su directorio ‘config‘. Se definiría así:

1
...
2
aplicacion.config=/home/miguel/config-aplicacion-tomcat/
3
...

Código 04. Configurando el Tomcat

O directamente definiendo la propiedad al arrancar la máquina virtual. Por ejemplo si tu proyecto tiene configurado el plugin,  arrancando el jetty embebido de mvn de la siguiente manera:

1
mvn -Daplicacion.config=/home/miguel/config-aplicacion-jetty/ jetty:run

Código 05. Ejemplo al arrancar el jetty de mvn

En los ejemplos en los dos directorios ‘/home/miguel/config−aplicacion−jetty/‘ y ‘/home/miguel/config−aplicacion−tomcat/‘ se encontrarían sendos archivos ‘aplicacion.properties‘ cada uno configurados con los valores para cada entorno.

Espero que os sirva.

M.E.

De despliegue continuo y de responsabilidad personal

Despliegue continuo con Jenkins, Maven, Selenium y Junit

Están surgiendo nuevos conceptos como el despliegue continuo y la responsabilidad personal que están cambiando la forma de desplegar en un entorno de producción.

Digamos que la “manera tradicional” es decidir que funcionalidades van a ir en cada versión codificarlas, probar esa versión y por fin el despliegue en producción. Quién se haya enfrentado a esto sabe el estrés que produce el despliegue de una nueva versión sobre todo si conlleva bastantes cambios, …si ya sabemos que todo está probado, que no va a pasar nada, pero el mal trago del despliegue no te lo quita nadie … “¿irá todo bien? ¿no irá?

Despliegue continuo

¿Cómo están haciendo las cosas empresas como Facebook? … pues simplemente no hay versiones. Sigue leyendo

Dar valor a los tweets: Interés, difusión, audiencia,… trasteando con el API de Twitter

No se puede decir que sea un ‘social media‘, pero de un tiempo a esta parte Twitter se ha convertido para mi en una fuente de información esencial y casi imprescindible.  Tiene un pero, a veces te pierdes entre toda la información que te llega… Pensando siempre ‘alternativamente‘ me surgieron estas preguntas:

¿Sé puede hacer un poco más social una red social como Twitter?… ¿Por qué no mostrar de una manera sencilla como han valorado los demás usuarios el tweet que estás leyendo?…¿cuánto se ha difundido?…. ¿Sé puede estimar a cuanta gente a llegado?

Lo que me dio pie fue que, para 747mx.com, un proyecto hermano de Lógica Alternativa, quería incorporar la información de los tweets pero el widget oficial me fastidiaba el diseño, no sabía como encajarlo. La solución pasaba en estudiar el API REST de Twitter. Puesto manos a la obra me di cuenta del mundo de posibilidades que permitía,… apareció en mi el físico que llevo dentro, ese el que le gusta lo de los coeficientes y esas cosas, la cosa se lío y el resultado fue el siguiente. Sigue leyendo

Apuntes sobre diseño centrado en el usuario, Experiencia de usuario, Usabilidad, …

Usabilidad, Experiencia de Usuario, Diseño Centrado en el Usuario, … son palabras que se nos han hecho familiares a raíz de la evolución de la web y sobre todo con la aparición de los nuevos dispositivos móviles.

Esto ha hecho que el técnico experto en estas materias sean uno de los perfiles más valorados en el mercado. Existen otros conceptos relacionados, unos a nivel teórico y otros unidos a la práctica profesional, que son elementos claves y que engloban lo que se llama interacción persona-ordenador (IPO).

En mi vida profesional he utilizado estas técnicas y conceptos. Últimamente me he enfrentado a ellos desde la visión académica. Para poder fijar ideas y tener una visión clara y concisa de esta apasionante disciplina me obligado a escribir este artículo.

Me centraré más en el Diseño Centrado en el Usuario, en que consiste, cuales son sus ventajas, sus etapas, que herramientas se usan y su integración con la metodologías ágiles. Pero antes y para enmarcarlo en su contexto doy unas pequeñas pinceladas sobre conceptos como Interacción persona-ordenador, Experiencia de usuario y Usabilidad. Sigue leyendo

OpenStreetMap-OpenLayers-OpenRouteService la ‘alternativa’ a Google Maps

Realmente no te das cuenta de la dependencia que tienes de los servicios de Google. Piensas que puedes disponer de ellos porque además de ser potentes son gratis… hasta que dejan de serlo.

[Mapa OpenLayers]Me ha ocurrido en el pasado, en un proyecto personal (747mx.com) que utilizaba el traductor de Google. Era gratis hasta un número de peticiones, suficientes para la pretensiones de esa página y pasó a ser de pago desde la primera petición. Algo que no me podía permitir en ese portal.

Así que cuando en una entrevista a Javier De La Torre uno de los fundadores de Vizzuality señalaba a OpenStreetMap como alternativa seria a Google Maps me dije ‘… esto me lo tengo que mirar‘ .

Para saber como funciona de verdad, lo que me propuse fue migrar un código que tenía con el API de Google Maps en 747mx.com. Basarme en él y hacer lo mismo en OpenStreetMap utilizando lal librería OpenLayers y el servicio de geolocalización de OpenRouteService.org. Sigue leyendo

El siguiente nivel, Agile Coach Competency Framework

Para mi son tiempos de cambios, algunos “forzados” y otros “provocados”. Ahora tengo la necesidad de saber que es lo que está pasando en este mundillo de la programación y la informática. Siempre me ha interesado las metodologías ágiles, así que el pasado miércoles asistí a un seminario/taller organizado por Agile Madrid y dirigido por Ángel Diaz Maroto.

En este seminario presentó el Framework de Competencias de Agile Coach ideado por Lyssa Adkins. La idea de fondo de este marco de trabajo es intentar conseguir transformar a un grupo de personas en un grupo de alto rendimiento. Sigue leyendo

Hibernate 4: obtener el objeto Connection relacionado con la sesión

Una nota rápida de un problema con el que me he pegado hace poco.

Necesitaba lanzar una función de BBDD (Oracle) desde Hibernate manteniendo la transacción.  Para lanzar la función desde jdbc, en las versiones anteriores de Hibernate era muy intuitivo obtener el objeto Connection relacionado con la sesión pero en Hibernate 4 ha cambiado el interface Session. Sigue leyendo

Cambio de color a barra de progreso en Android

AndroidLa duración de manga de motocross se mide en minutos + 2 vueltas. A nivel regional son 20 minutos + 2 vueltas, a nivel nacional 30 minutos + 2 vueltas, etc… Entrenando lo normal es hacer mangas de la misma duración, o de menos tiempo (mejorando la rapidez) o de más (mejorando el fondo). Las motos de cross no tienen instrumentación y obliga a que una persona desde fuera indique al piloto cuanto le queda de manga.

¿Qué por qué cuento esto? Desde hace bastante tiempo mi hermano y yo corremos motocross a nivel regional. Bueno en realidad mi hermano es el “quemao” y siempre andaba quejándose de que sus entrenos no podían ser de calidad porque no sabía el tiempo que llevaba, no sabía cuando apretar, cuando regular, bla, bla, bla…

Ahí salió el “hermano informático”, surgió el problema de cambiar el color a una barra de progreso y echarme a la cara el peor ‘stakeholder‘ que he tenido en mi vida … Sigue leyendo