Si vous êtes un développeur d'applications mobiles, peut-être avez-vous rêvé de la flexibilité du développement en ligne pour apporter des changements de mise en page et de logique à la volée et la possibilité d'exécuter des tests d'hypothèse en quelques secondes et de traiter les résultats encore plus rapidement ?

Les développeurs mobiles apprennent à croire que la vitesse à laquelle les applications sont publiées et mises à jour est directement liée à la rapidité avec laquelle elles parviennent aux utilisateurs. Le temps de modération de l'App Store peut être frustrant. La création d'un kit de développement logiciel (SDK) sera encore plus lente car vous devez adapter vos besoins aux cycles de développement et de publication de produits de quelqu'un d'autre. Cela peut être une bonne excuse pour ne pas du tout tester des hypothèses.

Dans cet article de blog, nous passerons en revue le sujet et vous guiderons à travers les étapes du développement piloté par le backend, décrivant comment il est utilisé pour résoudre des problèmes spécifiques et quels avantages il nous a apportés. Les matériaux pour ce poste ont été tirés de la source sur l'exemple de MovilePay. L'auteur du texte original est Rodrigo Maximo.

Qu'est-ce que le développement piloté par le backend ?

Le développement piloté par le backend (ou Backend-Driven Development, ou Backend-Driven UI, ou Server-Driven UI) est le concept de développement d'applications front-end basées sur les réponses du serveur. Les écrans et le flux changent en fonction des réponses du serveur.

L'essentiel du travail de création d'applications mobiles est généralement associé à la construction d'une interface utilisateur : placer les éléments avec lesquels l'utilisateur interagit sur des écrans afin qu'il puisse effectuer rapidement telle ou telle action. Certains de ces composants sont remplis de charges utiles d'API : généralement JSON avec des types primitifs (entiers, booléens, chaînes) ou des processus métier d'application.

L'approche traditionnelle de mise en œuvre des écrans présente certains inconvénients, car il peut y avoir beaucoup de logique métier du côté de l'application et le code devient plus difficile à maintenir :

  • Besoin du même code pour de nombreuses plateformes (Android, iOS, Web, etc.). Cette approche rend plus difficile le maintien de la compatibilité entre plates-formes, ce qui augmente le risque de bogues et d'incompatibilités ;
  • Chaque mise à jour ou modification d'une application mobile implique la nécessité de changer le code, ce qui entraîne une sortie étendue des applications dans l'App Store ;
  • En numérique, les tests A/B sont plus difficiles. Il est plus difficile de tester des concepts et de collecter des données auprès des utilisateurs pour comprendre les informations importantes sur les produits ;
  • Étant donné que la majeure partie de la logique métier se trouve du côté de l'application, le code est plus difficile à maintenir et à maintenir.

Le développement orienté backend est arrivé pour résoudre ces problèmes.

Considérez le scénario suivant (qui est basé sur l'exemple d'application iOS mais peut facilement être traduit dans n'importe quel autre projet frontal) :

Scenario for backend driven development

 {
    "pageTitle" : "Titre démonstratif" ,
    "boîtes" : [
        {
            "type ": "bigBlue" ,
            « titre » : « Jolie boîte » ,
            "sous-titre" : "Sous-titre de la boîte"
        } ,
        {
            "type " : "petitrouge" ,
            « titre » : « Super coffret »
        } ,
        {
            "type ": "rectangleVert" ,
            « titre » : « Incroyable coffret » ,
            "sous-titre" : "Sous-titre de la boîte" ,
            "nombre" : 10
        }
    ]
}

Toute la logique métier pour l'affichage des champs et l'affichage des informations textuelles et visuelles est consolidée et abstraite côté serveur, éliminant ainsi le besoin de plusieurs interfaces pour traiter cette API. Le serveur applique ensuite la logique métier et utilise ses résultats pour générer une réponse API au format JSON.

Dans l'exemple, pour afficher des blocs à l'écran ("bigBlue", "smallRed" et "rectangleGreen"), des informations supplémentaires de chaque champ sont utilisées. Fait intéressant, la variable "boxes" permet au backend de traiter autant de blocs que le serveur en donne.

Avez-vous probablement déjà deviné comment effectuer des tests A/B dans cette situation ? Le serveur peut sélectionner des utilisateurs spécifiques pour afficher uniquement les blocs "bigBlue", tandis que d'autres peuvent voir les trois types de blocs. En outre, vous pouvez effectuer des tests A / B qui modifient l'ordre d'affichage des blocs à l'écran.

Un autre cas d'utilisation du développement piloté par le serveur consiste à apporter des modifications à l'interface d'une application. Par exemple, si nous devons changer les en-têtes dans l'application, il suffit de changer simplement la réponse du serveur. L'ordre d'affichage des sous-titres et des blocs est également facile à modifier. Dans ce cas, vous n'avez pas besoin de publier une nouvelle version de l'application dans l'AppStore.

Making changes to the interface in backend driven development

 {
    "pageTitle" : "Titre démonstratif" ,
    "boîtes" : [
        {
            "type ": "rectangleVert" ,
            « titre » : « Un autre titre » ,
            « sous-titre » : « Un autre sous-titre » ,
            "nombre" : 100
        } ,
        {
            "type " : "petitrouge" ,
            "titre" : "Titre différent"
        }
        {
            "type ": "bigBlue" ,
            « titre » : « Piloté par le backend » ,
            « sous-titre » : « Développement »
        }
    ]
}

Réfléchissez à deux fois

Il y a quelques points à garder à l'esprit lors de l'utilisation de l'approche Backend Driven Development. Tout d'abord, de quel degré de flexibilité avez-vous besoin ?

Sur la base de l'expérience et de la recherche, nous considérons que la flexibilité moyenne est optimale.

Il ne faut pas se précipiter d'un extrême à l'autre. Une grande quantité de liberté peut affecter négativement le retour sur investissement de votre développement. Vous ne pouvez pas tout prévoir, d'autant plus que les spécifications de l'appareil ou la taille de l'écran sont hors de votre contrôle. Enfin, vous vous retrouvez avec une logique de présentation côté application très confuse et surchargée. De plus, vous ne pouvez pas anticiper tout ce que votre équipe de conception pourrait vouloir faire à l'avenir. Ainsi, vous devez encore apporter des modifications au code de l'application et, lors des tests, de nombreux itinéraires complexes pour atteindre l'objectif seront découverts.

Donc, en conclusion, vous n'aurez pas besoin de la flexibilité du HTML dans la grande majorité des cas. Par conséquent, avant de développer des écrans et des solutions de serveur qui utilisent l'idée de développement piloté par le backend, nous vous suggérons de réfléchir à toutes les options possibles.

Une super création d'application, Movile Tech Case

Vous connaissez probablement le concept de super application et avez entendu parler d'une application comme WeChat. WeChat est une plateforme de messagerie mobile et un réseau social développé en Chine et devenu extrêmement populaire dans le monde entier.

Une telle application vise à rassembler plusieurs services récurrents en un seul endroit et à offrir aux utilisateurs un point d'accès unique à la plupart des requêtes en ligne de leur vie quotidienne. C'est le Saint Graal du développement logiciel : rassembler de nombreuses fonctionnalités pour que tout ressemble àe, offrant aux utilisateurs des réponses simples à des questions complexes et des solutions à de gros problèmes.

Dans le passé, MovilePay a été impliqué dans le développement d'une super application, dont le processus de développement d'une version améliorée est décrit dans cet article. Il était censé être un centre de test et de validation où l'équipe pouvait tester de nouveaux services et trouver un terrain d'entente dans leur utilisation.

MovielePay a eu un problème lors de la création d'une application capable de modifier rapidement le code. Cela a nécessité de tester de nombreux services et services et de mener des recherches sur le comportement des utilisateurs en fonction des informations affichées et de tester des hypothèses. MovielePay voulait pouvoir activer et désactiver rapidement les fonctionnalités. Dans ces conditions, il était impossible d'utiliser l'approche traditionnelle avec une libération pour chaque changement. Compte tenu de tous ces points et d'un scénario complexe, il a été décidé d'appliquer le développement piloté par le backend.

MovielePay a créé un écran d'accueil basé sur les catégories pour résoudre ce problème. Chaque section a son propre ensemble d'éléments appelés widgets. Les sections affichaient des points d'entrée pour tous les services déjà mis en œuvre dans n'importe quel ordre et mettaient en évidence des widgets individuels.

Parfois, un seul service était affiché. D'autres fois, il y en avait trois, selon ce qui était actuellement testé. MovielePay a laissé le choix au serveur plutôt que de coder en dur une règle dans l'application. Par conséquent, l'application ne connaît que la définition du point d'entrée du service et comment rendre chaque style particulier. Leur serveur indique quels services doivent être générés et dans quel ordre. Voici quelques widgets que l'application MovielePay peut afficher.

Widgets that the MovilePay application

Widgets in MovilePay application

Widgets in MovilePay application

Widgets in MovilePay application

Ainsi, pour créer un écran d'accueil hautement adaptable, nous avons dû obtenir une réponse du backend avec une liste de sections, chacune contenant une liste de widgets. Voici un exemple de réponse JSON que l'application MovilePay doit analyser et créer un écran d'accueil comme dans l'exemple ci-dessous.

Parsing and creating a home screen

 [
    {
        "titre" : "Section 1" ,
        "widget" : [
            {
                "identifiant" : "COLLECTION_WIDGET" ,
                "contenu" : [
                    {
                        "title" : "Titre A" ,
                        "image" : "A" ,
                        "couleur" : "jaune"
                    } ,
                    {
                        "title" : "Titre B" ,
                        "image" : "B" ,
                        "couleur" : "bleu"
                    } ,
                    {
                        "title" : "Titre C" ,
                        "image" : "C" ,
                        "couleur" : "rouge"
                    } ,
                    {
                        "title" : "Titre D" ,
                        "image" : "D" ,
                        "couleur" : "violet"
                    } ,
                    {
                        "title" : "Titre E" ,
                        "image" : "E" ,
                        "couleur" : "vert"
                    }
                ]
            } ,
            {
                "identifiant" : "IMAGES_WIDGET" ,
                "contenu" : [
                    {
                        "image" : "Image" ,
                        "couleur" : "vert"
                    } ,
                    {
                        "image" : "Image" ,
                        "couleur" : "bleu"
                    } ,
                    {
                        "image" : "Image" ,
                        "couleur" : "orange"
                    }
                ]
            } ,
            {
                "identifiant" : "COLLECTION_WIDGET" ,
                "contenu" : [
                    {"title" : "Titre E" , "image" : "E" , "color" : "vert" } , { "title" : "Titre F" , "image" : "F" , "color" : "violet " } , { "title" : "Title G" , "image" : "G" , "color" : "red" } , { "title" : "Title H" , "image" : "H" , "color " : "bleu" } , { "title" : "Titre H" , "image" : "H" , "color" : "jaune" } ] } ] } , { "title" : "Section 2" , "widgets " : [ { "identifier" : "CELLS_WIDGET" , "content" : [ { "title" : "Cell 1" , "color" : "red" } , { "title" : "Cell 2" , "color" : "violet" } , { "title" : "Cellule 3" , "color" : "jaune" } , { "title" : "Cellule 4" , "color" : "blue" } , { "title" : "Cellule 5" , "couleur" : "vert foncé" } ] } ] } ]

Nous passerons également en revue certains écrans qui peuvent être créés à l'aide d'un développement piloté par le backend.

Home screens in backend-driven development

Navigation souple

La Super App développée par MovilePay a atteint son objectif d'innovation. MovilePay a beaucoup appris des tests d'hypothèses, mais une chose dans laquelle ils sont particulièrement doués est le traitement des paiements ou le processus de paiement pour divers services et produits. Ils avaient une application de paiement qui pouvait traiter les paiements pour n'importe quel service qu'ils fournissaient. La capacité à gérer les transactions de paiement était un avantage significatif, car MovilePay pouvait faire baisser les prix en traitant plusieurs transactions et en obtenant des informations précieuses sur le comportement des consommateurs.

MovilePay a décidé de développer un SDK de paiement basé sur le modèle Google Pay, Apple Pay ou VisaCheckout qui pourrait être intégré à n'importe quelle autre application.

Cependant, étant donné que travailler sur un SDK implique très peu de capacité à tester à l'aide de modèles de développement typiques, l'automatisation est nécessaire.

Depuis que MovielePay s'occupait des paiements, la transformation des flux était critique. MovielePay ne pouvait pas se permettre de perdre ses utilisateurs à n'importe quelle étape de l'entonnoir de conversion. Par conséquent, l'optimisation de l'ensemble du processus commercial était nécessaire, de l'enregistrement de l'utilisateur à l'ajout d'une carte et au paiement. C'est là que le développement piloté par le backend est à nouveau utile, transformant le serveur en "navigateur" de l'application.

Optimizing the business process with BDD

Aucun des écrans de l'application MovilePay ne savait quel écran était le suivant. Une fois que l'écran précédent avait terminé ses tâches, le serveur était chargé de renvoyer l'écran à afficher ensuite.

Les routes étaient des actions qu'une application pouvait reconnaître et auxquelles répondre via une structure connue sous le nom de routeur. Le mécanisme de connexion comprenait deux branches d'action distinctes : une pour le titre de la page et une pour les autres éléments (tels qu'un changement de nom d'utilisateur ou un nouveau mot de passe) rencontrés dans l'arbre d'action. Le routeur les traitait en les envoyant au serveur, qui interprétait ensuite leurs actions et déterminait quelles interprétations devaient figurer sur l'écran suivant.

Ce modeste changement de stratégie a permis une rationalisation. MovielePay a essayé de nombreuses façons différentes d'afficher le formulaire d'inscription. Il a été possible de tester s'il est préférable d'afficher l'écran de paiement avant ou après l'ajout de la carte. C'est par exemple l'une des raisons pour lesquelles MovilePay a pu augmenter son taux de conversion de 30% par rapport aux autres options de paiement.

Un autre exemple est la façon dont MovilePay a utilisé le développement piloté par le backend pour résoudre ses problèmes. Nous pensons que vous êtes émerveillécomment appliquer cette approche dans la pratique. Laissez-moi vous montrer à quel point c'est facile.

Il existe de nombreuses méthodes alternatives pour atteindre le même objectif. Nous allons vous montrer comment MovielePay l'a fait pour iOS. Si vous le souhaitez, ce concept peut être appliqué à toute autre plate-forme frontale.

Lorsque MovilePay l'a implémenté, ils ont pris en compte des exigences telles que la facilité d'ajout de widgets supplémentaires, la lisibilité du code et la responsabilité unique. Pour rendre les choses plus simples et plus natives, MovilePay a décidé d'utiliser l'API Codable pour la sérialisation.

Widget (iOS)

En termes de flexibilité, MovilePay a estimé que la meilleure solution serait de généraliser les widgets qui devaient être analysés avec un protocole. MovilePay définit également une énumération pour déterminer quelle structure de widget analyser les données.

 Widget protocolaire : Décodable { }

enum WidgetIdentifier : Chaîne , Décodable {
    bannière de cas = "BANNIÈRE"
    collection de cas = "COLLECTION"
    liste de cas = "LISTE"

    var métatype : Widget . Tapez {
        passer soi-même {
        cas . bannière :
            retourner BannerWidget . soi
        cas . collecte :
            renvoie CollectionWidget . soi
        cas . liste :
            renvoie ListWidget . soi
        }
    }
}

Ils profitent de l'API Codable via le protocole Decodable implémenté par le protocole Widget. Vous trouverez ci-dessous un exemple de définition d'une structure de widget.

 struct BannièreWidget : Widget {
    private let imageURLString : chaîne
}

struct CollectionWidget : Widget {

    struct Item : Décodable {
        laisser imageURLString : chaîne
        laisser le titre : String
        laissez le sous-titre : Chaîne
    }

    let sectionTitle : Chaîne
    let list : [ Objet ]
}

struct ListeWidget : Widget {

    struct Item : Décodable {
        laisser imageURLString : chaîne
        laisser le texte : Chaîne
    }

    let sectionTitle : Chaîne
    let list : [ Objet ]
}

Enfin, il a été défini comme un type d'effacement, qui interprète tout widget avec la méthode d'initialisation requise, lorsqu'il est nécessaire de modifier l'initialisation personnalisée donnée par Decodable.

 classe finale AnyWidget : Décodable {

    énumération privée CodingKeys : CodingKey {
        identifiant de cas
    }

    laisser widget : Widget ?

    requis init ( du décodeur : Decoder ) lance {
        faire {
            let conteneur = essayer décodeur . conteneur ( keyedBy : CodingKeys . self )
            let type = try container . décoder ( WidgetIdentifier . self , forKey : . identifier )
            soi . widget = essayer de taper . métatype . init ( de : décodeur )
        } attraper {
            soi . widget = néant
        }
    }
}

Ce type d'effacement est utilisé pour déchiffrer l'identifiant du Widget et sa propriété "méta-type" afin de déterminer quelle structure de widget doit être utilisée pour analyser le reste des données du Widget analysé.

Tout cela permet à la structure ci-dessous d'être capable d'analyser une réponse contenant toutes les informations sur les widgets. Il a une caractéristique unique : un tableau de types de protocoles Widget et peut déchiffrer chaque Widget en utilisant le type d'effacement défini ci-dessus.

 struct HomeResponse : Décodable {

    énumération privée CodingKeys : CodingKey {
        widgets de cas
    }

    laisser les widgets : [ Widget ]

    init ( du décodeur : Decoder ) lance {
        let conteneur = essayer décodeur . conteneur ( keyedBy : CodingKeys . self )
        soi . widgets = essayez le conteneur . décoder ( [ AnyWidget ] . self , forKey : . widgetsss="ponctuation symbolique">) . compactMap {$ 0. widget } } init ( widgets : [ Widget ] ) { soi . widgets = widgets } }

MovielePay aurait pu choisir d'autres options, telles que ne pas utiliser le protocole et s'appuyer sur le backend pour renvoyer un tableau de chaque widget pris en charge pour l'analyse. Cependant, nous avons constaté que notre choix de protocole était le meilleur choix pour la maintenance et la lisibilité. Cette approche était suffisante pour créer une nouvelle structure et ajouter des cas à l'énumération chaque fois qu'il fallait créer un nouveau widget. Avec un système différent dans une situation similaire, la conception de HomeResponse devrait être modifiée.

Vous trouverez ci-dessous une réponse API JSON possible que ce modèle analysera.

 {
    "widget" : [
        {
            "identifiant" : "BANNIÈRE" ,
            "imageURLString" : "url_image_to_be_downloaded"
        } ,
        {
            "identifiant" : "COLLECTION" ,
            "sectionTitle" : "Titre de la section" ,
            "liste" : [
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "title" : "Titre de l'élément 1" ,
                    "subtitle" : "Élément de sous-titre 1"
                } ,
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "title" : "Titre de l'élément 2" ,
                    "subtitle" : "Élément de sous-titre 2"
                } ,
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "title" : "Titre de l'élément 3" ,
                    "subtitle" : "Élément de sous-titre 3"
                }
            ]
        } ,
        {
            "identifiant" : "LISTE" ,
            "sectionTitle" : "Titre de la section" ,
            "liste" : [
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "text" : "élément de texte 1"
                } ,
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "text" : "élément de texte 2"
                } ,
                {
                    "imageURLString" : "url_image_to_be_downloaded" ,
                    "text" : "élément de texte 3"
                }
            ]
        } ,
        {
            "identifiant" : "BANNIÈRE" ,
            "imageURLString" : "url_image_to_be_downloaded"
        }
    ]
}

Cette approche est très proche du développement de la Super App, qui a permis à MovilePay de présenter différents services à différents utilisateurs, de tester de nombreuses options d'affichage, d'élaborer des hypothèses et de déterminer quel widget sera utilisé pour quel service. Le changement dans le tri des écrans et le regroupement des services était proche de ce que MovilePay avait fait auparavant.

Navigation (iOS)

Après avoir résolu le problème du widget, MovielePay a essayé d'améliorer la navigation de la même manière. Ils ont créé le protocole Action, qui était identique au protocole Widget.

Une action est un objet structuré renvoyé dans la réponse JSON de certaines API MovilePay, avec un ID et tous les paramètres qui doivent être affichés dans la scène qu'il représente. De ce fait, le protocole Action est chargé d'aider à déconstruire l'objet structuré.

 protocol Action : Décodable {
    func scène ( ) - > UIViewController
}

enum ActionIdentifier : Chaîne , Décodable {
    case home = "MAISON"
    cas screenOne = "SCREEN_ONE"
    cas screenTwo = "SCREEN_TWO"

    var métatype : Action . Tapez {
        passer soi-même {
        cas . maison :
            retourner HomeAction . soi
        cas . screenOneoken operator"> : renvoie ScreenOneAction . self case . screenTwo : renvoie ScreenTwoAction . self } } } view raw

La seule différence entre le protocole Action et le protocole Widget est que nous fournissons une méthode qui renvoie la scène appropriée pour chaque action dans la définition d'action. A titre d'exemple, regardez comment ces actions sont mises en œuvre.

 struct HomeAction : Action {
    func scène ( ) - > UIViewController {
        retour HomeCoordinator . scène ( )
    }
}

struct ScreenOneAction : Action {
    laisser le titre : String

    func scène ( ) - > UIViewController {
        renvoie ScreenOneCoordinator . scène ( titre : soi . titre )
    }
}

struct ScreenTwoAction : Action {
    laisser le titre : String
    laissez le sous-titre : Chaîne

    func scène ( ) - > UIViewController {
        renvoie ScreenTwoCoordinator . scène ( titre : soi . titre , sous-titre : soi . sous-titre )
    }
}

L'exemple ci-dessus montre qu'une fois créées, les Actions doivent contenir toutes les propriétés nécessaires pour initialiser leur scène et appeler la méthode Coordinators pour instancier le UIViewController. Les coordinateurs sont des structures qui fournissent un UIViewController. Voici quelque chose à mentionner : MovilePay utilise un modèle de conception dans les structures des coordinateurs, représenté par une méthode statique scene() chargée de générer une instance UIViewController pour chaque étape.

 classe finale AccueilCoordonnateur : Coordonnateur {
    scène func statique ( ) - > UIViewController {
        // Crée le ViewController et tous les composants d'architecture de cette scène...
        retourner le contrôleur de vue créé
    }
}

classe finale ScreenOneCoordinator : Coordinateur {
    scène func statique ( ) - > UIViewController {
        // Crée le ViewController et tous les composants d'architecture de cette scène...
        retourner le contrôleur de vue créé
    }
}

classe finale ScreenTwoCoordinator : Coordinateur {
    scène func statique ( ) - > UIViewController {
        // Crée le ViewController et tous les composants d'architecture de cette scène...
        retourner le contrôleur de vue créé
    }
}

Il convient également de noter que, malgré le modèle de conception architectural choisi (MVC, MVP, MVVM-C, VIPER-C, VIP ou toute autre architecture utilisant un coordinateur pour créer des scènes et passer d'une scène à l'autre), la mise en œuvre à l'aide de Le développement piloté par l'action et le backend est tout à fait approprié.

Pour le contexte Actions MovilePay, nous avons utilisé le même type d'effacement que pour les widgets, avec une légère adaptation.

 classe finale AnyAction : décodable {

    énumération privée CodingKeys : CodingKey {
        identifiant de cas
    }

    laisser agir : Action ?

    requis init ( du décodeur : Decoder ) lance {
        faire {
            let conteneur = essayer décodeur . conteneur ( keyedBy : CodingKeys . self )
            let type = try container . décoder ( ActionIdentifier . self , forKey : . identifier )
            soi . action = essayer de taper . métatype . init ( de : décodeur )
        } attraper {
            soi . action = néant
        }
    }
}

Une note pertinente ici est que MovilePay pourrait utiliser le modèle de conception génériques pour éviter la duplication du code d'effacement de type. Cependant, ils ont choisi de ne pas le faire. Voici un exemple de structure contenant une action.

 struct ResponseModelForActions : Décodable {
    enum privé CodingKeys"opérateur de jeton"> : CodingKey { action de cas , texte } let action : Action ? let text : String init ( du décodeur : Decoder ) lance { let container = try decoder . conteneur ( keyedBy : CodingKeys . self ) self . text = essayez le conteneur . decode ( String . self , forKey : . text ) let anyAction = try ? conteneur . décoder ( AnyAction . self , forKey : . action ) self . action = touteAction ?. action } }

Il peut s'agir de JSON fourni par une API, par exemple, pour créer un UIButton à l'écran. L'objet d'action géré après que l'utilisateur appuie sur ce bouton peut effectuer l'action fournie, ce qui amène l'application à afficher l'écran d'accueil.

 {
    "text" : "Texte démonstratif" ,
    "action" : {
        "identifiant" : "HOME_SCREEN"
    }
}

Cela a été facilement réalisé en étendant le protocole Coordinateur pour permettre à tous les coordinateurs d'obtenir une nouvelle scène via l'objet Actions.

Il permet au coordinateur d'agir, c'est-à-dire de générer la prochaine instance UIViewController pour cette action, puis de l'afficher.

 coordinateur de vulgarisation {
    scène func ( en utilisant action : Action ) - > UIViewController {
        action de retour . scène ( )
    }
}

Un indice sur la mise en œuvre du serveur

Vous vous demandez probablement à quoi tout cela ressemble côté serveur. Comment ne pas confondre vos services et capacités de base avec des informations externes ? Le secret du succès dans le développement de logiciels est de travailler en couches.

Ainsi, en plus de tous les services de base complexes, MovilePay a ajouté une autre couche au serveur, qui, en faisant abstraction de tous les autres services et en appliquant toute la logique d'application, transforme les données en la réponse attendue par le frontend. Cette couche est appelée BFF, ou Backend For Frontend est une couche qui assure la communication entre deux extrémités distinctes et non liées du système. C'est là que les chaînes, les images, les flux et les variations de style sont configurés et appliqués aux données sous-jacentes avant de les envoyer aux applications.

conclusion

L'utilisation de l'approche Backend-Driven présente plusieurs avantages, que nous avons essayé de clarifier tout au long de l'article. Cependant, il ne s'agit que d'un autre modèle de solution. Ce n'est pas une pilule magique pour le développement d'applications. De plus, le contexte dans lequel l'application sera utilisée doit être considéré. Avez-vous besoin de créer des applications pour plusieurs plateformes ? Quels types de tests aimeriez-vous faire ? Avez-vous besoin d'un contrôle complet sur tous les écrans ? Quelle sera la taille de vos charges utiles ? Avez-vous suffisamment de ressources pour mener à bien ce projet, y compris une équipe de développement capable de gérer ces tâches ?

Par-dessus tout, vous devez toujours faire attention au niveau de flexibilité dont vous avez besoin. La création de composants d'interface utilisateur extrêmement polyvalents ou l'utilisation de polices et de marges non standard peut rendre la base de code incroyablement complexe, entraînant une expérience utilisateur moins bonne.

La plupart des projets n'ont pas besoin de ce genre de flexibilité. Lors du choix d'une approche Backend-Driven, il est essentiel de déterminer si vous disposez des ressources financières et d'une équipe de développement pour développer et maintenir un tel projet et si vous pouvez calculer correctement la charge utile de votre application.