Aula 2: Arquiteturas e Frameworks Multiplataforma
A aula anterior mostrou as forças que atuam sobre uma aplicação que precisa atender navegador e celular. Esta aula trata das escolhas que respondem a essas forças — e do preço de cada uma.
São duas decisões distintas, e confundi-las é a origem de boa parte da confusão inicial:
- Como o sistema se divide? Um programa que faz tudo, ou um serviço com clientes separados?
- Como o aplicativo móvel é construído? Nativo, híbrido, compilado ou web?
A primeira decisão é de arquitetura; a segunda, de estratégia de implementação. Ao final, a aula registra qual combinação esta disciplina adota e por quê — não porque seja a única defensável, mas porque as razões da escolha são o próprio conteúdo.
| O que vem depois | Onde |
|---|---|
| A linguagem comum ao serviço e ao cliente web | Aula 3 — TypeScript |
| O contrato entre o serviço e os clientes | Aula 4 — API REST |
| A implementação do serviço | Módulo 2 — NestJS |
Objetivos
Ao final desta aula, você deve ser capaz de:
- Comparar a arquitetura acoplada (renderizada no servidor) com a arquitetura desacoplada baseada em API, identificando o que trafega na rede em cada uma.
- Explicar o que efetivamente executa no dispositivo em cada uma das quatro estratégias de desenvolvimento mobile.
- Justificar a escolha de uma estratégia para um cenário dado, considerando desempenho, acesso a recursos, custo de manutenção e prazo.
- Descrever a arquitetura adotada na disciplina e o papel de cada tecnologia nela.
- Reconhecer os limites das arquiteturas desacopladas — o custo que elas cobram em troca da flexibilidade.
- Preparar o ambiente de desenvolvimento das três frentes e verificar a instalação.
Parte 1 — Acoplado ou desacoplado
Comecemos pela decisão que condiciona todas as outras.
A diferença não é a linguagem nem o framework. É o que trafega na rede.
| Renderizado no servidor | Desacoplado (API) | |
|---|---|---|
| O servidor devolve | A página HTML montada | Os dados, em JSON |
| Quem monta a tela | O servidor | Cada cliente |
| Ao navegar | Recarrega a página inteira | Atualiza apenas o que mudou |
| Um segundo cliente | Exige um novo servidor de apresentação | Consome a mesma API |
| Interface e regra | Evoluem juntas, no mesmo projeto | Evoluem em ritmos separados |
| Primeira carga | Rápida: o HTML já vem pronto | Mais lenta: baixa o aplicativo, depois os dados |
| Indexação por buscadores | Natural | Exige cuidado adicional |
Aplicações renderizadas no servidor continuam sendo a melhor escolha para sites de conteúdo, portais institucionais e sistemas internos com um cliente só. Programação Web Java trabalha exatamente esse modelo com Jakarta Faces — e faz sentido, porque lá o cliente é um só. A arquitetura desacoplada não é "melhor": ela paga um custo inicial que só se justifica quando há mais de um cliente, ou quando eles evoluem em ritmos diferentes.
O híbrido que virou padrão
Vale notar que a fronteira se dissolveu. Next.js — o framework do Módulo 3 — renderiza no servidor e consome API: a primeira tela vem montada, para ser rápida e indexável, e a navegação seguinte busca só os dados. Os dois modelos convivem no mesmo projeto, e escolher entre eles passou a ser uma decisão por tela, não por sistema.
O que não muda é a posição das regras de negócio: elas continuam no serviço. Um servidor Next.js renderizando HTML ainda é um cliente da API — não é o dono das regras.
O custo que a arquitetura desacoplada cobra
A separação não é gratuita, e vale ser explícito quanto a isso:
- Mais partes móveis. Três projetos para versionar, testar e publicar em vez de um.
- Latência somada. Uma tela que precisa de três recursos pode fazer três viagens à rede.
- Contrato para manter. Mudar um campo deixa de ser uma refatoração e vira uma negociação entre times.
- Autenticação distribuída. Sessão em servidor não serve mais; é preciso token, e tratá-lo em cada cliente.
- Depuração mais difícil. O erro pode estar em qualquer um dos três lados, ou na fronteira entre eles.
Vale a pena quando há mais de um cliente — que é exatamente o nosso caso.
Parte 2 — As quatro estratégias de desenvolvimento mobile
Decidida a arquitetura, resta a segunda pergunta: como o aplicativo é construído? Quatro respostas dividem o mercado, e a diferença entre elas está em uma única coisa: o que desenha a interface na tela.
Nativo
Escrito na linguagem oficial de cada plataforma — Kotlin no Android, Swift no iOS — usando diretamente os componentes de interface do sistema.
- A favor: desempenho máximo, acesso imediato a qualquer recurso e a APIs recém-lançadas, aparência exatamente igual à da plataforma.
- Contra: duas bases de código, duas equipes ou uma equipe que domina duas linguagens, e todo recurso implementado duas vezes.
- Quando escolher: quando desempenho gráfico, integração profunda com o sistema ou acesso a APIs muito recentes forem requisito, e houver equipe para sustentar dois projetos.
Híbrido (WebView)
A interface é HTML, CSS e JavaScript, exibida dentro de um componente de navegador embutido no aplicativo — a WebView. Uma ponte dá acesso a recursos nativos. Exemplos: Ionic, Apache Cordova, Capacitor.
- A favor: aproveita conhecimento e código da web; uma base para as duas plataformas; ciclo de desenvolvimento curto.
- Contra: o desempenho é o da WebView; animações e listas longas costumam denunciar a origem; a aparência é a mesma nos dois sistemas, o que nem sempre é desejável.
- Quando escolher: aplicativos majoritariamente de conteúdo, com pouca interação complexa, ou quando já existe uma aplicação web madura para reaproveitar.
Cross-platform compilado
O código é escrito uma vez, em uma linguagem própria, e compilado para código nativo. A interface não usa os componentes do sistema: o framework traz o próprio motor gráfico e desenha tudo em um canvas. É a estratégia do Flutter (Dart) e, com um arranjo diferente, do React Native.
- A favor: desempenho próximo do nativo; uma base de código; interface idêntica nas duas plataformas por construção; ciclo de desenvolvimento rápido, com hot reload.
- Contra: depende do framework para alcançar recursos do sistema — o que geralmente significa aguardar um plugin; o binário é maior; APIs recém-lançadas chegam com atraso.
- Quando escolher: aplicativos com interface rica e interativa, equipe única e necessidade de acesso a recursos do dispositivo. É a escolha desta disciplina.
O React Native traduz os componentes do código para componentes nativos do sistema; o Flutter desenha os seus próprios. A consequência prática: no React Native, um botão é um botão do Android ou do iOS, e a aparência muda entre as plataformas; no Flutter, é o mesmo botão em ambas. Nenhuma das duas abordagens é superior — elas otimizam coisas diferentes. Usamos Flutter porque o controle total sobre a renderização torna o comportamento mais previsível, e porque Dart permite comparar diretamente com o TypeScript usado nas outras duas frentes.
Web app e PWA
Não há aplicativo: há um site, acessado pelo navegador do celular. Um Progressive Web App acrescenta manifesto, ícone e service worker, podendo ser instalado na tela inicial e funcionar parcialmente offline.
- A favor: uma base de código para tudo; publicação imediata, sem loja; atualização instantânea para todos os usuários.
- Contra: acesso restrito a recursos do dispositivo, com diferenças relevantes entre navegadores; sem presença na loja; notificações push com suporte desigual.
- Quando escolher: quando não há necessidade real de recursos do dispositivo nem de estar na loja. É a opção de menor custo — e por isso a primeira a ser descartada com honestidade, não por reflexo.
Em uma tabela
| Nativo | Híbrido | Compilado | Web app / PWA | |
|---|---|---|---|---|
| Linguagem | Kotlin, Swift | HTML/CSS/JS | Dart, JS | HTML/CSS/JS |
| Quem desenha a tela | O sistema | A WebView | O motor do framework | O navegador |
| Desempenho | Máximo | Limitado | Próximo do nativo | O do navegador |
| Recursos do dispositivo | Total | Via ponte | Via plugins | Restrito |
| Bases de código | Uma por plataforma | Uma | Uma | Uma |
| Está na loja | Sim | Sim | Sim | Não |
| Atualização | Pela loja | Pela loja | Pela loja | Imediata |
Parte 3 — Como escolher
Não existe estratégia correta em abstrato. Existe a que melhor equilibra requisitos, prazo e equipe — e a decisão costuma caber em três perguntas.
1. Precisa estar na loja ou usar recursos do dispositivo? Se não, um web app resolve com o menor custo possível. Descarte essa opção apenas com um requisito na mão, não por hábito.
2. Uma única base de código atende as duas plataformas? Se o produto depende de desempenho gráfico extremo, de integração profunda com o sistema ou de APIs lançadas há poucos meses, a resposta é não — e a estratégia é nativa, com o custo de dois projetos assumido conscientemente.
3. A tela é sobretudo conteúdo que já existe na web? Se sim, o híbrido aproveita o que já está pronto. Se não — se há interação, animação, listas longas, estado complexo — o cross-platform compilado entrega resultado próximo do nativo com uma base de código só.
Os critérios por trás das perguntas
| Critério | Pergunta que ele responde |
|---|---|
| Requisitos de recurso | O app precisa de câmera, GPS, biometria, notificações, uso offline? |
| Exigência de interface | Há animação, gesto complexo, lista muito longa, gráfico interativo? |
| Equipe | Que linguagens a equipe domina hoje? Quantas pessoas mantêm o projeto? |
| Prazo e orçamento | Duas bases de código dobram o custo de cada funcionalidade |
| Vida útil | Um piloto de três meses e um produto de cinco anos não pedem a mesma escolha |
| Ecossistema | Existe plugin mantido para o que você precisa, ou será preciso escrever código nativo? |
"Prefiro X" não é critério. A pergunta é sempre qual restrição do produto essa escolha atende, e qual custo ela impõe. Um argumento de escolha que não menciona custo está incompleto.
Parte 4 — A arquitetura desta disciplina
Com o vocabulário estabelecido, dá para enunciar a arquitetura do semestre e justificar cada peça.
| Camada | Tecnologia | Por que |
|---|---|---|
| Serviço | NestJS (TypeScript) sobre Node.js | Estrutura opinativa, com módulos, injeção de dependência e validação — os mesmos conceitos de Jakarta EE, em outro ecossistema |
| Persistência | PostgreSQL, acessado por ORM | Base relacional madura, com migrações versionadas |
| Contrato | REST sobre HTTP, descrito em OpenAPI | Independente de linguagem: os dois clientes leem o mesmo documento |
| Cliente web | Next.js + React (TypeScript) | Componentização, roteamento e escolha de estratégia de renderização por tela |
| Cliente mobile | Flutter (Dart) | Uma base de código, desempenho próximo do nativo, acesso a recursos via plugins |
Três decisões merecem justificativa explícita, porque são as que voltam nas provas e nos projetos:
Por que o backend vem primeiro. Os dois clientes consomem os serviços construídos nele. Começar pelo cliente significaria inventar um contrato que ainda não existe — e depois refazê-lo.
Por que TypeScript no serviço e no cliente web. Uma linguagem a menos para aprender, e a possibilidade de compartilhar os tipos do contrato entre os dois lados. O cliente mobile usa Dart, e essa diferença é proposital: mostra que o contrato funciona sem compartilhar código.
Por que o contrato é o centro do diagrama. É a única peça que nenhum dos três lados pode mudar sozinho. Toda a aula 4 é dedicada a ele.
Vale mapear os conceitos, porque eles se transferem quase inteiros: injeção de dependência (CDI → NestJS providers), API REST (Jakarta REST → NestJS controllers), mapeamento objeto-relacional (JPA → ORM) e validação declarativa (Bean Validation → class-validator). O padrão é o mesmo; muda a sintaxe e o ecossistema. Comparar as duas stacks é uma das formas mais rápidas de consolidar o conteúdo.
Parte 5 — O ambiente de desenvolvimento
Os exemplos da disciplina são executáveis. Esta seção reúne o mínimo para que a próxima aula não comece com problema de instalação.
| Ferramenta | Versão sugerida | Para quê |
|---|---|---|
| Node.js | 22 LTS ou superior | Runtime do serviço e do cliente web |
| npm ou pnpm | a que acompanha o Node | Gerenciamento de pacotes |
| NestJS CLI | 11.x | Geração e execução do serviço |
| Next.js | 15.x (App Router) | Cliente web |
| Flutter SDK (com Dart) | 3.x | Cliente mobile |
| PostgreSQL | 16 ou superior | Base de dados |
| Docker | versão estável atual | Base de dados local e empacotamento |
| Android Studio / Xcode | conforme a plataforma alvo | Emulador, simulador e build mobile |
| Git | versão estável atual | Versionamento |
Verificando a instalação
Os comandos abaixo são executáveis e não alteram nada: cada um apenas responde com uma versão. Rode todos antes da próxima aula.
node --version # v22.x ou superior
npm --version
git --version
docker --version
flutter --version # inclui a versão do Dart
O Flutter traz um diagnóstico próprio, que verifica SDK, emuladores e dependências de cada plataforma:
flutter doctor
Node, NestJS, Next.js e Flutter têm ciclos de release rápidos. As versões acima são o ponto de partida; a combinação efetivamente adotada na turma é confirmada em aula e no Moodle.
Editor
Qualquer editor serve, mas vale garantir três coisas: suporte a TypeScript
(nativo no VS Code e nos IDEs JetBrains), extensão do Flutter/Dart e um
cliente HTTP para exercitar a API — Postman, Insomnia, a extensão REST Client
ou simplesmente curl. A partir do Módulo 2, testar um endpoint fora do cliente
web será rotina.
Erros comuns
| Erro | Consequência |
|---|---|
| Escolher a estratégia mobile por preferência pessoal | A decisão não sobrevive à primeira revisão técnica |
| Adotar arquitetura desacoplada com um cliente só | Paga-se o custo da separação sem receber o benefício |
| Colocar regra de negócio no servidor Next.js | O cliente mobile fica sem ela: a regra deixa de existir para metade dos usuários |
| Tratar PWA e híbrido como sinônimos | São coisas distintas: um é site, o outro é aplicativo com WebView dentro |
| Supor que cross-platform elimina conhecimento de plataforma | Permissões, build e publicação continuam sendo específicos de cada sistema |
| Começar pelos clientes, antes do contrato | Cada cliente inventa um contrato diferente, e os dois são refeitos |
Ignorar flutter doctor | O problema aparece na aula do Módulo 4, quando já não há tempo |
| Comparar frameworks só por desempenho | Custo de manutenção pesa mais no ciclo de vida do produto |
Exercícios (Checkpoints)
-
Explique, em duas frases, a diferença essencial entre arquitetura acoplada e desacoplada em termos do que trafega na rede — sem citar nomes de frameworks.
-
Liste três custos concretos que a arquitetura desacoplada impõe e, para cada um, descreva em que situação esse custo não compensa.
-
Descreva o que efetivamente desenha a interface na tela em cada uma das quatro estratégias mobile e explique como isso determina o desempenho de cada uma.
-
Escolha uma estratégia para cada cenário, justificando com pelo menos dois critérios: (a) o aplicativo de uma revista, essencialmente texto e imagem, com uma equipe web de três pessoas; (b) um jogo casual com animação contínua; (c) o aplicativo de um banco, com biometria e leitura de código de barras; (d) uma ferramenta interna de registro de ponto, para cem funcionários.
-
Compare Flutter e React Native quanto ao modo de renderizar a interface, e explique uma consequência prática dessa diferença para quem usa o aplicativo.
-
Justifique por que, nesta disciplina, o backend é construído antes dos clientes. Depois, descreva o que aconteceria se os dois clientes fossem desenvolvidos em paralelo, sem contrato definido.
-
Analise a afirmação: "Como o servidor Next.js roda no servidor, posso colocar a regra de negócio nele." Aponte por que ela é problemática na arquitetura da disciplina e o que se perde ao seguir esse caminho.
-
Prepare o ambiente: instale Node.js, Git e o Flutter SDK, execute
flutter doctore registre o que o diagnóstico apontou. Traga as pendências para a próxima aula. -
Investigue um aplicativo que você usa diariamente e tente identificar a estratégia com que foi construído — observando animações, tempo de resposta, aparência entre Android e iOS, tamanho do binário. Registre as evidências e o grau de confiança da sua conclusão.
Referências
Principais
- Flutter — documentação oficial — instalação, widgets e ferramentas
- NestJS — Introdução — estrutura do framework do Módulo 2
- Next.js — documentação — App Router e estratégias de renderização
- web.dev — O que é um Progressive Web App — definição e requisitos
Aprofundamento
- Flutter — Architectural overview — como o motor gráfico funciona por dentro
- React Native — documentação — a abordagem alternativa de cross-platform
- Capacitor — desenvolvimento híbrido com WebView
- Android Developers — Distribuir na Google Play — o processo de publicação
- Martin Fowler — Microservices — onde a separação em serviços leva, em escalas maiores