Bit - loader

Casos de uso de Programación Reactiva (API Netflix)

   Artículo | Programación Reactiva Bit - Casos de uso de Programación Reactiva (API Netflix)
Ricardo Ahumada | 28/02/18

En este artículo vamos a mostrar algunos casos de uso de programación reactiva.

La API de Reactive Extensions es muy potente, pero necesitamos generar una fuente de Observables en alguna parte. Crear un Observable desde cero puede ser un desafío debido que debe seguirse el contrato de Rx (y la contra-presión).

La buena noticia es que hay muchas librerías y marcos que admiten Rx de forma nativa. Asimismo, Rx resulta ser muy útil en algunas plataformas que son inherentemente asincrónicas.

 

Cuándo se necesita programación reactiva

La programación reactiva es útil en escenarios como los siguientes:

  • Procesar eventos de usuario como el movimiento o clics del ratón; la escritura en teclado; las señales de GPS que cambian con el tiempo a medida que los usuarios se mueven con su dispositivo; las señales del giroscopio de un dispositivo; los eventos táctiles; etc.
  • Responder y procesar cualquiera/todos los eventos de E/S vinculados a la latencia desde el disco o la red. Dado que los eventos de E/S son intrínsecamente asíncronos (se realiza una solicitud, el tiempo pasa, se puede recibir o no una respuesta, lo que desencadena un trabajo posterior).
  • Manejo de eventos o datos enviados a una aplicación por un productor que no puede controlar (eventos del sistema desde un servidor, los eventos del usuario antes mencionados, señales del hardware, eventos desencadenados por el mundo analógico desde sensores, etc.).

Si el código en cuestión está gestionando solo un flujo de eventos, la programación imperativa-reactiva con un callback es suficiente; la programación funcional reactiva no nos dará muchos beneficios. Se pueden tener cientos de secuencias de eventos diferentes, y si son completamente independientes entre sí, la programación imperativa no será un problema. En casos de uso tan simples, los enfoques imperativos van a ser los más eficientes porque eliminan la capa de abstracción de la programación reactiva y se mantienen más cerca de aquellos para los que se optimizan los sistemas operativos, los lenguajes y los compiladores actuales.

Sin embargo, si el programa es como en la mayoría de casos y, necesita combinar eventos (o respuestas asincrónicas de funciones o llamadas de red), tener lógica condicional interactuando entre ellos, y debe manejar escenarios de fallo y limpieza de recursos en cualquiera de ellos. Aquí es donde el enfoque de imperativo-reactivo comienza a aumentar drásticamente en complejidad y la programación funcional reactiva comienza a brillar.

Aunque la programación funcional reactiva tiene inicialmente una curva de aprendizaje superior y una barrera para la entrada, el techo para la complejidad es mucho más bajo que con la programación imperativa-reactiva.

 

 

Llamadas de servicios externos

Actualmente muchos servicios back-end son RESTful (operan a través de HTTP), por lo que el protocolo subyacente es fundamentalmente de bloqueo y sincrónico. Quizás no sea un territorio obvio para la programación reactiva funcional (FRP: Functional Reactive Programming), pero en realidad es un terreno bastante fértil porque la implementación de estos servicios a menudo implica llamar a otros servicios, y más servicios dependiendo de los resultados de las primeras llamadas. Con tanto IO sucediendo si se esperara a que se complete una llamada antes de enviar la próxima solicitud, el pobre cliente se rendiría de frustración antes de que se pueda reunir una respuesta. Por lo tanto, las llamadas al servicio externo, especialmente las complejas orquestaciones de dependencias entre llamadas, son necesarias de optimizar. FRP ofrece la promesa de “combinabilidad (composability)”  de la lógica que guía dichas operaciones, por lo que es más fácil implementar para el desarrollador de los servicios que las invocan.

 

Consumidores de mensajes altamente concurrentes

El procesamiento de mensajes, en particular cuando son altamente concurrentes, es un caso de uso empresarial común. Los frameworks reactivos les gusta mostrar benchmarks y presumen de cuántos mensajes por segundo pueden procesar. Los resultados son realmente asombrosos (logran fácilmente decenas de millones de mensajes por segundo), pero posiblemente algo artificiales: evaluación de un simple bucle “for”. No obstante, no debemos apresurarnos a denostar estos resultados. Los patrones reactivos se ajustan naturalmente al procesamiento de mensajes (dado que un evento se traduce muy bien en un mensaje), de modo que es una forma de procesar más mensajes, más rápido.

 

Hojas de cálculo

En realidad tal vez no sea un caso de uso empresarial, pero sí uno con el que todos pueden relacionarse fácilmente, además de captar muy bien la filosofía y la dificultad de implementar FRP. Si la celda B depende de la celda A, y la celda C depende de ambas celdas A y B, entonces, ¿cómo se propagan los cambios en A, asegurando que C se actualice antes de que cualquier evento se envíe a B? Si tiene un framework realmente reactivo, la respuesta es “no le importa, solo se declaran las dependencias”, y ese es realmente el poder de una hoja de cálculo en pocas palabras. También destaca la diferencia entre FRP y la programación simple basada en eventos: cambiar de “inteligente” a “enrutamiento inteligente”.

 

Abstracción sobre procesamiento (A)síncrono

Este es más un caso de uso abstracto, aunque la propuesta básica es familiar y justificable: Mientras los desarrolladores estén dispuestos a aceptar una capa adicional de abstracción, pueden olvidarse de si el código que están invocando es sincrónico o asíncrono. Algunas de las librerías FRP proponen herramientas reales útiles para lograr este objetivo.

 

Caso de uso: API Netflix

En el artículoReactive Programming in the Netflix API with RxJava” de su blog, el equipo de Netflix nos cuenta cómo han implementado su API usando programación reactiva.

Algunos de los puntos clave son:

  • Concurrencia para reducir de manera efectiva la sobre-mensajería (chattiness) de la red.
  • Los futuros funcionan bien para un solo nivel de asincronicidad, pero son costosos de componer con la asincronía condicional.
  • Los callback se vuelven poco manejables con composiciones asíncronas anidadas (Pyramid of doom).
  • La programación reactiva ofrece una ejecución y composición eficientes al proveer una colección de operadores capaces de filtrar, seleccionar, transformar, combinar y componer Observables.

La API de Netflix aprovecha Rx al hacer que toda la capa de servicio sea asíncrona (o al menos así lo parezca); todos los métodos de “servicio” devuelven un Observable<T>.

Hacer todos los tipos de retorno observables combinados con un estilo de programación funcional libera la implementación de la capa de servicio para usar concurrencia de manera segura. También habilita la implementación de la capa de servicio para:

  • Usar return condicional inmediato desde un caché
  • Bloquear en lugar de usar subprocesos si los recursos están restringidos
  • Usar múltiples hilos
  • Usar E/S sin bloqueo
  • Migrar una implementación subyacente de “basada en red” a “caché en memoria”

Todo esto puede suceder sin cambiar el modo en que el código del cliente interactúa o compone las respuestas.

 

Reflexiones finales

Tal como hemos visto, existen un conjunto de casos de uso en los que se puede aplicar programación reactiva, bastante alineadas con la problemática empresarial actual. La programación reactiva permite una mejor performance e interoperabilidad entre componentes; tal como nos cuenta el equipo de Netflix en su blog.

Aunque la curva de aprendizaje es empinada, nos ayudará a reducir la complejidad de las implementaciones y esto es un gran beneficio en los sistemas actuales.

En el siguiente artículo veremos ejemplos de programación reactiva en Javascript y Java.

 


Entradas relacionadas
Nuestro sitio utiliza cookies para análisis. Si no estás seguro de ello, echa un vistazo a nuestra política de privacidad.