Se é um programador de aplicações móveis, talvez tenha sonhado com a flexibilidade do desenvolvimento online para fazer alterações de layout e lógicas em tempo real e a capacidade de executar testes de hipóteses em segundos e processar resultados ainda mais rapidamente?

p>Desenvolvedores móveis são ensinados a acreditar que a velocidade com que as aplicações são lançadas e actualizadas está directamente relacionada com a rapidez com que chegam aos utilizadores. O tempo de moderação da App Store pode ser frustrantemente longo. A construção de um Kit de Desenvolvimento de Software (SDK) será ainda mais lenta porque terá de se adaptar às suas necessidades nos ciclos de desenvolvimento e lançamento de produtos de outra pessoa. Pode ser uma boa desculpa para não testar hipóteses.

Neste post do blog, vamos rever o tópico e acompanhá-lo através dos passos do Desenvolvimento Guiado por Backend-Driven, descrevendo como é usado para resolver problemas específicos e que benefícios nos trouxe. Os materiais para este post foram retirados do source sobre o exemplo da MovilePay. O autor do texto original é Rodrigo Maximo.

What is Backend Driven Development?

Backend-driven development (ou Backend-Driven Development, ou Backend-Driven UI, ou Server-Driven UI) é o conceito de desenvolvimento de aplicações front-end com base nas respostas do servidor. Os ecrãs e mudança de fluxo com base nas respostas do servidor.

A maior parte do trabalho de criação de aplicações móveis está normalmente associada à construção de uma interface de utilizador: colocar os elementos com os quais o utilizador interage nos ecrãs para que possa executar rapidamente uma ou outra acção. Alguns destes componentes são preenchidos com cargas úteis API: tipicamente JSON com tipos primitivos (inteiros, booleans, strings) ou processos de negócio de aplicações.

A abordagem tradicional de implementar ecrãs tem certos inconvenientes, uma vez que pode haver muita lógica de negócio do lado da aplicação, e o código torna-se mais difícil de manter:

>ul>
  • Need o mesmo código para muitas plataformas (Android, iOS, Web, etc.). Esta abordagem torna mais difícil manter a compatibilidade entre plataformas, o que aumenta a probabilidade de bugs e incompatibilidades;
  • Cada actualização ou modificação de uma aplicação móvel implica a necessidade de alterar o código, o que leva a uma libertação prolongada de aplicações na App Store;
  • No digital, os testes A/B são mais difíceis. É mais difícil testar conceitos e recolher dados dos utilizadores para compreender informações importantes do produto;
  • >li>li>li>Desde que a maior parte da lógica empresarial está do lado da aplicação, o código é mais desafiante de manter e manter.

    > desenvolvimento orientado para oackend- chegou para resolver estes problemas.

    >p>Considerar o seguinte cenário (que é baseado na aplicação iOS de amostra mas pode ser facilmente traduzido para qualquer outro projecto de front-end):

    >img src="https://ws.apms.io/api/_files/MzJ6ixGgg2KXjvtwxPaUpZQ/download/" title="Backend driven development scenario" width="268" height="535" alt="Scenario for backend driven development" data-mce-src="https://ws.apms.io/api/_files/MzJ6ixGg2KXjvtwxPaUpZQ/download/">

    {
        "pageTitle": "Título demonstrativo",
        "boxes": [
            {
                "type": "bigBlue",": "bigBlue"
                "title": "Caixa bonita",
                "subtítulo": "Subtitle de box"
            },
            {
                "type": "smallRed",": "smallRed"
                "title": "Grande caixa"
            },
            {
                "type": "rectangleGreen",": "rectangleGreen"
                "title": "Incredible box",
                "subtitle": "Subtitle de box",
                "number": 10
            }
        ]
    }
    p> Toda a lógica de negócio para exibir campos e exibir texto e informação visual é consolidada e abstraída no lado do servidor, eliminando a necessidade de múltiplas interfaces para processar esta API. O servidor aplica então a lógica empresarial e utiliza os seus resultados para gerar uma resposta API em formato JSON.

    No exemplo, para exibir blocos no ecrã ("bigBlue", "smallRed" e "rectangleGreen"), é utilizada informação adicional de cada campo. Curiosamente, a variável "caixas" permite ao backend processar tantos blocos como o servidor dá.

    P>Devem já ter adivinhado como pode conduzir os testes A / B nesta situação? O servidor pode seleccionar utilizadores específicos para ver apenas blocos "bigBlue", enquanto outros podem ver os três tipos de blocos. Além disso, pode conduzir testes A / B que alteram a ordem de exibição dos blocos no ecrã.

    Outro caso de uso para o Desenvolvimento orientado pelo Servidor é fazer alterações à interface de uma aplicação. Por exemplo, se precisarmos de alterar os cabeçalhos na aplicação, basta alterar a resposta do servidor de forma simples. A ordem de apresentação de legendas e blocos também é fácil de alterar. Neste caso, não é necessário publicar uma nova versão da aplicação na AppStore.

    Making changes to the interface in backend driven development

    {
        "pageTitle": "Título demonstrativo",
        "boxes": [
            {
                "type": "rectangleGreen",": "rectangleGreen"
                "title": "Outro título",
                "subtítulo": "Another subtitle",
                "number": 100
            },
            {
                "type": "smallRed",": "smallRed"
                "title": "Título diferente"
            }
            {
                "type": "bigBlue",": "bigBlue"
                "title": "Backend Driven",
                "subtítulo": "Desenvolvimento"
            }
        ]
    }

    Pense duas vezes

    Há algumas coisas a ter em mente ao utilizar a abordagem Backend Driven Development. Primeiro, que grau de flexibilidade é necessário?

    p>Baseado na experiência e investigação, consideramos que a flexibilidade média é óptima.

    Não se deve apressar de um extremo a outro. Uma grande quantidade de liberdade pode afectar negativamente o retorno do seu desenvolvimento. Não pode prever tudo, especialmente porque as especificações do dispositivo ou o tamanho do ecrã estão fora do seu controlo. Finalmente, acaba com uma lógica de apresentação do lado da aplicação muito confusa e sobrecarregada. Além disso, não pode antecipar tudo o que a sua equipa de design possa querer fazer no futuro. Assim, ainda terá de fazer alterações ao código da aplicação, e, durante os testes, serão descobertas inúmeras rotas complexas para atingir o objectivo.

    Por isso, em conclusão, não precisará da flexibilidade que o HTML tem na grande maioria dos casos. Portanto, antes de desenvolver ecrãs e soluções de servidor que utilizem a ideia de Backend-Driven Development, sugerimos que pense em todas as opções possíveis.

    A Super App Creation, Movile Tech Case

    Vocês estão provavelmente familiarizados com o conceito de super aplicação e já ouviram falar de uma aplicação como a WeChat. WeChat é uma plataforma de mensagens móveis e rede social desenvolvida na China e tornou-se extremamente popular em todo o mundo.

    Tal aplicação visa recolher vários serviços recorrentes num único local e oferecer aos utilizadores um único ponto de acesso à maioria das consultas on-line da sua vida diária. É o Santo Graal do desenvolvimento de software: reunindo muitas funcionalidades para que tudo pareça um só, oferecendo aos utilizadores respostas simples a perguntas complexas e soluções para grandes problemas.

    No passado, a MovilePay esteve envolvida no desenvolvimento de uma super aplicação, cujo processo de desenvolvimento de uma versão melhorada é descrito neste artigo. Devia ser um centro de testes e validação onde a equipa podia testar novos serviços e encontrar terreno comum na sua utilização.

    MovilePay teve um problema ao criar uma aplicação que podia rapidamente fazer alterações ao código. Era necessário testar muitos serviços e serviços e realizar pesquisas sobre o comportamento dos utilizadores com base na informação apresentada e testar hipóteses. A MovilePay queria ser capaz de ligar e desligar rapidamente as funcionalidades. Em tais condições, era impossível utilizar a abordagem tradicional com uma liberação para cada alteração. Considerando todos estes pontos e um cenário complexo, foi decidido aplicar o Backend-Driven Development.

    MovilePay criou um ecrã inicial baseado em categorias para resolver este problema. Cada secção tem o seu próprio conjunto de itens chamados widgets. As secções exibiram pontos de entrada para quaisquer serviços já implementados em qualquer ordem e destacaram widgets individuais.

    Algumas vezes apenas um serviço foi exibido. Outras vezes havia três, dependendo do que estava actualmente a ser testado. A MovilePay deixou a escolha para o servidor em vez de codificar qualquer regra na aplicação. Como resultado, a aplicação só conhece a definição do ponto de entrada do serviço e como renderizar cada estilo em particular. O seu servidor diz quais os serviços que devem ser gerados e em que ordem. Aqui estão alguns widgets que a aplicação MovilePay pode exibir.

    Widgets que a aplicação MovilePay

    >Widgets na aplicação MovilePay

    Widgets na aplicação MovilePay

    Widgets na aplicação MovilePay

    >p> Assim, para criar um ecrã inicial altamente adaptável, tivemos de obter uma resposta do backend com uma lista de secções, cada uma contendo uma lista de widgets. O seguinte é um exemplo de uma resposta JSON que a aplicação MovilePay deve analisar e criar um ecrã inicial como o exemplo abaixo.

    >Parsing and creating a home screen

    [
        {
            "title": "Section 1",
            "widgets": [
                {
                    "identificador": "COLECTION_WIDGET",
                    "content": [
                        {
                            "title": "Title A",
                            "image": "A",
                            "color": "yellow"
                        },
                        {
                            "title": "Title B",
                            "image": "B",
                            "color": "blue"
                        },
                        {
                            "title": "Title C",
                            "image": "C",
                            "color": "red"
                        },
                        {
                            "title": "Title D",
                            "image": "D",
                            "color": "roxo"
                        },
                        {
                            "title": "Title E",
                            "image": "E",
                            "color": "green"
                        }
                    ]
                },
                {
                    "identificador": "IMAGES_WIDGET",
                    "content": [
                        {
                            "image": "Image",
                            "color": "green"
                        },
                        {
                            "image": "Image",
                            "color": "blue"
                        },
                        {
                            "image": "Image",
                            "color": "orange"
                        }
                    ]
                },
                {
                    "identificador": "COLECTION_WIDGET",
                    "content": [
                        {
                            "title": "Title E",
                            "image": "E",
                            "color": "green"
                        },
                        {
                            "title": "Title F",
                            "image": "F",
                            "color": "roxo"
                        },
                        {
                            "title": "Title G",
                            "image": "G",
                            "color": "red"
                        },
                        {
                            "title": "Title H",
                            "image": "H",
                            "color": "blue"
                        },
                        {
                            "title": "Title H",
                            "image": "H",
                            "color": "yellow"
                        }
                    ]
                }
            ]
        },
        {
            "title": "Section 2",
            "widgets": [
                {
                    "identificador": "CELLS_WIDGET",
                    "content": [
                        {
                            "title": "Cell 1",
                            "color": "red"
                        },
                        {
                            "title": "Cell 2",
                            "color": "roxo"
                        },
                        {
                            "title": "Cell 3",
                            "color": "yellow"
                        },
                        {
                            "title": "Cell 4",
                            "color": "blue"
                        },
                        {
                            "title": "Cell 5",
                            "color": "verde escuro"
                        }
                    ]
                }
            ]
        }
    ]

    Também passaremos por alguns ecrãs que podem ser construídos utilizando desenvolvimento orientado por backend.

    >Home screens in backend-driven development

    Navegação flexível

    A Super Aplicação desenvolvida pela MovilePay atingiu o seu objectivo pretendido de ser inovadora. A MovilePay aprendeu muito com o teste de hipóteses, mas uma coisa em que são particularmente bons é no processamento de pagamentos ou no processo de pagamento de vários serviços e produtos. Eles tinham uma aplicação de pagamento que podia processar pagamentos para qualquer serviço que prestassem. A capacidade de gerir transacções de pagamento era uma vantagem significativa, uma vez que a MovilePay podia fazer baixar os preços através do processamento de múltiplas transacções e ganhar conhecimentos valiosos sobre o comportamento do consumidor.

    >p>MovilePay decidiu desenvolver um SDK de pagamento baseado no modelo Google Pay, Apple Pay, ou VisaCheckout que podia ser integrado com qualquer outra aplicação.

    No entanto, uma vez que trabalhar num SDK implica muito pouca capacidade de testar utilizando padrões de desenvolvimento típicos, a automatização é necessária.

    p>p>Desde que a MovilePay lidava com pagamentos, a transformação dos fluxos era crítica. A MovilePay não podia dar-se ao luxo de perder os seus utilizadores em qualquer fase de conversão de funil. Por conseguinte, era necessário optimizar todo o processo comercial - desde o registo do utilizador até à adição de um cartão e ao pagamento. Foi aí que o desenvolvimento orientado por Backend-Driven voltou a ser útil, transformando o servidor no "navegador" da aplicação.

    Optimizing the business process with BDD

    Nenhum dos ecrãs da aplicação MovilePay sabia qual era o ecrã seguinte. Após o ecrã anterior ter completado as suas tarefas, o servidor era responsável por devolver qual o ecrã que deveria ser exibido a seguir.

    Roteiros eram acções que uma aplicação podia reconhecer e responder através de uma estrutura conhecida como Router. O mecanismo de login incluía dois ramos de acção separados: um para o título da página e outro para outros elementos (tais como uma mudança de nome de utilizador ou uma nova palavra-passe) que foram encontrados na árvore de acção. O router processou-os enviando-os para o servidor, que depois interpretou as suas acções e determinou quais as interpretações que deveriam estar no ecrã seguinte.

    Esta modesta mudança de estratégia permitiu racionalizar. A MovilePay tentou muitas formas diferentes de exibir o formulário de inscrição. Foi possível testar se é preferível mostrar o ecrã de checkout antes ou depois de adicionar o cartão. Por exemplo, esta é uma das razões pelas quais a MovilePay foi capaz de aumentar a sua taxa de conversão em 30% em comparação com outras opções de pagamento.

    Outro exemplo é como a MovilePay utilizou o Backend-Driven Development para resolver os seus problemas. Pensamos que se está a perguntar como aplicar esta abordagem na prática. Deixe-me mostrar-lhe como é fácil.

    Existem muitos métodos alternativos para alcançar o mesmo objectivo. Mostrar-lhe-emos como a MovilePay o fez para o iOS. Se desejar, este conceito pode ser aplicado a qualquer outra plataforma front-end.

    Quando a MovilePay o implementou, consideraram requisitos como a facilidade de acrescentar widgets adicionais, legibilidade do código, e responsabilidade única. Para tornar as coisas mais simples e mais nativas, a MovilePay decidiu utilizar o API codificável para serialização.

    Widgets (iOS)

    Em termos de flexibilidade, a MovilePay considerou que a melhor solução seria generalizar os widgets que precisavam de ser analisados com um protocolo. MovilePay também estabelece um enumero para determinar qual a estrutura de widgets a analisar os dados.

    protocol Widget: Decodable {}
    
    enum WidgetIdentifier: String, Decodable {
        case banner =/span> "BANNER"
        case colecção =/span> "COLECTION"
        case lista =/span> "LISTA"
    
        var metatype: Widget.Type {
            switch self {
            case .banner:
                return BannerWidget.self
            case .collection:
                return CollectionWidget.self
            case .list:
                return ListWidget.self
            }
        }
    }
    p>p>Estão a tirar partido do API codificável através do protocolo Decodable implementado pelo protocolo Widget. Abaixo está um exemplo de definição de uma estrutura widget.

    struct BannerWidget: Widget {
        private let imageURLString: String
    }
    
    struct CollectionWidget: Widget {
    
        structure Item: Decodable {
            let imageURLString: String
            let title: String
            let subtitle: String
        }
    
        let sectionTitle: String
        let lista: [Item]
    }
    
    struct ListWidget: Widget {
    
        structure Item: Decodable {
            let imageURLString: String
            let text: String
        }
    
        let sectionTitle: String
        let lista: [Item]
    }
    p>p>Finalmente, foi definido como uma rasura de tipo, que interpretou qualquer widget com o método de inicialização requerido, quando é necessário alterar a inicialização personalizada dada por Decodable.

    final class AnyWidget: Decodable {
    
        private enum CodingKeys: CodingKey {
            case identificador
        }
    
        let widget: Widget?
    
        necessário init(from decoder: Decoder) throw {
            do {
                let container =/span> try decoder.>>span class="token function">container>>span class="token punctuation">(keyedBy: CodingKeys.self)
                let tipo =/span> try container.decode(WidgetIdentifier.self, forKey: .identifier)
                self.widget = try type.metatype.>init(de: descodificador)
            } catch {
                self.widget = nil
            }
        }
    }
    >p> Este tipo de apagamento é utilizado para descodificar o identificador do Widget e a sua propriedade "meta-type" para determinar que estrutura de widget deve ser utilizada para analisar o resto dos dados do Widget analisado.

    Tudo isto resulta em que a estrutura abaixo possa analisar uma resposta contendo toda a informação sobre os widgets. Tem uma característica única: um conjunto de tipos de protocolo Widget e pode decifrar cada Widget usando o tipo de apagamento definido acima.

    struct HomeResponse: Decodable {
    
        private enum CodingKeys: CodingKey {
            case widgets
        }
    
        let widgets: [Widget]
    
        init(from decoder: Decoder) throw {
            let container =/span> try decoder.>>span class="token function">container>>span class="token punctuation">(keyedBy: CodingKeys.self)
            self.widgets = try container.>decode([AnyWidget].self, forKey: .widgets).compactMap {$0.widget }
        }
    
        init(widgets:>>span class="token punctuation">[Widget]>>span class="token punctuation">) {>
            self.widgets = widgets
        }
    }
    >p>MovilePay poderia ter escolhido outras opções, tais como não utilizar o protocolo e contar com o backend para devolver um conjunto de cada widget suportado para análise. No entanto, descobrimos que a nossa escolha de protocolo foi a melhor escolha para manutenção e legibilidade. Esta abordagem foi suficiente para criar uma nova estrutura e acrescentar casos ao enumerar cada vez que foi necessário criar um novo widget. Com um sistema diferente numa situação semelhante, a concepção da HomeResponse teria de ser alterada.

    Below é uma possível resposta JSON API que este modelo parse.

    {
        "widgets": [
            {
                "identificador": "BANNER",
                "imageURLString": "url_image_to_be_downloaded"
            },
            {
                "identificador": "COLECTION",
                "sectionTitle": "Section Title",
                "list": [
                    {
                        "imageURLString": "url_image_to_be_downloaded",
                        "title": "Title item 1",
                        "subtitle": "Subtitle item 1"
                    },
                    {
                        "imageURLString": "url_image_to_be_downloaded",
                        "title": "Title item 2",
                        "subtitle": "Subtitle item 2"
                    },
                    {
                        "imageURLString": "url_image_to_be_downloaded",
                        "title": "Title item 3",
                        "subtitle": "Subtitle item 3"
                    }
                ]
            },
            {
                "identificador": "LISTA",
                "sectionTitle": "Section Title",
                "list": [
                    {
                        "imageURLString": "url_image_to_be_downloaded",
                        "text": "Text item 1"
                    },
                    {
                        "imageURLString": "url_image_to_be_downloaded",
                        "text": "Text item 2"
                    },
                    {
                        "imageURLString": "url_image_to_be_downloaded",
                        "text": "Text item 3"
                    }
                ]
            },
            {
                "identificador": "BANNER",
                "imageURLString": "url_image_to_be_downloaded"
            }
        ]
    }
    p> Esta abordagem está muito próxima do desenvolvimento da Super App, que permitiu à MovilePay apresentar diferentes serviços a diferentes utilizadores, testar muitas opções de exibição, elaborar hipóteses, e determinar que widget será utilizado para cada serviço. A mudança na classificação do ecrã e no agrupamento de serviços estava próxima do que a MovilePay tinha feito antes.

    h2>Navigation (iOS)

    Depois de corrigir a questão do widget, a MovilePay tentou melhorar a navegação de forma semelhante. Criaram o protocolo Action, que era idêntico ao protocolo Widget.

    Uma Action é um objecto estruturado devolvido na resposta JSON de alguns APIs MovilePay, com um ID e quaisquer parâmetros que deveriam ser exibidos na cena que representa. Como resultado, o protocolo Action é responsável por ajudar a desconstruir o objecto estruturado.

    protocol Action: Decodable {
        func scene() -> UIViewController
    }
    
    enum ActionIdentifier: String, Decodable {
        case home =/span> "HOME"
        case screenOne =/span> "SCREEN_ONE"
        case screenTwo = "SCREEN_TWO"
    
        var metatype: Action.Type {
            switch self {
            case .home:
                return HomeAction.self
            case .screenOne:
                return ScreenOneAction.self
            case .screenTwo:
                return ScreenTwoAction.self
            }
        }
    }
    view raw
    >p> A única diferença entre o protocolo de Acção e o protocolo Widget é que fornecemos um método que devolve a cena apropriada para cada Acção na definição de Acção. Como exemplo, ver como estas acções são implementadas.

    struct HomeAction: Action {
        func scene() -> UIViewController {
            return HomeCoordinator.scene()
        }
    }
    
    structure ScreenOneAction: Action {
        let title: String
    
        func scene() -> UIViewController {
            return ScreenOneCoordinator.scene(title: self.title)
        }
    }
    
    struct ScreenTwoAction: Action {
        let title: String
        let subtitle: String
    
        func scene() -> UIViewController {
            return ScreenTwoCoordinator.scene(title: self.title, subtitle: self.subtitle)
        }
    }
    >p> O exemplo acima mostra que, quando criadas, as Acções devem conter todas as propriedades necessárias para inicializar a sua cena e para chamar o método dos Coordenadores para instanciar o UIViewController. Os Coordenadores são estruturas que fornecem um UIViewController. Aqui está algo a mencionar: A MovilePay utiliza um padrão de desenho em estruturas de Coordenadores, representado por um método de cena estática() encarregado de gerar uma instância UIViewController para cada etapa.

    final">final class HomeCoordinator: Coordinator {
        static func scene() -> UIViewController {
            // Criar o ViewController e todos os componentes de arquitectura desta cena...
            return createdViewController
        }
    }
    
    final class ScreenOneCoordinator: Coordinator {
        static func scene() -> UIViewController {
            // Criar o ViewController e todos os componentes de arquitectura desta cena...
            return createdViewController
        }
    }
    
    final class ScreenTwoCoordinator: Coordenador {
        static func scene() -> UIViewController {
            // Criar o ViewController e todos os componentes de arquitectura desta cena...
            return createdViewController
        }
    }
    >p> É também de notar que, apesar do padrão de desenho arquitectónico escolhido (MVC, MVP, MVVM-C, VIPER-C, VIP, ou qualquer outra arquitectura que utilize um coordenador para criar cenas e mover-se de uma cena para outra), a implementação utilizando Action e Backend-Driven Development é bastante apropriada.

    Para o contexto das Acções MovilePay, utilizámos o mesmo tipo de apagamento que para os widgets, com uma ligeira adaptação.

    final">final class AnyAction: Decodable {
    
        private enum CodingKeys: CodingKey {
            case identificador
        }
    
        let action: Action?
    
        necessário init(from decoder: Decoder) throw {
            do {
                let container =/span> try decoder.>>span class="token function">container>>span class="token punctuation">(keyedBy: CodingKeys.self)
                let tipo =/span> try container.decode(ActionIdentifier.self, forKey: .identifier)
                self.acção =/span> try type.metatype>init(de: descodificador)
            } catch {
                self.action = nil
            }
        }
    }
    >p> Uma nota pertinente aqui é que a MovilePay poderia usar o padrão de desenho dos Genéricos para evitar a duplicação do código de apagamento do tipo. No entanto, eles optaram por não o fazer. O seguinte é um exemplo de uma estrutura que contém uma Action.

    struct ResponseModelForActions: Decodable {
        private enum CodingKeys: CodingKey {
            case action, text
        }
    
        let action: Action?
        let text: String
    
        init(from decoder: Decoder) throw {
            let container =/span> try decoder.>>span class="token function">container>>span class="token punctuation">(keyedBy: CodingKeys.self)
            self.text =/span> try container.decode(Stringself, forKey: .text)
            let qualquerAcção =/span> try? container>decode(AnyAction.self, forKey: .action)
            self.acção =/span> qualquerAcção?.acção
        }
    }
    >p> Pode ser JSON fornecido por um API, por exemplo, para criar um UIButton no ecrã. O objecto de acção manuseado após o utilizador tocar neste botão pode executar a acção fornecida, fazendo com que a aplicação exiba o ecrã inicial.

    {
        "text": "Texto demonstrativo",
        "action": {
            "identificador": "HOME_SCREEN"
        }
    }
    p> Foi facilmente alcançado através da extensão do protocolo do Coordenador para permitir a todos os coordenadores obter uma nova cena através do objecto Acções.

    Permite ao coordenador agir, ou seja, gerar a próxima instância UIViewController para essa acção e depois exibi-la.

    extension Coordinator {
        func scene(using action: Acção) -> UIViewController {
            returnacção.scene()
        }
    }

    Uma dica sobre a implementação do servidor

    Vocês provavelmente estão a perguntar-se como é que tudo isto se parece no lado do servidor. Como não confundir os seus serviços e capacidades centrais com informação externa? O segredo para o sucesso no desenvolvimento de software é trabalhar em camadas.

    p> Então, além de todos os serviços centrais complexos, a MovilePay adicionou outra camada ao servidor, que, abstraindo todos os outros serviços e aplicando toda a lógica da aplicação, transforma os dados na resposta esperada pelo frontend. Esta camada chama-se BFF, ou Backend For Frontend é uma camada que proporciona comunicação entre duas extremidades separadas e não relacionadas do sistema. É onde cordas, imagens, fluxos, e variações de estilo são configurados e aplicados aos dados subjacentes antes de os enviar para as aplicações.

    h2>Conclusionsp>Usar a abordagem Backend-Driven tem várias vantagens, que tentámos esclarecer ao longo do artigo. No entanto, este é apenas mais um modelo de solução. Não é uma pílula mágica para o desenvolvimento de aplicações. Além disso, o contexto em que a aplicação será utilizada deve ser considerado. Precisa de criar aplicações para múltiplas plataformas? Que tipos de testes gostaria de fazer? Precisa de controlo completo sobre todos os ecrãs? Qual será o tamanho das suas cargas úteis? Tem recursos suficientes para realizar este projecto, incluindo uma equipa de desenvolvimento capaz de lidar com estas tarefas?

    Acima de tudo, deve ter sempre cuidado com o nível de flexibilidade de que necessita. Criar componentes de IU extremamente versáteis ou utilizar fontes e margens não padronizadas pode tornar a base de códigos incrivelmente complexa, levando a uma pior experiência do utilizador.

    A maioria dos projectos não precisa deste tipo de flexibilidade. Ao escolher uma abordagem Backend-Driven, é essencial considerar se tem os recursos sob a forma de finanças e uma equipa de desenvolvimento para desenvolver e manter tal projecto e se pode calcular correctamente a carga útil da sua aplicação.