No es la primera vez que hablamos de decoradores en este blog, pero sí es la primera vez que vamos a hablar de Reactive Programing. Una advertencia antes de comenzar: se trata de un post algo más técnico que lo habitual. Esto requiere, de entrada, que deba suponer que conoces perfectamente la librería RxJS. De otro modo, este post se alargaría demasiado.

Así pues, sentadas las bases de lo que doy por supuesto que ya sabes, voy a explicar un pequeño proyecto en el que he estado trabajando unos días atrás.

El problema

Imagínate que estás trabajando en una base de código completamente orientado a objetos -- algo muy usual -- y que deseas tener un observable sobre las llamadas y respuestas que se hagan a un método concreto de una instancia de tu clase. Es decir, tienes una clase como la que sigue:

class Person {  
    greeting(name){
        return `Hi ${name}`;
    }
}

const person = new Person();  

y quieres tener un observable sobre todas las llamadas que se hagan al método person.greeting(). Quieres, además, saber con qué argumentos se ha llamado y cuál ha sido la respuesta del método. Es más, aun cuando lo que devuelva ese método sea una promesa, quieres obtener directamente el valor de la promesa y no la promesa en sí.

La solución

Para resolver este problema he desarrollado Streamify, un decorador que se encarga de crear streams de todos los métodos que necesites observar de tu clase.

Esto quiere decir que a la clase Persona la definimos como antes, pero le agregamos nuestro decorador:

@streamify('greeting', 'greetingAsync')
class Person {  
    greeting(name){
        return `Hi ${name}`;
    }

    methodWithOutStream(){
      return 'I don't have a stream for my calls'
    }

    greetingAsync(name){
        return new Promise( resolve => setTimeout(resolve(`Hi ${name}`), 100) );
    }
}

Así, obtenemos una nueva entrada en el prototype de la clase: $ . Esta es la puerta de entrada a todos los observables que hayamos definido en nuestro decorador. Funciona de la siguiente forma:

person.$.greeting.subscribe(({params, result}) => {  
    console.log(`I was called with ${params} and I replied "${result}"`);
    // => I was called with ['Carlos'] and I replied "Hi Carlos"
});

person.$.greetingAsync.subscribe(({params, result}) => {  
    console.log(`I was called with ${params} and I replied "${result}"`);
    // => I was called with ['CarlosAsync'] and I replied "Hi CarlosAsync"
});

person.greeting('Carlos');  
person.greetingAsync('CarlosAsync');  

Como puedes ver, se pueden hacer muchas cosas interesantes con una decorador así. Por ejemplo, se pueden tener sincronizadas dos partes de tu aplicación sin que haya una comunicación directa o generar un sistema de logger no intrusivo en el código.

Si te ha gustado este post, difunde la palabra. Tampoco dudes en dejar comentarios u observaciones. ¡Gracias! :)

Suscríbete a mi lista de correo

* Campos obligatorios