Introducción a la programación reactiva con Combine

Andres Felipe Ocampo
7 min readJun 16, 2021

--

Comenzaré comentado que escribiré una serie de artículos relacionados con el nuevo framework de programación funcional reactiva de Apple “Combine”. Esto siginifica que tiene algo de relación entre la programación funcional y la reacción a un entorno en constante cambio. A lo largo de la serie de Artículos aprenderás todo lo necesario para adoptar Combine y la esencia de la programación funcional reactiva, como siempre ya lgo que me caracteriza es la implementación práctica.

Para asegurarme que comprendes qué es Combine y para qué debe usarse, primero es bueno que nos aseguremos una base sólida de conocimientos. Esto significa que primero tendremos que repasar algunos temas menos prácticos pero igualmente importantes, En ésta introducción centraremos los primeros temas en:

  • Entender la programacion funcional reactiva (FRP, Funtional Reactive Programming)
  • Mejora de la legibilidad con FRP
  • Comparando Combine con RxSwift

Entender la programacion funcional reactiva

Como he mencionado Combine es un framework de programación funcional reactiva. Me referirá a éste como FRP, en sus principios este marco se basa en la programación funcional. Esto significa que FRP nos permite escribir código que se puede componer usando muchas funciones pequeñas que operan solo en sus entradas sin cambiar nada que esté fuera de la función en sí, un ejemplo es la conocida funcion map en Swift:

[1,2,3].map { $0 * 2 }

El código anterior toma un Array de enteros y las llamadas al map se asignan en él. Esto nos permite transformar el Array de enteros en otra cosa, en este caso se multiplica el argumento recibido por el map(usamos para eso el $0 tal como una notacion corta en Swift) y multiplicandolo por dos, la funcion map solo opera en el array y en lugar de cambiar el array existe devuelve un array mapeado nuevo. La clausura pasada al map actúa como una fucnión en la programación funcional y solo opera sobre los argumentos que recibe. Esto significa que hemos podido crear un nuevo array con contenido diferente al original, sin realizar ningún trabajo que no esté encapsulado por una función.

Una función que toma otra función o clausura como parámetros se denomina función de orden superior en programacion funcional. Una función que sólo opera con los argumentos que recibe se llama función pura estos dos términos con extremadamente importantes por que forman la base de muchas de las funciones de Combine. Mi objetivo no es enseñar programación funcional, lo que si haré es explicar fragmentos de programación funcional cuando sea necesario, aquí el objetivo mas importante es centrarnos en el funcionamiento de Combine.

En este punto ya tenemos la suficiente información para comenzar a comprender que es la FRP, pero que es lo Reactivo?, la parte reactiva de FRP significa que no operamos en objetos de forma síncrona. Componemos funciones y operaciones cada vez que que sucede algo y recibimos un nuevo valor de algo, realizamos operaciones sobre él para llegar a un resultado determinado, considerando el ejemplo anterio descrito, primero tenemos un Array de [1,2,3] y luego un nuevo Array con un nuevo contendo de [2,4,6], bien, es simple! todo parece que funciona de manera síncrona, Consideremos otro ejemplo, un serie de valores que se emiten a lo largo del tiempo, podemos tomar cada valor y podemos transformarlo en un nuevo valor:

El código anterior es un ejemplo en el que tomamos eventos .onTap que son emitodos por un botón cuando un usuario toca dicho botón, a estos eventos los llamamos Transmisión. Todo en FRP se considera una transmision, como un Array de valores en donde los valores se entregan a los largo del tiempo, siempre que se emite nuevo valor del .onTap se pasa al map, la implementación del map lo podemos ignorar y pasamos de largo a la transformación de un Boolean aleatorio, muy parecido a como multipliocamos los numeros enteros en el ejemplo anterior, finalmente se imprime un mensaje basado en el valor boolean recibido.

En Combine usamos el metodo sink para recibir valores, pero ésto lo veremos con mas adelante en un articulo que se encargará de explorar los publishers y los subscribers, pero con base en los ejemplos anteriores podemos decri que FRP usa la programación funcional para reaccionar a eventos que ocurren con el tiempo o de forma asíncrona.

Mejorar la legibilidad con FRP

Cuando estamos comenzado con FRP, no existe otra forma de usar FRP?, pero tiene una caracaterística muy interesante, aumenta la legibilidad del código y reduce significativamente la complejidad del codigo. El inconveninte quizá más importante de FRP es que tiene a tener una curva de aprendizaje bastante pronunciada, igual que los test unitarios, una vez que los principios hacen click y comprendemos como funciona FRP y Combine, a partir de este punto comienza a quedar muy claro cómo FRP mejora la legibilidad.

Aunque aún no sabemos nada de Combine, vamos a ver un ejemplo de cómo Combine puede aumentar la legibilidad al compararlo con un enfoque tradicional basado en una devolución de una llamada a un servicio, vamos a ver los dos ejemplos:

Si bien el código anterior no es complejo, podemos ver gestionamos controles de finalizacion o valores de que podrían hacer que nuestro código hiciera crash, y no solo eso, hay una gran cantidad de codigo repetitivo involucrado en esta simple solicitud, un desempaquetado de un valor opcional, luego tienes que gestionar el valor descomprimido para el Result, ahora, vamos a verlo con Combine:

En lugar de manejar el error y el éxito tanto en el controlador de finalización que se para a la URLSession como el método que llama a requestData(), los eventos de finalización y error se transmiten al flujo de valor de Combine.

Con todo esto Combine nos puede ayudar a deshacernos de una gran cantidad de código repetivivo, que nos ayudará a centranos en lo que nos interesa realmente, crear una aplicación móvil. Hay que tener en cuenta que Combine usa varias funciones pequeñas y puras llamadas operadores para transformar valores a medida que se transmiten a lo largo de la cadena, puede realizar muchas trasnformaciones legibles y sin repetición que casi se leen como oraciones enteras normales, para eso esta el siguiente código

Está claro, este código llama al método, que invoca el NetworkService, decodifica los datos devueltos por la solicitud en un SomeModel, mapea el resultado para extraer el nombre de los datos decodificados y luego lo imprime, veremos con mas detalle estos operadores, lo que quiero es mostrar como Combine puede componerlos juntos para crear una cadena de transformaciones que hacen cambios pequeños y aislados en los datos.

Comparando Combine a RxSwift

¿En que se diferencia Combine de RxSwift?¿Por que iba a cambiar?, RxSwift es un framework que se basa en ReactiveCocoa, y mas usuarios que el propio RxSwift, pero es si duda un buena base para Combine, RxSwift es un framework que implementa la Api de ReactiveX multiplataforma. ReactiveX es un estandard para la programación reactiva que se apodta en muchas plataformas. Hay versiones de Javascript, Java y más disponibles. RxSwift es de código abierto, lo que indica que tenemos información sobre su desarrollo e incluso se puede llegar a contribuir a corregir errores etc..Pero RxSwift es una dependencia de terceros, y como ya sabemos dependemos del mantenimiento del proyecto, para tener un codigo seguro y sin errores.

Combine esta escrito en el ecosistema de Apple, esto significa que está siempre corregido y evita que los errores lleguen a las nuevas versiones de iOS, y esta claro que el comportamiento del framework puede cambiar entre las versiones de iOS. Además estemos seguros que Apple mantendrá Combine por mucho tiempo incluso si es solo por razones de compatibilidad, y lo mejor es que no tenemos que importar ningun codigo externo esta en su base.

Está estrechamente integrado con SwiftUI, asi que la decisión puede que se haya tomado de una vez si estas leyendo este artículo.

Resumen

Este es el primero de muchosd artículos destinados al entendimiento de Combine, he explicado los conceptos basico de FRP, dicha FRP toma prestados muchos principios de la programación funcional y que ademas usa funciones puras y funciones de orden superior para componer comportamientos complejos con varios operadores pequeños. Hemos visto algunos ejemplos como podemos transformar la pulsación de un botón en un valor booleano aleatorio utilizando un editor combinado personalizado. También vimos cómo Combine puede ayudarnos a limpiar las API basadas en devoluciones de llamada al ocultar la complejidad en operadores pequeños, con los que cada uno hace una parte del trabajo para obtener el resultado esperado, por último un poco de historia de RxSwift y Combine, son muy similares pero con grandes diferencias, en los próximos artículos nos centraremos en los Publishers y los Subscribers de Combine y aprenderemos más de los fragmentos de código que hemos visto en este artículo.

--

--

Andres Felipe Ocampo
Andres Felipe Ocampo

Written by Andres Felipe Ocampo

Digital Manager and Sr Lead iOS Engineer

No responses yet