Si es un desarrollador de aplicaciones móviles, tal vez soñó con la flexibilidad del desarrollo en línea para realizar cambios de diseño y lógica sobre la marcha y la capacidad de ejecutar pruebas de hipótesis en segundos y procesar los resultados aún más rápido.

A los desarrolladores móviles se les enseña a creer que la velocidad a la que se lanzan y actualizan las aplicaciones está directamente relacionada con la rapidez con la que llegan a los usuarios. El tiempo de moderación de la App Store puede ser frustrantemente largo. La creación de un kit de desarrollo de software (SDK) será aún más lenta porque debe adaptar sus necesidades a los ciclos de desarrollo y lanzamiento de productos de otra persona. Puede ser una buena excusa para no probar hipótesis en absoluto.

En esta publicación de blog, repasaremos el tema y lo guiaremos a través de los pasos del desarrollo impulsado por backend, describiendo cómo se usa para resolver problemas específicos y qué beneficios nos ha brindado. Los materiales para esta publicación se tomaron de la fuente en el ejemplo de MovilePay. El autor del texto original es Rodrigo Máximo.

¿Qué es el desarrollo impulsado por backend?

El desarrollo impulsado por backend (o Desarrollo impulsado por backend, o IU controlada por backend, o IU controlada por servidor) es el concepto de desarrollar aplicaciones front-end basadas en las respuestas del servidor. Las pantallas y el flujo cambian según las respuestas del servidor.

El grueso del trabajo de creación de aplicaciones móviles suele ir asociado a la construcción de una interfaz de usuario: colocar en pantallas los elementos con los que interactúa el usuario para que pueda realizar rápidamente una u otra acción. Algunos de estos componentes están llenos de cargas útiles de API: generalmente JSON con tipos primitivos (enteros, booleanos, cadenas) o procesos comerciales de aplicaciones.

El enfoque tradicional para implementar pantallas tiene ciertos inconvenientes, ya que puede haber mucha lógica comercial en el lado de la aplicación y el código se vuelve más difícil de mantener:

  • Necesita el mismo código para muchas plataformas (Android, iOS, Web, etc.). Este enfoque hace que sea más difícil mantener la compatibilidad entre plataformas, lo que aumenta la posibilidad de errores e incompatibilidades;
  • Cada actualización o modificación de una aplicación móvil implica la necesidad de cambiar el código, lo que conlleva un lanzamiento extendido de aplicaciones en la App Store;
  • En digital, las pruebas A/B son más difíciles. Es más desafiante probar conceptos y recopilar datos de los usuarios para comprender información importante del producto;
  • Dado que la mayor parte de la lógica comercial está en el lado de la aplicación, el código es más difícil de mantener y mantener.

El desarrollo orientado a backend ha llegado para resolver estos problemas.

Considere el siguiente escenario (que se basa en la aplicación iOS de muestra, pero se puede traducir fácilmente a cualquier otro proyecto front-end):

Scenario for backend driven development

 {
    "pageTitle" : "Título demostrativo" ,
    "cajas" : [
        {
            "escriba ": "Azulgrande" ,
            "título" : "Bonita caja" ,
            “subtitle” : “Subtítulo del recuadro"
        } ,
        {
            "tipo ": "pequeñoRojo" ,
            “título” : “Gran caja”
        } ,
        {
            "tipo ": "rectánguloVerde" ,
            “título” : “Caja increíble” ,
            “subtítulo” : “Subtítulo del recuadro” ,
            "número" : 10
        }
    ]
}

Toda la lógica comercial para mostrar campos y mostrar texto e información visual se consolida y abstrae en el lado del servidor, lo que elimina la necesidad de múltiples interfaces para procesar esta API. Luego, el servidor aplica la lógica comercial y usa sus resultados para generar una respuesta API en formato JSON.

En el ejemplo, para mostrar bloques en la pantalla ("bigBlue", "smallRed" y "rectangleGreen"), se usa información adicional de cada campo. Curiosamente, la variable "boxes" permite que el backend procese tantos bloques como el servidor da.

¿Probablemente ya has adivinado cómo puedes realizar pruebas A / B en esta situación? El servidor puede seleccionar usuarios específicos para ver solo bloques "bigBlue", mientras que otros pueden ver los tres tipos de bloques. Además, puede realizar pruebas A / B que cambian el orden de visualización de los bloques en la pantalla.

Otro caso de uso para el desarrollo basado en servidor es realizar cambios en la interfaz de una aplicación. Por ejemplo, si necesitamos cambiar los encabezados en la aplicación, basta con cambiar la respuesta del servidor simplemente. El orden de visualización de los subtítulos y bloques también es fácil de cambiar. En este caso, no necesita publicar una nueva versión de la aplicación en la AppStore.

Making changes to the interface in backend driven development

 {
    "pageTitle" : "Título demostrativo" ,
    "cajas" : [
        {
            "tipo ": "rectánguloVerde" ,
            “título” : “Otro título” ,
            “subtítulo” : “Otro subtítulo” ,
            “número” : 100
        } ,
        {
            "tipo ": "pequeñoRojo" ,
            “título” : “Título diferente”
        }
        {
            "escriba ": "Azulgrande" ,
            "título" : "Impulsado por backend" ,
            “subtítulo” : “Desarrollo”
        }
    ]
}

Pensar dos veces

Hay algunas cosas a tener en cuenta al usar el enfoque de desarrollo impulsado por backend. Primero, ¿qué grado de flexibilidad necesita?

Según la experiencia y la investigación, consideramos que la flexibilidad media es óptima.

No debes precipitarte de un extremo a otro. Una gran cantidad de libertad puede afectar negativamente la recuperación de su desarrollo. No puedes prever todo, especialmente porque las especificaciones del dispositivo o el tamaño de la pantalla están fuera de tu control. Finalmente, termina con una lógica de presentación del lado de la aplicación muy confusa y sobrecargada. Además, no puede anticipar todo lo que su equipo de diseño podría querer hacer en el futuro. Por lo tanto, aún debe realizar cambios en el código de la aplicación y, durante las pruebas, se descubrirán numerosas rutas complejas para lograr el objetivo.

Entonces, en conclusión, no necesitará la flexibilidad que tiene HTML en la gran mayoría de los casos. Por lo tanto, antes de desarrollar pantallas y soluciones de servidor que utilicen la idea de desarrollo dirigido por backend, le sugerimos que piense en todas las opciones posibles.

Creación de una súper aplicación, caso de tecnología móvil

Probablemente esté familiarizado con el concepto de súper aplicación y haya oído hablar de una aplicación como WeChat. WeChat es una plataforma de mensajería móvil y una red social desarrollada en China y se ha vuelto extremadamente popular en todo el mundo.

Dicha aplicación tiene como objetivo recopilar varios servicios recurrentes en un solo lugar y ofrecer a los usuarios un único punto de acceso a la mayoría de las consultas en línea de su vida diaria. Es el santo grial del desarrollo de software: juntar mucha funcionalidad para que todo se vea como ene, ofreciendo a los usuarios respuestas simples a preguntas complejas y soluciones a grandes problemas.

En el pasado, MovilePay participó en el desarrollo de una súper aplicación, cuyo proceso de desarrollo de una versión mejorada se describe en este artículo. Se suponía que iba a ser un centro de prueba y validación donde el equipo pudiera probar nuevos servicios y encontrar puntos en común en su uso.

MovilePay tuvo un problema al crear una aplicación que pudiera hacer cambios en el código rápidamente. Requirió probar muchos servicios y servicios y realizar investigaciones sobre el comportamiento del usuario en función de la información mostrada y probar hipótesis. MovilePay quería poder activar y desactivar funciones rápidamente. En tales condiciones, era imposible utilizar el enfoque tradicional con una versión para cada cambio. Considerando todos estos puntos y un escenario complejo, se decidió aplicar Backend-Driven Development.

MovilePay creó una pantalla de inicio basada en categorías para resolver este problema. Cada sección tiene su propio conjunto de elementos llamados widgets. Las secciones mostraban puntos de entrada para cualquier servicio ya implementado en cualquier orden y widgets individuales resaltados.

A veces solo se mostraba un servicio. Otras veces había tres, dependiendo de lo que se estaba probando en ese momento. MovilePay dejó la elección al servidor en lugar de codificar cualquier regla en la aplicación. Como resultado, la aplicación solo conoce la definición del punto de entrada del servicio y cómo representar cada estilo en particular. Su servidor indica qué servicios deben generarse y en qué orden. Aquí hay algunos widgets que puede mostrar la aplicación MovilePay.

Widgets that the MovilePay application

Widgets in MovilePay application

Widgets in MovilePay application

Widgets in MovilePay application

Entonces, para crear una pantalla de inicio altamente adaptable, tuvimos que obtener una respuesta del backend con una lista de secciones, cada una con una lista de widgets. El siguiente es un ejemplo de una respuesta JSON que la aplicación MovilePay debería analizar y crear una pantalla de inicio como el ejemplo a continuación.

Parsing and creating a home screen

 [
    {
        "título" : "Sección 1" ,
        "widgets" : [
            {
                "identificador" : "COLLECTION_WIDGET" ,
                "contenido" : [
                    {
                        "título" : "Título A" ,
                        "imagen" : "A" ,
                        "color" : "amarillo"
                    } ,
                    {
                        "título" : "Título B" ,
                        "imagen" : "B" ,
                        "color" : "azul"
                    } ,
                    {
                        "título" : "Título C" ,
                        "imagen" : "C" ,
                        "color" : "rojo"
                    } ,
                    {
                        "título" : "Título D" ,
                        "imagen" : "D" ,
                        "color" : "morado"
                    } ,
                    {
                        "título" : "Título E" ,
                        "imagen" : "E" ,
                        "color" : "verde"
                    }
                ]
            } ,
            {
                "identificador" : "IMAGES_WIDGET" ,
                "contenido" : [
                    {
                        "imagen" : "Imagen" ,
                        "color" : "verde"
                    } ,
                    {
                        "imagen" : "Imagen" ,
                        "color" : "azul"
                    } ,
                    {
                        "imagen" : "Imagen" ,
                        "color" : "naranja"
                    }
                ]
            } ,
            {
                "identificador" : "COLLECTION_WIDGET" ,
                "contenido" : [
                    {"título" : "Título E" , "imagen" : "E" , "color" : "verde" } , { "título" : "Título F" , "imagen" : "F" , "color" : "púrpura " } , { "título" : "Título G" , "imagen" : "G" , "color" : "rojo" } , { "título" : "Título H" , "imagen" : "H" , "color " : "azul" } , { "título" : "Título H" , "imagen" : "H" , "color" : "amarillo" } ] } ] } , { "título" : "Sección 2" , "widgets " : [ { "identificador" : "CELLS_WIDGET" , "contenido" : [ { "título" : "Celda 1" , "color" : "rojo" } , { "título" : "Celda 2" , "color" : "púrpura" } , { "título" : "Celda 3" , "color" : "amarillo" } , { "título" : "Celda 4" , "color" : "azul" } , { "título" : "Celda 5" , "color" : "verde oscuro" } ] } ] } ]

También repasaremos algunas pantallas que se pueden crear mediante el desarrollo basado en back-end.

Home screens in backend-driven development

Navegación flexible

La Súper App desarrollada por MovilePay ha logrado su objetivo de ser innovadora. MovilePay ha aprendido mucho de las pruebas de hipótesis, pero una cosa en la que son particularmente buenos es el procesamiento de pagos o el proceso de pago de varios servicios y productos. Tenían una aplicación de pago que podía procesar los pagos de cualquier servicio que prestaran. La capacidad de administrar transacciones de pago fue una ventaja significativa, ya que MovilePay podía reducir los precios al procesar múltiples transacciones y obtener información valiosa sobre el comportamiento del consumidor.

MovilePay decidió desarrollar un SDK de pago basado en el modelo de Google Pay, Apple Pay o VisaCheckout que pudiera integrarse con cualquier otra aplicación.

Sin embargo, dado que trabajar en un SDK implica muy poca capacidad para probar usando patrones de desarrollo típicos, la automatización es necesaria.

Dado que MovilePay se ocupaba de los pagos, la transformación de los flujos era fundamental. MovilePay no podía permitirse el lujo de perder a sus usuarios en ninguna etapa del embudo de conversión. Por lo tanto, era necesario optimizar todo el proceso comercial, desde el registro del usuario hasta agregar una tarjeta y pagar. Aquí es donde el desarrollo impulsado por backend volvió a ser útil, convirtiendo el servidor en el "navegador" de la aplicación.

Optimizing the business process with BDD

Ninguna de las pantallas de la aplicación MovilePay sabía qué pantalla era la siguiente. Una vez que la pantalla anterior había completado sus tareas, el servidor era responsable de devolver qué pantalla debería mostrarse a continuación.

Las rutas eran acciones que una aplicación podía reconocer y responder a través de una estructura conocida como enrutador. El mecanismo de inicio de sesión incluía dos ramas de acción separadas: una para el título de la página y otra para otros elementos (como un cambio de nombre de usuario o una nueva contraseña) que se encontraron en el árbol de acciones. El enrutador los procesó enviándolos al servidor, que luego interpretó sus acciones y determinó qué interpretaciones deberían estar en la siguiente pantalla.

Este modesto cambio de estrategia permitió la racionalización. MovilePay probó muchas formas diferentes de mostrar el formulario de registro. Se pudo probar si es preferible mostrar la pantalla de pago antes o después de agregar la tarjeta. Por ejemplo, esta es una de las razones por las que MovilePay pudo aumentar su tasa de conversión en un 30% en comparación con otras opciones de pago.

Otro ejemplo es cómo MovilePay utilizó el desarrollo impulsado por backend para resolver sus problemas. Creemos que eres maravillososaber cómo aplicar este enfoque en la práctica. Déjame mostrarte lo fácil que es.

Hay muchos métodos alternativos para lograr el mismo objetivo. Te mostraremos cómo lo hizo MovilePay para iOS. Si lo desea, este concepto se puede aplicar a cualquier otra plataforma front-end.

Cuando MovilePay lo implementó, consideraron requisitos como la facilidad de agregar widgets adicionales, la legibilidad del código y la responsabilidad única. Para hacer las cosas más simples y nativas, MovilePay decidió usar la API Codable para la serialización.

Widgets (iOS)

En términos de flexibilidad, MovilePay consideró que la mejor solución sería generalizar los widgets que debían analizarse con un protocolo. MovilePay también establece una enumeración para determinar qué estructura de widget analizar los datos.

 Widget de protocolo : decodificable { }

enum WidgetIdentifier : cadena , decodificable {
    banner de caso = "BANDERA"
    colección de casos = "COLECCIÓN"
    lista de casos = "LISTA"

    var metatipo : Widget . Tipo {
        cambiar de uno mismo {
        caso _ pancarta :
            devuelve BannerWidget . uno mismo
        caso _ colección :
            devuelve CollectionWidget . uno mismo
        caso _ lista :
            devuelve ListWidget . uno mismo
        }
    }
}

Están aprovechando la API Codificable a través del protocolo Decodificable implementado por el protocolo Widget. A continuación se muestra un ejemplo de definición de una estructura de widget.

 estructura BannerWidget : Widget {
    privado let imageURLString : String
}

struct CollectionWidget : Widget {

    elemento de estructura : decodificable {
        dejar imageURLString : Cadena
        dejar título : Cadena
        dejar subtítulo : Cadena
    }

    let sectionTitle : Cadena
    Lista de let : [ Artículo ]
}

estructura ListWidget : Widget {

    elemento de estructura : decodificable {
        dejar imageURLString : Cadena
        dejar texto : cadena
    }

    let sectionTitle : Cadena
    Lista de let : [ Artículo ]
}

Finalmente, se definió como un tipo de borrado, que interpreta cualquier widget con el método de inicialización requerido, cuando se necesita cambiar la inicialización personalizada dada por Decodable.

 clase final AnyWidget : Decodificable {

    enumeración privada Claves de codificación : Clave de codificación {
        identificador de caso
    }

    dejar widget : Widget ?

    requerido init ( del decodificador : Decodificador ) lanza {
        hacer {
            dejar contenedor = probar decodificador . contenedor ( con clave : CodingKeys . self )
            let type = probar contenedor . decodificar ( WidgetIdentifier . self , forKey :. identificador )
            uno mismo widget = tipo de prueba . metatipo init ( de : decodificador )
        } atrapar {
            uno mismo widget = nulo
        }
    }
}

Este tipo de borrado se usa para descifrar el identificador del Widget y su propiedad de "metatipo" para determinar qué estructura de widget debe usarse para analizar el resto de los datos del Widget analizado.

Todo esto da como resultado que la estructura a continuación pueda analizar una respuesta que contiene toda la información sobre los widgets. Tiene una característica única: una matriz de tipos de protocolo de Widget y puede descifrar cada Widget utilizando el tipo de borrado definido anteriormente.

 struct HomeResponse : Decodificable {

    enumeración privada Claves de codificación : Clave de codificación {
        widgets de casos
    }

    dejar widgets : [ Widget ]

    init ( del decodificador : Decodificador ) lanza {
        dejar contenedor = probar decodificador . contenedor ( con clave : CodingKeys . self )
        uno mismo widgets = probar contenedor . decodificar ( [ AnyWidget ] . self , forKey : . widgetsss="puntuación del token">) . compactMap {$ 0. widget } } init ( widgets : [ Widget ] ) { self . widgets = widgets } }

MovilePay podría haber elegido otras opciones, como no usar el protocolo y confiar en el backend para devolver una matriz de cada widget admitido para el análisis. Sin embargo, descubrimos que nuestra elección de protocolo era la mejor opción para el mantenimiento y la legibilidad. Este enfoque fue suficiente para crear una nueva estructura y agregar casos a la enumeración cada vez que requería la creación de un nuevo widget. Con un sistema diferente en una situación similar, habría que cambiar el diseño de HomeResponse.

A continuación se muestra una posible respuesta de la API JSON que analizará este modelo.

 {
    "widgets" : [
        {
            "identificador" : "BANDERA" ,
            "imageURLString" : "url_image_to_be_downloaded"
        } ,
        {
            "identificador" : "COLECCIÓN" ,
            "sectionTitle" : "Título de la sección" ,
            "lista" : [
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "título" : "Ítem de título 1" ,
                    "subtitle" : "Elemento de subtítulo 1"
                } ,
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "título" : "Ítem de título 2" ,
                    "subtitle" : "Elemento de subtítulo 2"
                } ,
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "título" : "Artículo de título 3" ,
                    "subtitle" : "Elemento de subtítulo 3"
                }
            ]
        } ,
        {
            "identificador" : "LISTA" ,
            "sectionTitle" : "Título de la sección" ,
            "lista" : [
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "texto" : "Elemento de texto 1"
                } ,
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "texto" : "Elemento de texto 2"
                } ,
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "texto" : "Elemento de texto 3"
                }
            ]
        } ,
        {
            "identificador" : "BANDERA" ,
            "imageURLString" : "url_image_to_be_downloaded"
        }
    ]
}

Este enfoque está muy cerca del desarrollo de la Súper App, que permitió a MovilePay presentar diferentes servicios a diferentes usuarios, probar muchas opciones de visualización, elaborar hipótesis y determinar qué widget se usará para qué servicio. El cambio en la clasificación de pantallas y la agrupación de servicios estuvo cerca de lo que MovilePay había hecho antes.

Navegación (iOS)

Después de solucionar el problema del widget, MovilePay intentó mejorar la navegación de manera similar. Crearon el protocolo Action, que era idéntico al protocolo Widget.

Una Acción es un objeto estructurado devuelto en la respuesta JSON de algunas API de MovilePay, con un ID y los parámetros que deben mostrarse en la escena que representa. Como resultado, el protocolo de Acción se encarga de ayudar a deconstruir el objeto estructurado.

 Acción de protocolo : Decodificable {
    func escena ( ) - > UIViewController
}

enum ActionIdentifier : cadena , decodificable {
    case inicio = "INICIO"
    caso screenOne = "SCREEN_ONE"
    caso screenTwo = "SCREEN_TWO"

    var metatipo : Acción . Tipo {
        cambiar de uno mismo {
        caso _ casa :
            volver HomeAction . uno mismo
        caso _ pantalla unooken operator">: return ScreenOneAction . self case . screenTwo : return ScreenTwoAction . self } } } ver raw

La única diferencia entre el protocolo de acción y el protocolo de widget es que proporcionamos un método que devuelve la escena adecuada para cada acción en la definición de acción. Como ejemplo, observe cómo se implementan estas acciones.

 struct HomeAction : Acción {
    función escena ( ) - > UIViewController {
        volver InicioCoordinador . escena ( )
    }
}

struct ScreenOneAction : Acción {
    dejar título : cadena

    función escena ( ) - > UIViewController {
        devolver ScreenOneCoordinator . escena ( título : propio . título )
    }
}

struct ScreenTwoAction : Acción {
    dejar título : Cadena
    dejar subtítulo : cadena

    función escena ( ) - > UIViewController {
        devuelve ScreenTwoCoordinator . escena ( título : propio . título , subtítulo : propio . subtítulo )
    }
}

El ejemplo anterior muestra que, cuando se crean, las acciones deben contener todas las propiedades necesarias para inicializar su escena y llamar al método de los coordinadores para instanciar el UIViewController. Los coordinadores son estructuras que proporcionan un UIViewController. Aquí hay algo para mencionar: MovilePay usa un patrón de diseño en estructuras de Coordinadores, representado por un método de escena estática () encargado de generar una instancia de UIViewController para cada etapa.

 clase final HomeCoordinator : Coordinador {
    escena de función estática ( ) - > UIViewController {
        // Crea el ViewController y todos los componentes de la arquitectura de esta escena...
        devolver createdViewController
    }
}

clase final ScreenOneCoordinator : Coordinador {
    escena de función estática ( ) - > UIViewController {
        // Crea el ViewController y todos los componentes de la arquitectura de esta escena...
        devolver createdViewController
    }
}

clase final ScreenTwoCoordinator : Coordinador {
    escena de función estática ( ) - > UIViewController {
        // Crea el ViewController y todos los componentes de la arquitectura de esta escena...
        devolver createdViewController
    }
}

También se debe tener en cuenta que, a pesar del patrón de diseño arquitectónico elegido (MVC, MVP, MVVM-C, VIPER-C, VIP o cualquier otra arquitectura que use un coordinador para crear escenas y moverse de una escena a otra), la implementación usando El desarrollo impulsado por la acción y el backend es bastante apropiado.

Para el contexto Acciones MovilePay, usamos el mismo tipo de borrado que para los widgets, con una ligera adaptación.

 clase final AnyAction : Decodificable {

    enumeración privada Claves de codificación : Clave de codificación {
        identificador de caso
    }

    let action : ¿Acción ?

    requerido init ( del decodificador : Decodificador ) lanza {
        hacer {
            dejar contenedor = probar decodificador . contenedor ( con clave : CodingKeys . self )
            let type = probar contenedor . decodificar ( Identificador de acción . self , forKey : . identificador )
            uno mismo acción = tipo de prueba . metatipo init ( de : decodificador )
        } atrapar {
            uno mismo acción = cero
        }
    }
}

Una nota pertinente aquí es que MovilePay podría usar el patrón de diseño Genéricos para evitar la duplicación del código de borrado de tipos. Sin embargo, optaron por no hacerlo. El siguiente es un ejemplo de una estructura que contiene una Acción.

 struct ResponseModelForActions : Decodificable {
    enumeración privada CodingKeys"operador de token">: CodingKey { case action , text } let action : Action ? let text : String init ( from decodificador : Decodificador ) throws { let contenedor = probar decodificador . contenedor ( keyedBy : CodingKeys . self ) self . texto = probar contenedor . decodificar ( String . self , forKey :. text ) let anyAction = probar ? contenedor decodificar ( AnyAction . self , forKey : . action ) self . acción = cualquierAcción ?. acción } }

Puede ser JSON proporcionado por una API, por ejemplo, para crear un UIButton en la pantalla. El objeto de acción manejado después de que el usuario toca este botón puede realizar la acción proporcionada, lo que hace que la aplicación muestre la pantalla de inicio.

 {
    "texto" : "Texto demostrativo" ,
    "acción" : {
        "identificador" : "PANTALLA_INICIO"
    }
}

Se logró fácilmente al extender el protocolo del Coordinador para permitir que todos los coordinadores obtengan una nueva escena a través del objeto Acciones.

Permite que el coordinador actúe, es decir, genere la siguiente instancia de UIViewController para esa acción y luego la muestre.

 Coordinador de extensión {
    func escena ( usando acción : Acción ) - > UIViewController {
        acción de retorno . escena ( )
    }
}

Una pista sobre la implementación del servidor

Probablemente se esté preguntando cómo se ve todo esto en el lado del servidor. ¿Cómo no confundir sus servicios y capacidades principales con información externa? El secreto del éxito en el desarrollo de software es trabajar en capas.

Entonces, además de todos los servicios centrales complejos, MovilePay agregó otra capa al servidor que, al abstraer todos los demás servicios y aplicar toda la lógica de la aplicación, transforma los datos en la respuesta esperada por la interfaz. Esta capa se llama BFF, o Backend For Frontend, es una capa que proporciona comunicación entre dos extremos separados y no relacionados del sistema. Es donde las cadenas, las imágenes, los flujos y las variaciones de estilo se configuran y aplican a los datos subyacentes antes de enviarlos a las aplicaciones.

Conclusiones

El uso del enfoque basado en backend tiene varias ventajas, que hemos tratado de aclarar a lo largo del artículo. Sin embargo, esta es solo otra plantilla de solución. No es una píldora mágica para el desarrollo de aplicaciones. Además, se debe considerar el contexto en el que se utilizará la aplicación. ¿Necesitas crear aplicaciones para múltiples plataformas? ¿Qué tipos de pruebas le gustaría hacer? ¿Necesita un control completo sobre todas las pantallas? ¿Qué tamaño tendrán sus cargas útiles? ¿Tiene suficientes recursos para llevar a cabo este proyecto, incluido un equipo de desarrollo capaz de manejar estas tareas?

Por encima de todo, siempre debe tener cuidado con el nivel de flexibilidad que necesita. La creación de componentes de interfaz de usuario extremadamente versátiles o el uso de fuentes y márgenes no estándar puede hacer que la base de código sea increíblemente compleja, lo que lleva a una peor experiencia del usuario.

La mayoría de los proyectos no necesitan este tipo de flexibilidad. Al elegir un enfoque impulsado por el backend, es esencial considerar si tiene los recursos en forma de finanzas y un equipo de desarrollo para desarrollar y mantener un proyecto de este tipo y si puede calcular correctamente la carga útil de su aplicación.