Certo dia chegou o pedido de criar um framework para facilitar a implementação de assinatura e criação de conta para os diversos aplicativos que desenvolvemos. A ideia desse framework é ser tão completo que conteria, inclusive, as telas, de forma que os apps precisariam chamar um único método:

Este iniciaria a navegação para as telas do framework, e no final, como resultado (no caso de sucesso), o usuário estaria logado e assinado. Só para ter uma ideia, o fluxo seria mais ou menos esse:

  1. Pedir para logar ou criar conta
  2. Validar o login ou cadastro
  3. Apresentar os planos de assinatura
  4. Exibir os termos de uso do plano escolhido
  5. Realizar a assinatura
  6. Apresentar uma mensagem de sucesso “Parabéns! Aproveite agora tudo que o app oferece”

Pensei comigo mesmo “claro, por que não? Desenvolver assinatura e conta nos apps é trabalhoso, chato e difícil de testar. Ter um framework que ofereça tudo isso com o mínimo de esforço seria ótimo”.

Iniciado o desenvolvimento do framework, comecei a perceber que não seria tão simples assim. Esse fluxo precisa ter layout e usabilidade impecáveis, afinal, é o que traz dinheiro para o app, logo precisa vender bem o produto. Como o framework vai ser usado por (potencialmente) todos os apps que trabalhamos, precisa, no mínimo, suportar todos os tamanhos de tela, tanto de smartphones quanto de tablets. Além disso, precisa funcionar em portrait e landscape. Mais do que isso, precisa suportar rotação da tela entre portrait e landscape, porque sempre pode existir um app que permite essa rotação.

Se todos esses requisitos não forem atendidos, o framework não poderia ser utilizado por qualquer app, e nesse caso não faria sentido ser desenvolvido.

Comecei a implementar a primeira tela, uma que exibe basicamente um texto introdutório e dois botões, nada que tomasse mais do que 4 horas de trabalho. Depois de 3 dias tentando adequá-la a todos os requisitos citados, decidi que seguir por esse caminho não daria certo.

Outro ponto, um dos requisitos do framework é de que as telas sejam minimamente personalizáveis, para que não fujam ao estilo visual de cada app em si. Se olharmos para os diversos apps existentes que oferecem conta e assinatura, cada um segue a sua própria identidade visual. Veja esses dois exemplos:

 

Fazer um framework oferecer um nível de personalização que atenda a esses dois casos, beira o inviável. Por outro lado, se a personalização for limitada demais, a interface empobrece e a usabilidade fica prejudicada.

Dada a dificuldade de atender a todos os requisitos e ainda oferecer algo de qualidade, pensei em uma estratégia, no mínimo, incomum. E se o framework oferecesse os fluxos de telas, mas não oferecesse as telas propriamente ditas?

Estranho, não? Vamos ver como isso seria possível na prática.

Usarei como base neste artigo o sistema iOS e Swift, porém os conceitos apresentados não se limitam nem a um sistema operacional nem a uma linguagem de programação.

Definindo uma tela

Uma tela é basicamente um UIViewController, o qual contém views, outlets, actions, métodos de lifecycle, entre outros. Podemos simplificar essa definição como um conjunto de views e um conjunto de métodos, e colocá-los em um protocolo:

Isso nos dá uma representação abstrata e alto nível do que uma tela contém e do que ela pode fazer. Se o framework definir as telas que precisa e o app às fornecê-las, conseguimos chegar na seguinte divisão de tarefas:

O que o app faz O que o framework faz
Layout das telas Comportamento de cada tela

Navegação entre as telas

Integração com APIs

Exemplo prático

Vamos construir um fluxo na prática, para trabalhar melhor a idéia. Considere o seguinte esboço de tela de login:

Temos um campo para inserir texto, um botão de confirmação e um botão para exibir os termos de uso. Podemos descrever esta tela da seguinte forma:

Utilizarei neste exemplo o conceito de Flow Controller. Cada tela terá um flow controller que servirá como um pai para a mesma, apresentando-a e adicionando comportamento aos seus botões e demais controles. A primeira tela seria utilizada da seguinte forma:

Para o flow controller não importa como a tela foi construída, apenas é importante que contenha o que está definido no protocolo. Desta forma o layout fica totalmente a cargo do app. Já o comportamento e navegação fica a cargo do flow controller. Por exemplo, uma possível implementação para a ação do botão de termos de uso seria:

Outras responsabilidades do flow controller é servir de entrada para comunicação do back-end e validação de dados. Por fim, executa a navegação para a próxima tela:

Uma implementação mais completa deste exemplo pode ser encontrado aqui.

Conclusão

Utilizando a divisão de tarefas entre view controller e flow controller conseguimos oferecer flexibilidade aos apps para construir telas que se adequem melhor às suas necessidades.

É importante perceber que não existe uma divisão clara entre o que ficará no app e que ficará no framework, e isso na verdade é muito bom. Quanto mais tarefas o framework fizer, menos esforço de desenvolvimento será exigido dos apps, no entanto é reduzida a liberdade de personalização dos apps.

Por outro lado, o comportamento das telas pode ficar inteiramente do lado do app, permitindo assim elevar a usabilidade do mesmo, no entanto o esforço será maior do lado do app, e o framework terá menos a oferecer.

Por fim, o próprio framework pode oferecer implementações padrões de telas, poupando completamente o app deste esforço. Essas implementações seriam, na prática, restritas, afinal já foi discutido no início, como o esforço para atender a todos os requisitos seria muito grande. Desta forma ganhamos:

  1. Os apps podem decidir entre usar os layouts padrões ou fornecerem seus próprios layouts.
  2. Poupamos esforço do framework em desenvolver telas que atendam a requisitos os quais, muitas vezes, nem se sabe se serão necessários.
  3. Priorizamos o desenvolvimento do framework com o que mais gera valor em primeiro (navegação, comportamento e integração), deixando para segundo plano o desenvolvimento das telas propriamente ditas.

 

Experience in iOS development since 2010. Currently developer at Wavy/Movile. Bachelor in Computer Science and M.Sc. in Visual Computer at Instituto de Computação/UNICAMP.

Posted by:Felipe Valio

Experience in iOS development since 2010. Currently developer at Wavy/Movile. Bachelor in Computer Science and M.Sc. in Visual Computer at Instituto de Computação/UNICAMP.

Deixe seu comentário