← Todos os artigos
Desenvolvimento iOS9 min de leitura

Da ideia à App Store 2: decisões técnicas e implementação

Como realizei escolhas de desenvolvimento a partir das necessidades do produto.

Este é o segundo artigo de uma série sobre meu processo de desenvolvimento do Volei+. Se você não leu o primeiro, comece por aqui. Nesta parte, vamos entrar mais a fundo nas escolhas técnicas de desenvolvimento do app.

Entre todas elas, uma decisão definiria o caminho das demais: por qual plataforma começar?

Por que o iOS como plataforma inicial?

A primeira decisão foi qual plataforma utilizar no desenvolvimento, e a escolha foi o iOS nativo. Essa decisão se baseou na especialidade do time técnico, composto, neste caso, apenas por mim, no desenvolvimento de aplicativos nativos para iOS com Swift. Também considerei desenvolver o app em Flutter, framework com o qual já tenho experiência, mas o conhecimento técnico acumulado no ecossistema da Apple me permitiria avançar mais rapidamente com o desenvolvimento nativo.

Sendo assim, o tempo de desenvolvimento e a qualidade do produto foram levados em consideração na hora da escolha. Com minha especialidade, sabia que conseguiria desenvolver uma aplicação do zero muito mais rapidamente de forma nativa. Isso me permitiu validar o produto com maior velocidade e tomar a decisão de prosseguir com o desenvolvimento. Nesse ponto, meus interesses de carreira também pesaram bastante na escolha. Eu gostaria de usar o aplicativo como um laboratório para testar funcionalidades do Swift com as quais não tinha tanto contato no dia a dia do trabalho, como Core Data e SwiftUI.

Isso me possibilitou adquirir antecipadamente experiência com essas features, ou funcionalidades, e gerar um impacto mais relevante quando precisei usá-las no meu trabalho. Em resumo, a escolha da plataforma foi muito mais influenciada pelas capacidades do time de desenvolvimento e pelos interesses futuros do que pelo próprio público naquele momento.

Porém, à medida que o app foi validado e se tornou mais relevante, ficou evidente a necessidade de expansão para o Android. Já decidi que o app nativo será substituído por uma implementação em Flutter que atenda tanto ao iOS quanto ao Android, mas ainda não defini quando começarei esse desenvolvimento.

Essa expansão virá depois. Para colocar a primeira versão nativa em funcionamento, havia uma decisão mais imediata: construir a interface com UIKit ou SwiftUI?

Por que escolhi SwiftUI em vez de UIKit?

Por ser um projeto iniciado do zero e voltado para versões recentes do iOS, eu não precisava manter componentes legados nem compatibilidade com versões antigas do sistema. Isso eliminou uma das principais razões para escolher o UIKit e me permitiu avaliar os dois frameworks a partir das necessidades técnicas do produto.

O Volei+ possui uma interface orientada a estado: listas de jogadores, times, partidas, carregamentos e mensagens de erro precisam reagir constantemente às alterações realizadas pelo usuário. A abordagem declarativa do SwiftUI se encaixou bem nesse cenário. As Views descrevem como a interface deve aparecer para cada estado, enquanto as ViewModels publicam as mudanças necessárias. Quando os dados são atualizados, o próprio framework renderiza novamente as partes afetadas, reduzindo a necessidade de sincronizar manualmente a interface com o modelo.

O SwiftUI também se integrou naturalmente às outras decisões arquiteturais do projeto. O NavigationStack trabalha com o AppRouter para centralizar as rotas, enquanto objetos compartilhados, como a sessão do usuário e o contêiner de dependências, podem ser disponibilizados para a hierarquia de telas. Além disso, os previews, visualizações prévias da interface dentro do ambiente de desenvolvimento, permitiram montar diferentes estados de uma tela e validar rapidamente componentes, alterações visuais e animações sem executar todo o fluxo do app.

O UIKit continuaria sendo uma opção relevante caso o produto exigisse componentes muito específicos, controle detalhado sobre o ciclo de vida da interface ou alguma funcionalidade ainda limitada no SwiftUI. Como essas necessidades não faziam parte do escopo inicial do Volei+, o ganho de produtividade e a integração com uma arquitetura reativa pesaram mais na decisão. Ainda assim, caso surja uma necessidade pontual, os dois frameworks podem coexistir por meio de mecanismos como o UIHostingController.

Escolher o framework resolveu como construir as telas, mas abriu uma questão maior: como organizar estado, navegação e acesso aos dados sem concentrar responsabilidades demais em cada View?

Como arquitetar tudo junto?

MVVM, MVVM-C, VIPER e MVP são arquiteturas válidas e amplamente utilizadas no desenvolvimento para iOS. Entre elas, eu precisava escolher uma que aproveitasse a reatividade do SwiftUI e, ao mesmo tempo, sustentasse o crescimento do app. O MVVM atendia bem à primeira necessidade, já que as ViewModels expõem os estados observados pelas Views. Para lidar também com a navegação, escolhi o MVVM-C.

Nesse modelo, o Coordinator, representado no Volei+ pelo AppRouter, centraliza as rotas e evita que cada View assuma a responsabilidade por definir os fluxos do app. Essa camada adicional tornou a implementação inicial um pouco mais trabalhosa, mas facilitou a inclusão de novas telas e mudanças na navegação conforme o produto evoluiu.

No entanto, organizar apenas a interface e a navegação não seria suficiente. Para evitar componentes-deus, estruturas que concentram responsabilidades demais e são modificadas por diversos motivos, eu também precisava separar a apresentação do acesso e da persistência dos dados.

Por isso, o MVVM-C ficou responsável pela camada de interface, enquanto princípios da Clean Architecture, abordagem que separa as responsabilidades do sistema em camadas e reduz o acoplamento entre elas, orientaram a organização do app como um todo. Na prática, as Views exibem o estado da interface, enquanto as ViewModels coordenam as ações do usuário e se comunicam com os repositórios por meio de protocolos, sem acessar diretamente o mecanismo de persistência.

Os repositórios fazem a ponte entre as ViewModels e os Data Sources, fontes que concentram os detalhes de acesso e conversão dos dados armazenados no Core Data. O AppContainer, por sua vez, centraliza a criação dessas dependências e as injeta nas ViewModels. Essa organização também facilita os testes, pois uma implementação real pode ser substituída por um mock, objeto que simula uma dependência, sem alterar a camada de interface.

Essa separação será especialmente importante na próxima evolução do produto. Quando o backend estiver disponível, poderei criar uma nova fonte de dados responsável pelo Networking, processo de comunicação do app com serviços externos, e conectá-la aos mesmos repositórios. Assim, a interface e boa parte das regras existentes não precisarão conhecer os detalhes da API nem ser reescritas por causa da mudança na origem dos dados.

Mas, antes de preparar o app para buscar informações em um servidor, eu precisava resolver um problema presente desde a primeira versão: onde e como armazenar os dados?

E o armazenamento?

Como expliquei no artigo anterior, o app é utilizado em arenas de vôlei e ambientes externos. Sendo assim, pode ser que o usuário não tenha acesso à internet ou enfrente grandes oscilações na conexão.

Unindo isso à curiosidade técnica, optei pelo armazenamento local. Para esse armazenamento, decidi utilizar o Core Data, que é um framework da Apple voltado ao armazenamento offline e que oferece uma gestão de relacionamentos bastante robusta. Entre as opções possíveis, essa parecia a mais interessante por ser um framework nativo da Apple, o que reduz a dependência de pacotes de terceiros, e por suportar relações mais complexas, já que eu precisava de modelos como Jogador, Pelada, Times e Campeonatos, entre os quais há várias relações.

Essa definitivamente foi a parte mais complexa do desenvolvimento do app. Precisei modelar os dados com calma e analisar suas relações para obter um resultado satisfatório, depois de algumas tentativas com bugs engraçados, como jogadores sumindo e times sendo desfeitos.

Com o crescimento do app, vejo como próximos passos a criação de um backend e a transferência dos dados locais para esse serviço. Com isso, o aplicativo passará a seguir um modelo online-first, abordagem na qual os dados do servidor são a fonte principal, mantendo também o suporte offline para situações em que não houver conexão. Isso vai me permitir criar diversas features de interação entre os usuários e fazer uma gestão interessante dos dados.

Plataforma, interface, arquitetura e armazenamento solucionaram problemas diferentes. A questão final é o que essas escolhas, analisadas em conjunto, representam para a evolução do produto e para meu trabalho como desenvolvedor.

Conclusão

Desenvolver um app sozinho envolve diversas decisões técnicas que também representam desafios diários em grandes companhias. Em um app pequeno, desenvolvido para aprendizado e testes, temos a possibilidade de fazer escolhas mais voltadas ao aprendizado e correr mais riscos. Porém, em um app de uma grande empresa, não podemos correr os mesmos riscos: as decisões precisam ser bem estudadas e embasadas.

Construir o Volei+ me permitiu vivenciar essas escolhas em todas as etapas, desde a definição da plataforma até a preparação da arquitetura para as próximas evoluções do produto. É essa experiência prática que levo para outros projetos. Se você também está tomando decisões sobre arquitetura, escalabilidade ou experiência do usuário, entre em contato comigo e conte-me sobre seu projeto. Posso ajudar você a encontrar os caminhos mais adequados para construir um app escalável e oferecer uma boa experiência aos seus clientes.

Sobre o autor

Danilo Lira

Engenheiro iOS com experiência construindo produtos para varejo, serviços financeiros, saúde e projetos independentes. Escrevo sobre decisões técnicas que geram produtos melhores.