Programación Reactiva


Introducción

¿Qué es la programación reactiva?

Es un paradigma enfocado en el trabajo con flujos de datos finitos o infinitos de manera asíncrona, es decir que las aplicaciones reaccionan a los cambios ejecutando una serie de eventos.

Este paradigma está enfocado principalmente en el manejo de flujos de datos asíncronos y en el uso eficiente de recursos. Los sistemas reactivos reaccionan a los datos que fluyen continuamente ejecutando una serie de eventos, esto es porque siguen el patrón de diseño Observer; cuando hay un cambio de estado en un objeto, los otros objetos son notificados y actualizados. Por lo tanto, en lugar de estar preguntando los cambios, los eventos se realizan de forma asíncrona para que los observadores puedan procesarlos.

La motivación detrás de este nuevo paradigma procede de la necesidad de responder a las limitaciones de escalado presentes en los modelos de desarrollo actuales, que se caracterizan por su desaprovechamiento del uso de la CPU debido al I/O, el sobreuso de memoria (enormes thread pools) y la ineficiencia de las interacciones bloqueantes.

Para el año 2018, la programación reactiva y la programación basada en eventos no eran paradigmas de programación, como la programación imperativa u orientada a objetos, sino que eran ortogonales a ellos. La programación dirigida por eventos se implementa dentro de un paradigma paradigma existente. Por lo tanto, se puede utilizar la programación orientada a eventos con un lenguaje orientado a objetos o un lenguaje funcional. La programación reactiva es un caso específico de la programación de eventos que con el paso de los años ha ido ganando importancia. Esto se puede ver en la siguiente figura:

Características

Actores

Flujo de datos: Son datos que se van modificando cada cierto tiempo, y que puede tener interés observar en tiempo real.

Observable: Un componente que puede ser observado, y que se encargará de informar cuando ese flujo de datos se modifique.

Observador: Es el elemento que observa esas modificaciones. Cuando el dato se modifica, se notifica al componente que lo está utilizando. Normalmente este observer necesita suscribirse cuando quiere empezar a recibir datos, y desuscribirse cuando ya no le interesan más esos datos.

Dispatchers: En cada framework de programación reactiva se llaman de una forma distinta, pero básicamente son un conjunto de hilos donde se van a ejecutar las operaciones, y unas reglas que optimizan su uso para ser lo más eficientes posibles.

Operadores: Existen montones de operadores que nos permiten modificar y combinar flujos de datos, y conocerlos todos es muy complicado. Dependen de las librerías.


Manejo de flujos de datos

Basado en datos que fluyen continuamente, los sistemas reactivos reaccionan a los datos ejecutando una serie de eventos.


Patrón de Diseño Observer

La programación reactiva sigue el patrón de diseño Observer; cuando hay un cambio de estado en un objeto, los otros objetos son notificados y actualizados acorde. Por lo tanto, en lugar de sondear eventos para los cambios, los eventos se realizan de forma asíncrona para que los observadores puedan procesarlos.


Uso eficiente de recursos

Utilizando E/S asíncrona, la idea es simple: disminuir el uso ineficiente de recursos usando recursos que de lo contrario estarían inactivos, ya que permanecen a la espera de actividad de E/S.


Liberación del cliente

Los nuevos datos se notifican a los clientes en vez de tener que solicitarlos, debido a que la E/S asíncrona invierte el diseño normal del procesamiento de E/S. Este enfoque libera al cliente para hacer otras cosas mientras espera nuevas notificaciones.


Demasiadas notificaciones

Existe el riesgo de que demasiadas notificaciones desborden al cliente.


Rechazar el trabajo que no se puede manejar

Un aspecto fundamental de control de flujo en sistemas distribuidos es que el cliente debe ser capaz de rechazar el trabajo que no puede manejar. En la programación reactiva, la capacidad del cliente para señalizar cuánto trabajo puede manejar se llama contrapresión.

Patrón de Diseño Observer

En este patrón, tenemos un objeto Observable al que podemos suscribirnos, y cada vez que haya un cambio en su valor seremos informados. A esto se le conoce como Publicador-Suscriptor.

Analogía del patrón observador de la vida cotidiana: suscripción al boletín de un portal técnico

Finalidad

El patrón Observer trabaja con dos tipos de actores: por un lado, el sujeto, es decir, el objeto cuyo estado quiere vigilarse a largo plazo. Por otro lado, están los objetos observadores, que han de ser informados de cualquier cambio en el sujeto. Sin el patrón Observer, los objetos observadores tendrían que solicitar al sujeto regularmente que les enviase actualizaciones acerca de su estado (status updates). Cada una de estas solicitudes conllevaría tiempo de computación y requeriría, además, ciertos recursos de hardware.


Funcionamiento y estructura

  1. El Notificador envía eventos de interés a otros objetos. Esos eventos ocurren cuando el notificador cambia su estado o ejecuta algunos comportamientos. Los notificadores contienen una infraestructura de suscripción que permite a nuevos y antiguos suscriptores abandonar la lista.
  2. Cuando sucede un nuevo evento, el notificador recorre la lista de suscripción e invoca el método de notificación declarado en la interfaz suscriptora en cada objeto suscriptor.
  3. La interfaz Suscriptora declara la interfaz de notificación. En la mayoría de los casos, consiste en un único método actualizar. El método puede tener varios parámetros que permitan al notificador pasar algunos detalles del evento junto a la actualización.
  4. Los Suscriptores Concretos realizan algunas acciones en respuesta a las notificaciones emitidas por el notificador. Todas estas clases deben implementar la misma interfaz de forma que el notificador no esté acoplado a clases concretas.
  5. Normalmente, los suscriptores necesitan cierta información contextual para manejar correctamente la actualización. Por este motivo, a menudo los notificadores pasan cierta información de contexto como argumentos del método de notificación. El notificador puede pasarse a sí mismo como argumento, dejando que los suscriptores extraigan la información necesaria directamente.
  6. El Cliente crea objetos tipo notificador y suscriptor por separado y después registra a los suscriptores para las actualizaciones del notificador.

Ventajas

Uso eficiente de recursos

En la programación asíncrona clásica, un hilo que se ejecuta pasa la mayor parte de su tiempo esperando. El hilo que se ejecuta envía una petición, por ejemplo, a la base de datos, luego espera durante un periodo de tiempo la respuesta con los datos, cuando finalmente obtiene una respuesta, continúa trabajando y al finalizar vuelve a estar disponible para otra ejecución. Lo que hace que este recurso se esté usando de forma ineficiente.

En la programación reactiva cada hilo se centra en enviar la solicitud, y luego vuelve a estar disponible para otra ejecución. Cuando la respuesta llega, este mismo hilo, u otro, puede recoger y procesar la respuesta. En pocas palabras: trata de asegurarse de que todos los hilos estén siempre trabajando en algo, y no esperando.

La utilización eficiente de los recursos deriva en gastar menos dinero en servidores y centros de datos. La promesa de la programación reactiva es que se puede hacer más con menos. Específicamente se puede procesar cargas de trabajo más altas con menos hilos.


Mantenibilidad

La combinación de flujos con potentes operadores resuelve problemas complejos de una manera muy declarativa. El código parecerá conciso y directo; en lugar de ramificaciones verbales y lógica imperativa, se tienen combinaciones de operadores que facilitan hacerse una imagen mental del funcionamiento. Lo cuál, hace más sencillo que cualquier persona diferente al desarrollador original, pueda modificar o mejorar algún aspecto en el código más rápido.


Escalabilidad

Usando programación reactiva se obtiene una implementación débilmente acoplada, que tiende a aislar los fallos y que tiene la capacidad de escalar horizontalmente y de forma rápida, permitiendo el manejo de grandes cantidades de eventos, que pueden ser millones o billones de eventos, muy útil para “Big Data”.


Facilidad en el manejo del backpressure

Se pueden dar situaciones donde un Notificador genere más elementos de los que un Suscriptor puede consumir. Lo cual genera que el proceso de convertir esa entrada en salida se resista de alguna manera. En la mayoría de los casos esa resistencia es la velocidad de cálculo.

Para manejar estas situaciones en la programación reactiva se han establecido los siguientes mecanismos: Los suscriptores pueden indicar el número de datos que quieren o pueden procesar, de manera que el notificador nunca les enviará más de n cantidad de elementos. Los notificadores pueden aplicar diferentes operaciones como buffers o descartar algunos datos, para evitar saturar a los suscriptores lentos.

Desventajas

Mayor costo en memoria

Este paradigma es más costoso en memoria, porque requiere mayor espacio en memoria para almacenar los flujos de datos (ya que se basa en flujos a lo largo del tiempo).


Curva de aprendizaje

La curva de aprendizaje es grande para dominar la programación reactiva. No sólo se está expuesto a un ecosistema completamente nuevo con nuevas APIs, sino que también se necesita tiempo para procesar este paradigma diferente de programación con streams, que puede ser bastante diferente de un estilo de código de escritura tradicional (por ejemplo, en comparación con la programación imperativa). También puede que se necesite aprender de nuevas herramientas para las pruebas unitarias y dominar conceptos adicionales como los diagramas de mármol, que ayudan a modelar adecuadamente los flujos de datos. Además, hay una falta de recursos buenos y sencillos para aprender.


Depurar no es más fácil

Del mismo modo que en la programación clásica donde nos podemos encontrar con un espagueti de funciones. En la programación reactiva también se puede encontrar un espagueti de flujos y no saber qué camino tomar. Con las funciones simples suele ser más sencillo hacer una depuración del código, dado que se componen secuencialmente. Con los flujos, puede que no sea tan sencillo porque no existe tal cosa como un flujo que invoca a otro flujo. En su lugar, se tiene un flujo que se conecta con otros flujos de maneras mixtas dependiendo de los operadores que los unen.


Acumulación de delay

Los sistemas reactivos pueden acumular fácilmente retrasos debido a un número excesivo de procesos vinculados al flujo.

Evolución del paradigma

Los orígenes de la programación reactiva se remontan, probablemente, a la década de 1970, pero esta empezó a resonar en la década del 2010, al mismo tiempo que comenzó el auge de los microservicios y los procesadores multinúcleo.

Desde entonces, dicho paradigma ha evolucionado de manera significativa y, por este motivo, las librerías que lo implementan pueden clasificarse en generaciones de acuerdo a su grado de madurez, según la categorización propuesta por el autor David Karnok en el año 2016, la cual se describe a continuación:


Generación 0

Consiste, principalmente, de la API java.util.Observable y de otras API basadas en callbacks, tal como addXXXListener en Swing, AWT y Android.

Los inconvenientes que presentaban las herramientas de esta generación eran las deficiencias de composición y el hecho de que, por sí mismas, resultaban bastante limitadas.


Primera generación

Una vez que Erik Meijer y el equipo de Microsoft reconocieron y abordaron las deficiencias, nació la primera generación de bibliotecas de programación reactiva: Rx.NET alrededor de 2010, Reactive4Java en 2011 y las primeras versiones de RxJava en 2013.

Algunos de los inconvenientes encontrados consistieron en que, al implementar las interfaces IObservable/IObserver no se podían cancelar las secuencias en ejecución usando el operador take(), además del problema de la falta de backpressure.


Segunda generación

El equipo de RxJava identificó estas deficiencias y se diseñó una nueva arquitectura. En esta se introdujo: la clase Subscriber, la cual puede decir si está interesada en más eventos o no; la interfaz Producer, para señalar la cantidad de elementos que un Subscriber puede procesar a la vez, y el método lift(), que permite una transformación funcional entre Subscribers.

No obstante, esta solución era un poco torpe y limitaba algunas optimizaciones, además de que era incompatible con los puntos de vista de otras bibliotecas reactivas que comenzarían a surgir más adelante.


Tercera generación

Ingenieros de varias compañías se juntaron y crearon la especificación Reactive Streams. Algunos ejemplos de librerías que pertenecen a esta generación son RxJava 2.x, Project Reactor y Akka-Streams.


Cuarta generación

Algunas de estas librerías se reimplementaron, lo cual condujo al establecimiento de la librería reactive-streams-commons, a la construcción de ciertos operadores fundacionales y al diseño de componentes de optimización que pasaron a recibir el nombre de operator-fusion. Comparada con la generación anterior, aunque lucen similares en el exterior, en el interior poseen cambios significativos que permitieron una reducción aún mayor de los gastos generales.



Adicionalmente, este autor especula que, de la quinta generación en adelante, la arquitectura de Reactive-Streams requeriría ciertas extensiones para soportar operaciones reactivas de entrada y salida en la forma de secuencias bidireccionales, entre otros cambios que, en ese punto, estaban abiertos a discusión.

El término "Reactive"

La programación reactiva, al tratarse de un paradigma emergente que está en constante actualización, suele confundirse con otros conceptos que también llevan la partícula "reactive" en su nombre. Este término es muy amplio y, aunque algunas personas pueden creer que las extensiones reactivas, los streams reactivos, los sistemas reactivos, y la programación funcional reactiva (entre otras muchas) sean lo mismo, la verdad es que existen diferencias importantes a considerar en todas ellas.


Programación Funcional Reactiva (FRP)

Fue definida en 1997 por Conal Elliott y Paul Hudak. De acuerdo con una presentación que Elliott dio en el año 2015, titulada "The essence and origins of FRP", el término había sido empleado incorrectamente para describir sistemas como Elm, Bacon y extensiones reactivas. La diferencia principal entre la FRP y la programación reactiva es que la primera opera en valores que cambian continuamente a través del tiempo, mientras que la segunda opera en valores discretos que se emiten a través del tiempo. La conferencia puede verse a continuación:


Extensiones y Streams Reactivos

Las extensiones reactivas, mejor conocidas como "ReactiveX" son un conjunto de herramientas que implementan el paradigma de la programación reactiva (estas se cubrirán a detalle más adelante).

Sin embargo, debido a que estas contienen una gran variedad de librerías y a la falta de interoperabilidad entre ellas, surgieron los Reactive Streams. Esta fue una iniciativa creada para proveer un estándar para las extensiones reactivas y que lidiara con el procesamiento de flujo (stream) asincrónico con contrapresión sin bloqueo (non-blocking backpressure); es decir, se buscó unificar las librerías ya existentes.


Sistemas reactivos

Los sistemas reactivos son un conjunto de principios de diseño arquitectónico para construir sistemas modernos que estén bien preparados para satisfacer las crecientes demandas que enfrentan las aplicaciones hoy en día. Sus especificaciones se pueden encontrar en línea bajo el nombre de "Manifiesto Reactivo", tal como sigue a continuación:

Los Sistemas Reactivos son:

Responsivos: El sistema responde a tiempo en la medida de lo posible. La responsividad es la piedra angular de la usabilidad y la utilidad, pero más que esto, responsividad significa que los problemas pueden ser detectados con rapidez y tratados efectivamente. Los sistemas responsivos se enfocan en proveer tiempos de respuesta rápidos y consistentes, estableciendo límites superiores confiables para así proporcionar una calidad de servicio consistente. Este comportamiento consistente, a su vez, simplifica el tratamiento de errores, aporta seguridad al usuario final y fomenta una mayor interacción.

Resilientes: El sistema permanece responsivo frente a fallos. Esto es aplicable no sólo a sistemas de alta disponibilidad o de misión crítica - cualquier sistema que no sea resiliente dejará de ser responsivo después de un fallo. La resiliencia es alcanzada con replicación, contención, aislamiento y delegación. Los fallos son manejados dentro de cada componente, aislando cada componente de los demás, y asegurando así que cualquier parte del sistema pueda fallar y recuperarse sin comprometer el sistema como un todo. La recuperación de cada componente se delega en otro componente (externo) y la alta disponibilidad se asegura con replicación allí donde sea necesario. El cliente de un componente no tiene que responsabilizarse del manejo sus fallos.

Elásticos: El sistema se mantiene responsivo bajo variaciones en la carga de trabajo. Los Sistemas Reactivos pueden reaccionar a cambios en la frecuencia de peticiones incrementando o reduciendo los recursos asignados para servir dichas peticiones. Esto implica diseños que no tengan puntos de contención o cuellos de botella centralizados, resultando en la capacidad de dividir o replicar componentes y distribuir las peticiones entre ellos. Los Sistemas Reactivos soportan algoritmos de escalado predictivos, así como Reactivos, al proporcionar relevantes medidas de rendimiento en tiempo real. La elasticidad se consigue de forma rentable haciendo uso de plataformas con hardware y software genéricos.

Orientados a Mensajes: Los Sistemas Reactivos confían en el intercambio de mensajes asíncrono para establecer fronteras entre componentes, lo que asegura bajo acoplamiento, aislamiento y transparencia de ubicación. Estas fronteras también proporcionan los medios para delegar fallos como mensajes. El uso del intercambio de mensajes explícito posibilita la gestión de la carga, la elasticidad, y el control de flujo, gracias al modelado y monitorización de las colas de mensajes en el sistema, y la aplicación de back-pressure cuando sea necesario. La mensajería basada en ubicaciones transparentes como medio de comunicación permite que la gestión de fallos pueda trabajar con los mismos bloques y semánticas a través de un clúster o dentro de un solo nodo. La comunicación No-bloqueante permite a los destinatarios consumir recursos sólo mientras estén activos, llevando a una menor sobrecarga del sistema.


Publicado en septiembre 16 2014. (v2.0) El Manifiesto de Sistemas Reactivos.

Esta es uno de los conceptos que suele causar más confusiones, debido al hecho de que usar programación reactiva no necesariamente conduce a la formación de sistemas reactivos. Aunque el paradigma sí es útil para satisfacer ciertos requerimientos enunciados en el manifiesto, hace falta considerar algunos puntos:

De acuerdo al white paper "Reactive Programming versus Reactive Systems", escrito por Jonas Bonér y Viktor Clang, la programación reactiva es, generalmente, dirigida por eventos, mientras que los sistemas reactivos son dirigidos por mensajes. La principal diferencia entre ambos consiste en que los mensajes son inherentemente dirigidos (siempre tienen un destino), mientras que los eventos no: estos son tan solo señales emitidas por un componente al alcanzar cierto estado.

En un sistema dirigido por mensajes, los receptores esperan por la llegada de estos y reaccionan a ellos, de lo contrario permanecen inactivos. Por otra parte, en un sistema dirigido por eventos, los detectores de notificaciones están anclados a las fuentes de dichos eventos, de tal forma que son invocados cuando el evento es emitido. En síntesis, un sistema dirigido por mensajes se centra en los destinatarios, mientras que uno dirigido por eventos se enfoca en los emisores.

De este modo, el uso exclusivo de programación reactiva puede hacer que la resiliencia sea más difícil de lograr, pues las callbacks suelen ser anónimas y, por ende, no direccionables. Es decir que, si falla una de las cadenas del flujo de datos, entonces se debe reiniciar la cadena y el cliente debe ser notificado (algo que no ocurre en un sistema dirigido por mensajes, que tendría la capacidad de autorrecuperarse sin involucrar al cliente). Sin embargo, si se integra este paradigma con una arquitectura reactiva, este termina siendo de gran utilidad a la hora de construir sistemas reactivos.

Programación

ReactiveX

Es un conjunto de herramientas que permiten que los programación imperativos operen en secuencias de datos independientemente de si los datos son síncronos o asincrónicos. Proporciona un conjunto de operadores de secuencia que operan en cada elemento de la secuencia. Es una implementación de programación reactiva y proporciona un modelo para que las herramientas se implementen en múltiples programación.

ReactiveX es una combinación de las mejores ideas del patrón Observer, el patrón Iterator y la programación funcional Reactiva.

Lenguajes con librería ReactiveX

Los siguientes lenguajes poseen una librería basada en ReactiveX que les permite pertenecer al paradigma de la Programación reactiva

ReactiveX para plataformas y frameworks

Spring framework 5.0

Spring 5 incluye Spring WebFlux, que proporciona soporte de programación reactiva para aplicaciones web.

Spring WebFlux permitirá construir un servicio REST no bloqueante, de tal forma que se puedan hacer varias peticiones simultáneas y estas se procesen en paralelo.


Svelte

Svelte presenta un enfoque nuevo para crear interfaces de usuario. Mientras los frameworks tradicionales como React y Vue hacen la mayor parte de su trabajo en el navegador, Svelte cambia ese trabajo a un paso de compilación que ocurre cuando se construye la aplicación.

Se podría decir que Svelte es un compilador que toma el código y genera JavaScript nativo que interactúa con el DOM directamente sin necesidad de un intermediario.

Ejemplos

RxPY


RxJAVA

El siguiente ejemplo muestra una implementación pura en Java que busca simular un caso de programación reactiva, en el que en un hilo se simula el envío de un correo a una dirección de correo aleatoria y en otro hilo se simula la confirmación de la recepción de dicho email

Ahora, el mismo ejemplo pero usando RxJava


RxJS

A continuación, veremos un ejemplo simple de reactividad en Javascript
Iniciamos definiendo dos funciones:

  • UpdateNotifications: Encargada de notificarnos cuando el usuario fue actualizado
  • GetUsers: La cual nos genera un usuario aleatorio
  • En este primer ejemplo el usuario se creará sin problemas y seguido de esto será actualizado mediante el bucle for. Ahora bien, ¿Qué ocurriría si en vez de un cliente tenemos un flujo de clientes continuo? ¡Correcto!, Al no terminar de crear clientes, el bucle for jamás llega a ejecutarse. Una forma de solucionar este problema puede ser obligar la ejecución del programa mediante otra sentencia SetInterval y mejorándolo un poco, como vemos a continuación; ajustando el index desde el que se recorrerá la lista de usuarios.
    Sin embargo está solución puede ser implementada utilizando programación reactiva de manera más elegante y ¡Menos código! Como observamos a continuación debemos declarar un Observador que será el encargado de avisarnos cuando se crea un nuevo usuario y comunicarlo al Suscribe, el cual se ejecutará apenas el estado de la lista cambie.


    RxRuby

    El siguiente ejemplo crea un observable que emite números secuenciales, uno cada 2 segundos, luego estos son capturados por el suscriptor y ejecutada la función según el caso


    Rx.NET

    El siguiente ejemplo crea 2 Observables, cada uno de un único elemento, luego los combina realizando la suma de los valores y selecciona la respuesta como String en caso de que la suma sea par, esta combinación se muestra tanto haciendo uso de sintaxis basada en Queries como en sintaxis fluida


    Ejemplo de chat usando programación reactiva


    Aplicaciones

    Dominios de Aplicación:

    Muchas empresas están utilizando esta forma de programación actualmente y con mucha razón. Como ya hemos señalado, permite crear aplicaciónes o sitios web de tal manera que ofrece una mejor experiencia de usuario. Resultados más suaves y rápidos provienen de este paradigma y hace que la interacción del usuario sea mucho mejor. Naturalmente, esto se traduce en clientes más felices y más ventas para el negocio.

    Compañías como Netflix llevan años aplicando la programación reactiva para mejorar el rendimiento de sus aplicaciones, superando las limitaciones nativas de múltiples lenguajes. Reactivex y otras librerías les proporcionó la pieza que necesitaban para realizar la orquestación de microservicios, la implementación del patrón circuit breaker y demás mecanismos que permiten a sus desarrollos adoptar los principios descritos por el manifiesto reactivo.

    Capital One rediseñó su aplicación de préstamos para automóviles en torno a los principios Reactivos para simplificar la compra y financiación de automóviles en línea. Los clientes pueden navegar por más de cuatro millones de automóviles de más de 12.000 concesionarios y precalificar el financiamiento en segundos, sin afectar las puntuaciones de crédito.

    LinkedIn recurrió a los principios Reactivos para crear indicadores de presencia en tiempo real (indicadores en línea) para el medio billón de usuarios de su red social.

    Verizon Wireless, operadores de la red 4G LTE más grande en Estados Unidos, redujo los tiempos de respuesta a la mitad utilizando los principios de Reactive en la actualización de su sitio web de comercio electrónico que soporta 146 millones de suscriptores que manejan 2.500 millones de transacciones al año.

    Walmart Canada reconstruyó toda su aplicación web y pila móvil como un sistema Reactivo y vio un aumento del 20 por ciento en la conversión a ventas de tráfico web y un aumento del 98 por ciento en los pedidos móviles recortando los tiempos de carga de páginas en más de un tercio.

    En Tenea, empresa que se dedica a implantar soluciones de negocio a través de las nuevas tecnologías, están trabajando hace más de 5 años con tecnologías como ActiveMQ, RabittMQ, Fuse Enterprise (componentes OSGI), mongoDB, ElasticSearch o Solr y, por supuesto, en orientación a eventos y en programación reactiva. Concretamente, en su motor de reglas IoT TeneaRules, que han miniaturizado para que corra sobre hardware de dominio público low cost (TP-Llink, Xiaomi), sobre el open source OpenWrt y cuya sintaxis declarativa y funcional les permite programar comportamientos asociados a los eventos del entorno: ES_DE(NOCHE)= , ALARMA(ON)= ; PUERTA,PRINCIPAL(ABIERTA)=, etc.

    Jafar Husain, Desarrollador Senior en el equipo de Interfaz de Usuario de TV en Netflix comenta lo siguiente:
    "Over the last year, Netflix has reinvented our client-server interaction model. One of the key building blocks of our platform is Microsoft’s open-source Reactive Extensions library (Rx). Netflix is a big believer in the Rx model, because Rx has made it much easier for us to build complex asynchronous programs."

    Husain También menciona que actualmente Netflix es de las pocas compañías que utiliza la programación reactiva tanto en el servidor como en el cliente, sin embargo, no son la única: Felipe Lima, Miembro del equipos de desarrollo de Android en Airbnb, menciona por qué decidieron inclinarse hacia la programación reactiva mediante RxJava:
    " It’s easy to switch back and forth between threads. It’s built right into the framework, Async can be very cumbersome and error-prone, and RxJava is one reason we you don’t need to do that anymore, and why you can compose different tasks together".

    La programación reactiva se ha aplicado durante varios años en el Front-end Mediante el uso de cambios de estado en los diferentes componentes Reactive Programming for React Developers

    Frontend en Reactivex
    Uno de los principales usos de Recativex
    Algunas compañías que hacen uso de este Paradigma en sus productos:
    Compañias que usan RecativeX
    Compañías como Netflix y Microsoft han apostado a este paradigma
    Fase monolito y evolución en la industria

    Tras un periodo de desarrollo de software, la empresa dispondrá de una plataforma que crecerá hasta donde el éxito le acompañe, incrementando la complejidad del ya sofisticado entorno. Tanto si la plataforma es Java, C#, PHP, Python o Perl, el desarrollo corre el riesgo de convertirse en un monolito difícil de mantener y evolucionar. Los procesos inicialmente simples tienden a cubrir cada vez más variantes, en función de las necesidades definidas por Dirección, Marketing o el propio Product Owner.

    En una situación como esta la solución más adoptada por los Arquitectos de Desarrollo es la de evolucionar hacia una arquitectura:

    • 1. Orientada a servicios. Cada servicio es una función sin estado que recibe una llamada y devuelve una respuesta.
    • 2. Orientada a microservicios. Es una evolución de la orientación a servicios. Como en el caso anterior los microservicios están coordinados a través de la ORQUESTACIÓN.
    • 3. Reactiva, funcional y orientada a microservicios, pero coordinados por COREOGRAFIA, y con la inferencia basada en eventos de negocio.
    Arquitectura Reactiva Funcional

    La arquitectura reactiva funcional es aquella en la que la inferencia son los EVENTOS. En este caso no hablamos de eventos de sistema, como los subsistemas de ventanas de los entornos gráficos (X11, Windows o Gnome), sino por eventos de negocio.

    La reactividad ha aparecido no solo en la parte servidora: Spring, Vert.x, ya que afecta a la arquitectura de ejecución, sino que ha entrado para instalarse de forma definitiva en la parte cliente con implementaciones en Javascript: Reactjs liberada por Facebook al mundo open, Bacon.js o RxJS.

    La importancia para las empresas radica en que se puede crear funcionalidad a partir de cualquier evento que se genere: alta_cliente, baja_cliente, venta_producto, así como la gestión de las operaciones: rotura_stock, paquetes_fuera_stock_minimo, alta_empleado, fin_promocion, envio_urgente, etc.

    Esto permitirá interceptar el flujo de datos, crear bases de datos/registros y/o funcionalidades que multiplican las capacidades digitales de la empresa, creando una nueva especie de empresas más flexibles, más adaptadas a los nuevos escenarios y, por tanto, más competitivas.

    La solución, que ya documentan empresas como Nginx y otros fabricantes, es evolucionar de aplicaciones MONOLITO a microservicios reactivos y funcionales con un roadmap bien definido, que acople el día a día de la empresa con la introducción de la arquitectura reactiva que ya usan empresas como Netflix u otras muchas.

    En definitiva, ya estamos en el momento de marcar el rumbo hacia estas nuevas herramientas y entornos de desarrollo.

    Aplicación en el backend: manejo de back-pressure

    Se dice que existe back-pressure cuando una aplicación no es capaz de soportar una gran cantidad de datos por falta de recursos, la mayoria de veces este problema esta relacionado a la velocidad computacional (Se procesando las entradas mas rapido que las salidas), la programación reactiva ayuda a manejar este problema notificando al servicio que nos esta enviando datos cuando el servicio que los recibe se queda sin recursos.

    ¿Cuando usar la programación reactiva?

    De manera general, la programación reactiva se implementa cuando una aplicación maneje un gran flujo de datos o tenga muchas fuentes de datos y que requiera de alguna manera la propagación de cambio en datos modulos y eventos., sin la programación reactiva estas aplicaciones pueden tener problemas relacionados a la sincronización de los datos y como se muestran en la interfaz grafica. Es comun usar la programación reactiva a la par con la programación orientada a objetos en casos donde la programación asincróna se vuelve dificil de entender y mantener. Es importante mencionar la concurrencia, tema en el cual partes de un programa son ejecutadas con cierta regularidad en desorden o en un orden parcial, estos se pueden comunicar entre ellos mientras se estan ejecutando, con la programación reactiva se mejora la concurrencia de las aplicaciones creando modelos asíncrono, no bloqueantes.

    Algunos casos de uso moderno
    • - Aplicaciones de IOT en donde se crean eventos que luego controlan procesos reales o transacciones de negocios.
    • - Aplicaciones que recogen y monitorean elementos de datos o actividades de una red.
    • - Aplicaciones que requieran alta interacción usuario-a-usuario donde cada acción debe ser procesada e interpretada como lo son los videojuegos o las redes sociales.
    • - Comunicación entre aplicaciones, particularmente que realicen analisis estadistico que monitoree cambios y realize eventos al detectar estos cambios.

    Referencias