En este artículo en particular trataremos de responder a preguntas como:
¿Qué es la programación reactiva? ¿Qué es la Programación Reactiva Funcional? Qué beneficios podemos obtener al utilizar la Rx en nuestras aplicaciones y por dónde puede empezar a introducir la Rx en su aplicación.
¿Qué es la programación reactiva?
Probablemente en cada artículo sobre la Programación Reactiva podrá encontrar una referencia y un enlace al Manifiesto Reactivo. En este documento puede obtener las principales afirmaciones sobre las ventajas de las aplicaciones reactivas, pero no le da ninguna idea sobre cómo conseguirlas, sin embargo.
De hecho, el Manifiesto Reactivo es sólo una lista de los principales pilares por los que debe preocuparse su aplicación reactiva. Específicamente como: Responsive, Resilient, Elastic y Message Driven.
Si intentamos expresar toda la idea en una frase, podemos obtener algo así
La programación reactiva nos da la capacidad de crear aplicaciones altamente estables y con capacidad de respuesta que pueden ser fácilmente modificadas o ampliadas de acuerdo con el enfoque dirigido por mensajes. Para poner estos beneficios en su aplicación puede utilizar la Programación Reactiva. Entonces, ¿qué es la Programación Reactiva?
La programación reactiva es un enfoque que se basa en los principios de flujos de datos asíncronos y datos inmutables. Está construida sobre conceptos básicos como Observables, Observadores y Programadores. Los dos primeros son una especie de realización del patrón Observador, que se ha mantenido en el tiempo. Y los Schedulers ayudan a la programación asíncrona y a la gestión de hilos.
Por ejemplo, si se suscribe a algún canal de youtube recibirá notificaciones sobre nuevos vídeos o streams, y podrá consultarlos si lo desea. Lo mismo ocurre con su proyecto, puede suscribirse a algún evento y reaccionar sobre él de acuerdo con la lógica de su aplicación. Los programadores entran en escena si, por ejemplo, usted emite un evento en el hilo de fondo y necesita reaccionar sobre él en el hilo principal.
Programación Reactiva Funcional
Casi todas las bibliotecas Rx modernas utilizan los principios básicos de la programación funcional. Como sabrá, en la programación funcional se manipulan funciones, y del mismo modo se manipulan otros tipos de datos como enteros o cadenas, y todos estos valores son inmutables.
En la Programación Funcional usted siempre hace tratos con pedazos de datos inmutables, este hecho le permite no preocuparse por la concurrencia y los estados actuales de los datos, lo que le da mayores ventajas de usar una arquitectura asincrónica de múltiples hilos. Además, como la programación funcional le da un comportamiento predecible es mucho más fácil cubrir toda su lógica con Pruebas de Unidad. Esto, potencialmente, puede darle un producto más estable.
FRP utiliza lo mejor de la programación reactiva y funcional. En la programación tradicional también utilizamos flujos de eventos para recibir la actividad del usuario, como la pulsación de un botón, el cambio de orientación del dispositivo y otros. En FRP las variables, la entrada del usuario, las respuestas del servidor, los parámetros de los modelos y los propios modelos pueden representarse como un flujo. Esto eleva el nivel de abstracción, por lo que se pueden manipular los flujos en lugar de objetos o funciones.
La sustancia principal de FRP es Observable, que cuenta con una amplia gama de operadores con los que realmente implementará la lógica de negocio de su aplicación. Las principales categorías de estos operadores son: Transformar Observables, Filtrar Observables, Combinar Observables, y otros. La lista completa y las descripciones de los mismos las puede encontrar aquí.
Puede parecer bastante difícil de entender. Afortunadamente para una mejor comprensión de la lógica de la Programación Reactiva podemos utilizar Diagramas de Mármol como este:
Puede encontrar tales diagramas para diferentes operadores que ilustran su trabajo aquí.
Programación funcional reactiva con Swift
Bien, entonces, ¿cómo conseguir estos resultados para su aplicación? Para aplicar Rx a su proyecto particular puede utilizar una de las bibliotecas Rx, cuya lista puede encontrar aquí.
Por ejemplo, vamos a utilizar RxSwift y probar algunos operadores básicos
Empecemos con el operador “filtro”.
“El operador “filtro” filtra un observable permitiendo sólo el paso de los elementos que pasan una prueba que usted especifica en forma de función de predicado”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | let disposeBag = DisposeBag() // Create an observable of integers Observable.of(1, 2, 3, 4, 5, 6) // Apply filter operator .filter { integer in integer % 2 == 0 } // Subscribe only on even numbers .subscribe(onNext: { print($0) }) .disposed(by: disposeBag) CONSOLE OUTPUT: 2 4 6 |
Como puede ver en este ejemplo, hemos creado un Observable de enteros predefinidos. Luego filtramos los valores pares y nos suscribimos a este Observable. La combinación de operadores es bastante flexible y le permite componer expresiones realmente potentes.
Como otro ejemplo, compruebe este trozo de código con un operador “flatMap”.
“El operador FlatMap transforma un Observable aplicando una función que usted especifica a cada elemento emitido por el Observable fuente, donde esa función devuelve un Observable que a su vez emite elementos. FlatMap entonces fusiona las emisiones de estos Observables resultantes, emitiendo estos resultados fusionados como su propia secuencia.”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | struct Video { var subscribers: Variable<Int> } let disposeBag = DisposeBag() let cat = Video(subscribers: Variable(30)) let bird = Video(subscribers: Variable(43)) let dog = Video(subscribers: Variable(20)) let channel = PublishSubject<Video>() channel.asObservable() .filter { video in video.subscribers.value > 20 } .flatMap { $0.subscribers.asObservable() } .subscribe(onNext: { print($0) }) .disposed(by: disposeBag) channel.onNext(cat) channel.onNext(bird) channel.onNext(dog) cat.subscribers.value = 40 dog.subscribers.value = 70 bird.subscribers.value = 123 dog.subscribers.asObservable() .subscribe(onNext: { print($0) }) .disposed(by: disposeBag) dog.subscribers.value = 80 CONSOLE OUTPUT: 30 43 40 123 70 80 |
En este ejemplo, en primer lugar, hemos creado la estructura “Video” con un solo parámetro observable “suscriptores”. Una de las formas de revivir los eventos de esos observables es suscribirse a cada uno de ellos, pero gracias a “flatMap” podemos conseguir un resultado similar de forma más elegante. Así que básicamente creamos un nuevo PublicSubject “canal” y utilizamos el operador “flatMap” para obtener un flujo con todos estos observables. Luego nos suscribimos a ellos para imprimir los valores en la pantalla.
Como he mencionado antes, podemos combinar operadores para obtener una funcionalidad más compleja. En este caso, utilizamos “filter” antes de “flatMap” para observar sólo los vídeos con un valor de suscriptor superior a veinte. Como resultado, la modificación del vídeo “perro” no desencadena el evento de impresión hasta que nos suscribimos a él directamente.
Para una mejor comprensión consulte este diagrama del operador “flatMap”:
¿Y ahora qué?
Llegados a este punto, puede empezar a llevar Rx a su aplicación. Sólo tiene que elegir una de las bibliotecas para su plataforma desde aquí. Todas ellas tienen una documentación bastante buena, pero como principiante puede necesitar algo de información adicional para empezar a utilizar Rx en las mejores condiciones. Afortunadamente hoy en día en el mercado tenemos un montón de buenos libros para diferentes plataformas que describen casos específicos de uso de las librerías Rx. Por ejemplo, si usted trabaja con swift como yo, le recomiendo que busque en este libro RxSwift creado por el equipo de tutores de raywenderlich.com.