El paradigma de la programación reactiva: claves para entenderla


¿Quieres saber en qué consiste la programación reactiva? ¿Te gustaría conocer la manera correcta de trabajar con datos asíncronos y operar con ellos de una forma escalable? Esta combinación nos da la clave para poder trabajar este poderoso concepto y descubrir cuáles son las formas de implementar la programación reactiva y Javascript.

Un paradigma para operar y manejar streams de datos asíncronos; quizás sea esta la definición más extendida sobre lo que es programación reactiva. Diez palabras, pero varios conceptos importantes a destacar:

  • Paradigma: define un marco de trabajo o forma de programar.
  • Streams: flujo de datos.
  • Datos asíncronos: no sabemos cuándo se producirán o cuándo llegarán a nuestro sistema.

Con esto, ya podemos empezar a hacernos una idea de qué es la programación reactiva: unas directrices de cómo debemos programar nuestro sistema para trabajar con datos que no sabemos cuándo se generan, pero que queremos reaccionar y actuar en consecuencia. Esto parece sencillo de enunciar, sin embargo, ¿por qué es tan difícil de entender? Esto se debe a que mezcla diversos conceptos no tan sencillos:

  • Programación funcional.
  • Patrón observer (más info, aquí).
  • Patrón iterator (más info, aquí).

La reactividad, al ser un paradigma (como la programación funcional), puede ser aplicada a más de un lenguaje. Tanto es así, que se han creado librerías para facilitar el desarrollo (y la vida de los desarrolladores), ahorrando tiempo, aumentando la productividad y construyendo sistemas más robustos y escalables.

Reactive eXtensions es el nombre que recibe (ReactiveX o RX directamente) la librería, y las implementaciones más conocidas a día de hoy son las de JavaScript (RxJS), Java (RxJava) o Scala (RxScala) entre muchas otras (aquí puedes consultar el listado completo).

Asincronía (o no sé cuándo llegará)

En nuestras aplicaciones, la gran mayoría de eventos que se producen son de naturaleza asíncrona, como un click de ratón, un envío de información desde backend o los caracteres que escribimos en un campo de búsqueda. Todas esas casuísticas tienen tres características en común:

  • No sabemos con certeza cuándo se producirán (ni momento ni frecuencia).
  • Queremos reaccionar ante ellos cuando se produzcan, bien sea operando con ellos o filtrándolos.
  • Pueden ocurrir (clicks sucesivos) y cambiar (criterio de búsqueda) más de una vez a lo largo del tiempo.

Esos cambios y esa continuidad a lo largo del tiempo dan lugar a que sean “observables”. Y precisamente, ese es el nombre de uno de los objetos más comúnmente utilizado en Rx.

Otro de los ejemplos típicos de sistema o aplicación reactiva es una hoja de cálculo. Introducimos dos valores y los sumamos… ¿qué sucede?

¿Cómo es eso? Debido a que Excel es capaz de “observar” esos cambios que se producen en la suma, y en cuanto recibe un nuevo número a sumar por parte del usuario, ejecuta de nuevo la suma. Es decir, ha reaccionado ante ese cambio asíncrono.

Si volvemos al ámbito de cualquiera de nuestras aplicaciones, esa observación se produce, como hemos dicho anteriormente, sobre un elemento que emite datos (una fuente de información). Pongamos como ejemplo un contador que comienza en cero y cuando llega a sesenta se reinicia de nuevo a cero (uhm… ¡y suena a tic-tac!). ¿Qué tenemos? Valores que una fuente emite y pueden ser observados (cada segundo habrá un valor nuevo). A cada valor recibido actuaremos en consecuencia: presumiblemente, actualizar alguna variable para reflejar el nuevo valor.

Suena bien… pero hay situaciones más complejas, como una petición a backend donde puede que tenga éxito o se produzca un fallo. Por ello, si va todo bien, genial; pero, ¿y si se produce un error? No hay problema, ya que el propio emisor puede no sólo emitir datos, sino también errores para indicarnos que algo no ha ido bien y nosotros podamos codificar la lógica necesaria para actuar en consecuencia.

Pero la programación reactiva nos permite poder llegar más allá. Vamos a imaginar que tenemos que leer un fichero línea a línea y hacer un procesamiento. Algo sencillo y común, ¿no? Bien, si leemos una línea, se emite la línea leída; si encuentra un error, se emite un error; pero… ¿cómo sabemos cuándo hemos terminado de leer el fichero? ¡Tachán! ¡Rx de nuevo al rescate! Un stream, como hemos visto en el ejemplo del reloj, puede ser infinito, pero pueden existir otros -como el fichero- que en algún momento se termina. Cuando esto se produzca, también seremos notificados para actuar convenientemente.

La potencia sin control, no sirve de nada

Hasta ahora sólo hemos visto el iceberg desde lejos, y si profundizamos en el mundo de los operadores de Rx sólo estaremos descubriendo su punta. Si vemos la potencia que pueden tener los streams de datos y la capacidad de gestionarlos, querremos llegar más allá y operar con ellos: combinar dos streams distintos, concatenarlos, filtrar datos, aplicar un delay, etc. Aquí es donde empieza la potencia de la reactividad.

Una ayuda visual y muy intuitiva para conocer los operadores y cómo funcionan puedes encontrarla aquí.

Pero, ese no es el final

Sólo hemos acariciado a la reactividad en su más pura y agnóstica acepción. Toda esa potencia se dispara cuando frameworks como Angular evidencia sus ventajas y lo utiliza internamente. Rx también está presente en multitud de las principales librerías, no sólo para en lenguaje particular, sino para más de uno de los mencionados anteriormente.

Enorme Potencial

Aunque este paradigma existe desde hace casi diez años, no ha sido hasta ahora cuando ha comenzado a obtener fama gracias a todo el potencial que nos ofrece. Merece la pena darle un vistazo y tirar alguna línea de código para probar y descubrir por nosotros mismos las ventajas anteriormente expuestas. No te arrepentirás.