Cómo utilizar Progtwigción funcional en desarrollo de aplicaciones

He estado leyendo y jugando con Progtwigción Funcional (FP) y me gustan mucho los conceptos, pero no estoy seguro de cómo aplicarlos para la mayoría de mis aplicaciones.

Seré más específico, hablemos de las aplicaciones de iOS. Veo cómo usar algunos de los conceptos como estructuras de datos inmutables y funciones de order superior, pero no cómo trabajar con funciones solo / en su mayoría puras, evitando los efectos secundarios, que parece ser la parte principal de FP.

Siento que la mayor parte de la aplicación se trata de coordinar llamadas de input, mostrar datos, save datos, hacer requestes de networking, navegar de una pantalla a otra, animaciones.

Todas esas serían funciones impuras en FP:

  • Entrada de coordinación: un toque de button, una notificación, un empuje de socket del server, para todos los que tengo que decidir qué llamar, dónde observarlos, etc.
  • Visualización de datos: lee desde una database local o desde un server (efecto secundario).
  • Guardar datos: igual que el anterior (pero escribiendo).
  • Realización de requestes de networking: obvio, por lo que solo daré un ejemplo aquí: recuperar imágenes de la list de Instagram.
  • Navegación: eso básicamente presenta View Controllers, que es un efecto secundario.
  • Animaciones: cambiar algo en la pantalla, efecto secundario.

Hay muy pocos lugares en los que tengo que procesar datos y aquellos consisten casi siempre en recuperar algunos Struct's de la database y concatenar la información múltiple en otro Struct que será utilizado por el View Controller (que es como 5 líneas … suponiéndote necesita 5 properties para mostrarse en la vista). Claro, tal vez necesites hacer algún procesamiento como convertir money: Int = 20 to moneyString: String = "US$\(money).00" , pero eso es todo.

Siento que no estoy implementando FP en el ciclo de desarrollo de mi aplicación. ¿Alguien puede aclarar cómo puedo lograr eso? Quizás con ejemplos.

Gracias.

EDITAR: ahora mismo, siguiendo la idea de Arquitectura Limpia , tengo algo así como mi architecture:

introduzca la descripción de la imagen aquí

Las inputs pueden provenir de la View , al presionar un button, van al ViewController que decide a qué Interactor llamar. Ese Interactor accederá a la Gateway necesaria para get algunos datos y transformarlos en datos presentables que serán pasados ​​al Presenter (en la forma de un delegado). Finalmente, el Presenter actualizará la View para mostrar los nuevos datos.

Además, la input puede provenir de fonts External , como el server que le dice que algunos datos se actualizaron y que debe actualizar la View . Eso va al Interactor (en forma de observador) que seguirá al rest de la cadena como en el ejemplo anterior.

La única parte FP está transformando los datos de la Gateway en datos presentables. Todo el rest tiene efectos secundarios. Siento que estoy haciendo algo mal y tal vez parte de ese código debe organizarse de manera diferente para que más código pueda moverse a funciones puras.

Dejando a un lado el FP por un momento, el desafío con los models dependientes de múltiples usuarios o time es que el usuario final frente al progtwig no sea la única fuente de events de control.

Para mantener limpias las dependencies, deberíamos ver los desencadenantes externos como una forma de input del usuario (no solicitado como puede ser) y procesarlos a través de las mismas routes.

Si de alguna manera se le hubiera informado telepáticamente al usuario final de que había nuevos datos disponibles, podría haber presionado un button para que el progtwig lo obtuviera. Entonces, nunca se necesitaría ningún flujo de control hacia atrás (como las notifications push).

En ese mundo perfecto, la acción del usuario para get los datos primero se capturó en el nivel de Vista y luego se llevó a las capas.

Esto nos dice que las notifications deberían ser manejadas por el controller de vista o, mejor aún, por un componente de vista diseñado para recibirlas. Sin embargo, tales notifications no includeían ningún dato, excepto quizás alguna indicación de qué parte del model se invalidó.

Volviendo a FP, este es, por supuesto, un efecto secundario gigantesco si considera que todas las llamadas a funciones a partir de entonces devolverán resultados potencialmente diferentes. PERO…

En matemáticas, si define una function que le da la distancia recorrida a una velocidad determinada pero no proporciona el parámetro de time, no es víctima de un efecto secundario, simplemente olvidó proporcionar un valor de input.

Por lo tanto, si consideramos que todas las capas de software son funciones puras, pero ese time es un parámetro implícito dado con la input inicial, puede validar que su progtwig se ajusta a FP comprobando que las llamadas repetidas, en cualquier order, a las funciones del sistema cuando el time está congelado siempre debe devolver los mismos resultados.

Si las bases de datos pudieran mantener un set completo de instantáneas del 100% de sus estados en cualquier momento dado, sería posible validar la conformidad FP pura de las aplicaciones congelando el time o convirtiéndolo en un parámetro.

De vuelta en el mundo real ahora, un layout así a menudo no es práctico por razones de performance. Sería prácticamente imposible cualquier forma de caching.

Sin embargo, le sugiero que intente categorizar las notifications como input no solicitada del usuario en su layout. Creo que puede ayudar a resolver algunos de los acertijos.

Siempre debe haber más de una herramienta en su caja de herramientas. FP es un gran enfoque y una disciplina que la mayoría de las personas debería tener para las partes del progtwig donde se aplica (por ejemplo, presentando el model en las vistas a través de los controlleres de vista en MVVC).

Intentar usar FP en todo en una aplicación probablemente no sea una tarea que valga la pena. Tan pronto como mantengas datos o manejes el paso del time, tendrás que lidiar con los estados. Incluso los services "tranquilos" (que son candidatos conceptualmente buenos para un enfoque FP) no serán FP puro y tendrán cierta dependencia estatal. Esto no se debe a que son malas implementaciones de FP, sino porque su objective es gestionar los estados persistidos externamente. Puede girar para ver los datos almacenados como "la input", pero desde cualquier lado del service, el otro lado seguirá siendo un efecto secundario (excepto para las operaciones de solo lectura).

Si embrasa el hecho de que MVVC es responsable de la gestión de la transición del estado y permite una relación no FP entre sus componentes, es más fácil implementar un paradigma FP de menor escala para cada uno de ellos.

Por ejemplo, sus controlleres de vista no deben tener ninguna variable que duplique o mantenga versiones transformadas de datos en el model. El uso de delegates entre los componentes de MVVC rompe las reglas de FP en algunos casos, pero dentro del scope de la funcionalidad de un controller de vista, esas son inputs (no estados). Al planificar (y dibujar) un diagtwig de interacción antes de comenzar a codificar, podrá aislar mejor las preocupaciones y no entrar en callejones sin salida que romperán el FP dentro de sus componentes.

Dentro del model en sí, las properties computadas pueden recorrer un largo path para garantizar que usted cumpla con FP.

En cualquier caso, si nunca usa la instrucción var (esto va a ser un desafío en algunos lugares), es probable que termine con el código de conformidad FP.

La functional programming es buena para abordar problemas de progtwigción específicos. Donde FP sobresale está en progtwigción simultánea / paralela; si ha leído alguno de los artículos escritos por Herb Sutter en la progtwigción simultánea, comienza a ver la superposition en buena progtwigción simultánea / paralela y layout funcional.

Para una aplicación, como dijo Alain, tienes que trabajar con el estado. Puede aplicar patrones de layout de FP sobre cómo se modifica el estado, pero independientemente, tiene que modificar el estado en un momento u otro, que es lo que descubrió, no está alineado con FP puro.

FP es una herramienta en el arcón de herramientas de los patrones de progtwigción, pero no es la única herramienta.