5 cosas que hay que saber sobre la programación reactiva

Por Clement Escoffier 30 de junio de 20176 de agosto de 2020

Reactivo, qué palabra tan sobrecargada. Muchas cosas resultan ser mágicamente Reactivas hoy en día. En este post, vamos a hablar de la Programación Reactiva, es decir, un modelo de desarrollo estructurado en torno a flujos de datos asíncronos.

Sé que estás impaciente por escribir tu primera aplicación reactiva, pero antes de hacerlo, hay un par de cosas que debes saber. El uso de la programación reactiva cambia la forma de diseñar y escribir el código. Antes de subirte al tren, es bueno saber hacia dónde te diriges.

En este post, vamos a explicar 5 cosas sobre la programación reactiva para que veas lo que te cambia.

Cuando se utiliza la programación reactiva, los flujos de datos van a ser la columna vertebral de tu aplicación. Los eventos, los mensajes, las llamadas e incluso los fallos van a ser transmitidos por un flujo de datos. Con la programación reactiva, observas estos flujos y reaccionas cuando se emite un valor.

Así que, en tu código, vas a crear flujos de datos de cualquier cosa y desde cualquier cosa: eventos de clic, peticiones HTTP, mensajes ingeridos, notificaciones de disponibilidad, cambios en una variable, eventos de caché, medidas de un sensor, literalmente cualquier cosa que pueda cambiar o suceder. Esto tiene un interesante efecto secundario en tu aplicación: se vuelve inherentemente asíncrona.

Reactive eXtension (http://reactivex.io, a.ka. RX) es una implementación de los principios de la programación reactiva para «componer programas asíncronos y basados en eventos mediante el uso de secuencias observables». Con RX, tu código crea y se suscribe a flujos de datos llamados Observables. Mientras que la Programación Reactiva es sobre los conceptos, RX le proporciona una increíble caja de herramientas. Al combinar los patrones de observadores e iteradores y los modismos funcionales, RX te da superpoderes. Tienes un arsenal de funciones para combinar, fusionar, filtrar, transformar y crear los flujos de datos. La siguiente imagen ilustra el uso de RX en Java (usando https://github.com/ReactiveX/RxJava).

Si bien RX no es la única implementación de los principios de la programación reactiva (por ejemplo podemos citar a BaconJS – http://baconjs.github.io), es la más utilizada en la actualidad. En el resto de este post, vamos a utilizar Rx Java.

2. Los observables pueden ser fríos o calientes – y eso importa.

En este punto, estás tratando de ver cuáles son los diferentes flujos (u observables) que vas a tratar en tu programa. Pero hay dos clases de flujos: calientes y fríos. Entender la diferencia es clave para utilizar con éxito la programación reactiva.

Los observables fríos son perezosos. No hacen nada hasta que alguien empieza a observarlos (suscribirse en RX). Sólo comienzan a ejecutarse cuando son consumidos. Los observables fríos se utilizan para representar acciones asíncronas, por ejemplo, que no se ejecutarán hasta que alguien esté interesado en el resultado. Otro ejemplo sería una descarga de archivos. No comenzará a extraer los bytes si nadie va a hacer algo con los datos. Los datos producidos por un flujo frío no se comparten entre los suscriptores y cuando te suscribes obtienes todos los elementos.

Los flujos calientes están activos antes de la suscripción como un ticker de bolsa, o los datos enviados por un sensor o un usuario. Los datos son independientes de un suscriptor individual. Cuando un observador se suscribe a un observable caliente, obtendrá todos los valores del flujo que se emitan después de que se suscriba. Los valores se comparten entre todos los suscriptores. Por ejemplo, aunque nadie se haya suscrito a un termómetro, éste mide y publica la temperatura actual. Cuando un suscriptor se registra en el flujo, recibe automáticamente la siguiente medida.

¿Por qué es tan importante entender si tus flujos están calientes o fríos? Porque cambia la forma en que su código consume los elementos transmitidos. Si no está suscrito a un observable caliente, no recibirá los datos, y estos se pierden.

Desarrolle utilizando los productos más valiosos de Red Hat

Su membresía desbloquea los productos de Red Hat y la formación técnica sobre el desarrollo de aplicaciones de nube empresarial.

Únete a RED HAT DEVELOPER

Muerde la asincronía mal empleada

Hay una palabra importante en la definición de programación reactiva: asíncrono. Se le notifica cuando los datos se emiten en el flujo de forma asíncrona, es decir, independientemente del flujo principal del programa. Al estructurar tu programa en torno a los flujos de datos, estás escribiendo código asíncrono: escribes código invocado cuando el flujo emite un nuevo elemento. Los hilos, el código de bloqueo y los efectos secundarios son cuestiones muy importantes en este contexto. Empecemos por los efectos secundarios.

Las funciones sin efectos secundarios interactúan con el resto del programa exclusivamente a través de sus argumentos y valores de retorno. Los efectos secundarios pueden ser muy útiles y son inevitables en muchos casos. Pero también tienen trampas. Al utilizar la programación reactiva, debes evitar los efectos secundarios innecesarios, y tener una intención clara cuando los utilices. Por lo tanto, abrazar la inmutabilidad, y las funciones libres de efectos secundarios. Aunque algunos casos están justificados, abusar de los efectos secundarios conduce a tormentas: la seguridad de los hilos.

Este es el segundo punto importante: los hilos. Es agradable observar los flujos y ser notificado cuando sucede algo interesante, pero nunca debes olvidar quién te llama, o más precisamente en qué hilo se ejecutan tus funciones. Se recomienda encarecidamente evitar el uso de demasiados hilos en su programa. Los programas asíncronos que dependen de múltiples hilos se convierten en un duro rompecabezas de sincronización que a menudo termina como una cacería de bloqueos.

Ese es el tercer punto: nunca bloquear. Como no eres el dueño del hilo que te llama, debes asegurarte de no bloquearlo nunca. Si lo haces puedes evitar que los otros elementos se emitan, se almacenarán en el buffer hasta que … el buffer se llene (la contrapresión puede entrar en juego en este caso, pero no es el tema de este post). Combinando RX e IO asíncrono tienes todo lo que necesitas para escribir código no bloqueante, y si quieres más, mira Eclipse Vert.x, un kit de herramientas reactivo que promueve la reactividad y la asincronía. Por ejemplo, el siguiente código muestra el cliente web Vert.x y su API RX para recuperar un documento JSON del servidor y mostrar la entrada del nombre:

client.get("/api/people/4").rxSend().map(HttpResponse::bodyAsJsonObject).map(json -> json.getString("name")).subscribe(System.out::println, Throwable::printStackTrace);

Nota el método subscribe en este último fragmento. Toma un segundo método llamado cuando una de las etapas de procesamiento lanza una excepción. Atrapa siempre las excepciones. Si no lo haces pasarás horas tratando de entender qué está fallando.

4. Mantén las cosas simples

Como sabes, «Un gran poder conlleva una gran responsabilidad». RX proporciona un montón de funciones muy chulas, y es fácil inclinarse hacia el lado oscuro. Encadenar flapmap, retry, debounce, y zip te hace sentir como un ninja… PERO, nunca olvides que el buen código tiene que ser legible por otra persona.

Tomemos un poco de código…

manager.getCampaignById(id) .flatMap(campaign -> manager.getCartsForCampaign(campaign) .flatMap(list -> { Single<List<Product>> products = manager.getProducts(campaign); Single<List<UserCommand>> carts = manager.getCarts(campaign); return products.zipWith(carts, (p, c) -> new CampaignModel(campaign, p, c)); }) .flatMap(model -> template .rxRender(rc, "templates/fruits/campaign.thl.html") .map(Buffer::toString)) ) .subscribe( content -> rc.response().end(content), err -> { log.error("Unable to render campaign view", err); getAllCampaigns(rc); });

Dado un ejemplo como este puede ser difícil de entender ¿no? Se encadenan varias operaciones asíncronas (flatmap), se unen a otro conjunto de operaciones (zip). El código de programación reactiva requiere primero un cambio de mentalidad. Se le notifican los eventos asíncronos. Luego, la API puede ser difícil de entender (basta con mirar la lista de operadores). No abuses, escribe comentarios, explica o dibuja diagramas (seguro que eres un artista del asciiart). RX es poderoso, abusar de él o no explicarlo hará que tus compañeros de trabajo se pongan de mal humor.

5. Programación reactiva != Sistema reactivo

Probablemente la parte más confusa. El uso de la programación reactiva no construye un sistema reactivo. Los sistemas reactivos, como se definen en el manifiesto reactivo, son un estilo arquitectónico para construir sistemas distribuidos con capacidad de respuesta. Los sistemas reactivos podrían ser vistos como sistemas distribuidos hechos correctamente. Un sistema reactivo se caracteriza por cuatro propiedades:

  • Responsive: un sistema reactivo necesita manejar las peticiones en un tiempo razonable (dejo que tú definas lo que es razonable).
  • Resilient: un sistema reactivo debe seguir respondiendo ante los fallos (crash, timeout, 500 errores… ), por lo que debe estar diseñado para los fallos y tratarlos adecuadamente.
  • Elastic: un sistema reactivo debe seguir respondiendo bajo diversas cargas. En consecuencia, debe escalar hacia arriba y hacia abajo, y ser capaz de manejar la carga con un mínimo de recursos.
  • Dirigido por mensajes: los componentes de un sistema reactivo interactúan utilizando el paso de mensajes asíncronos.

A pesar de la simplicidad de estos principios fundamentales de los sistemas reactivos, construir uno de ellos es complicado. Normalmente, cada nodo necesita adoptar un modelo de desarrollo asíncrono no bloqueante, un modelo de concurrencia basado en tareas y utiliza E/S no bloqueante. Si no piensas en estos puntos primero, rápidamente será un plato de espaguetis.

La programación reactiva y la eXtensión reactiva proporcionan un modelo de desarrollo para domar a la bestia asíncrona. Usándolo sabiamente, tu código va a seguir siendo legible, y comprensible. Sin embargo, usar la programación reactiva no transforma tu sistema en un Sistema Reactivo. Los Sistemas Reactivos son el siguiente nivel.

Conclusión

Por fin llegamos al final de este post. Si quieres ir más allá y te interesa lo reactivo, te recomiendo que eches un vistazo a Eclipse Vert.x – un kit de herramientas para construir sistemas reactivos y distribuidos (http://vertx.io), y al minilibro Reactive Microservices in Java disponible en https://developers.redhat.com/books/building-reactive-microservices-java. La combinación de Vert.x y Reactive eXtension da rienda suelta a su superpotencia reactiva. No sólo puede utilizar la programación reactiva, sino también construir sistemas reactivos y tener acceso a un ecosistema emocionante y creciente.

¡Feliz codificación!

Descargue la hoja de trucos de Eclipse Vert.x, esta hoja de trucos proporciona detalles paso a paso para que pueda crear sus aplicaciones de la manera que desee.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.