Introdução ao nativo
Já faz um bom tempo que plataformas de desenvolvimento como o React Native e o Flutter encontraram sucesso em reduzir a quantidade de trabalho em projetos mobile, e se tornaram plataformas mais populares do que o desenvolvimento diretamente no Android e no iOS.
Mas bala de prata não existe, e o desenvolvimento nativo continua sendo uma opção para novos projetos. Em certas ocasiões, é até melhor do que escolher uma plataforma híbrida.
Mas quais exatamente são as vantagens de cada opção, e o que devemos levar em consideração para tomar esta decisão?
Nativo também é moderno
Primeiro de tudo, vamos adereçar uma preocupação comum: existe a noção de que o desenvolvimento nativo é algo ultrapassado, parecido com os Windows Forms de antigamente onde arrastávamos os componentes visuais na tela, colocando a lógica nos controllers correspondentes.
É verdade que esse estilo de programação deu lugar ao estilo declarativo em plataformas mais modernas, mas o nativo não ficou para trás. Hoje em dia você não escreve mais código em Android arrastando componentes e escrevendo código com MVC; o Kotlin Jetpack é o jeito moderno de programar um aplicativo Android, e ele abusa a sintaxe da linguagem Kotlin para expressar os componentes com um estilo declarativo, bem parecido com os frameworks modernos da web, onde a aparência do código revela a estrutura lógica dos componentes visuais.
(Android Developers, https://developer.android.com/develop/ui/compose)
Se você olhar para o lado iOS, você vê a mesma coisa. A plataforma SwiftUI é o jeito moderno de escrever um app nativo, e ele usa uma sintaxe declarativa bem diferente de antigamente.
import SwiftUI
struct AlbumDetail: View {
var album: Album
var body: some View {
List(album.songs) { song in
HStack {
Image(album.cover)
VStack(alignment: .leading) {
Text(song.title)
Text(song.artist.name)
.foregroundStyle(.secondary)
}
}
}
}
}
(Apple Developer, https://developer.apple.com/xcode/swiftui/)
Isso quer dizer que a linguagem não é mais um obstáculo ao escolher uma plataforma nativa; pelo contrário, você tem acesso direto a todos os recursos do sistema operacional, programando com uma sintaxe nova tão legível quanto os frameworks modernos do front-end.
Duplicação e especialização
Mesmo assim, existem obstáculos no desenvolvimento nativo. Um projeto mobile frequentemente tem os mesmos requisitos e até a mesma especificação de design para a versão Android e iOS, e isso faz com que o código precise ser escrito, testado e validado duas vezes.
(DALL-E 3)
Em certas situações a interface visual varia entre o Android e o iOS para que siga a linguagem visual de cada sistema operacional. É verdade que as plataformas nativas têm uma vantagem porque te dão acesso a componentes nativos atualizados, mas a lógica da aplicação costuma ser a mesma porque os aplicativos têm a mesma função, tornando inevitável a duplicação de código.
Além disso, as plataformas nativas requerem um conhecimento mais especializado sobre Kotlin e Swift, respectivamente. É mais difícil encontrar equipes para desenvolver e manter código nessas linguagens em comparação às opções híbridas. Embora o desenvolvimento nativo te dê um acesso mais completo aos recursos do dispositivo, são poucos os aplicativos que fazem uso suficiente dessa vantagem para compensar a duplicação e a necessidade de profissionais especializados.
Código Híbrido
É para adereçar essas limitações que as plataformas híbridas existem no mercado. Vamos olhar para o React Native como um exemplo, que é uma das plataformas mais populares para escrever código híbrido:
(React Native, https://reactnative.dev)
(Sim, é confuso que o React Native é o nome de uma Plataforma híbrida e não nativa. Ele tem esse nome porque os componentes visuais escritos em Javascript viram componentes nativos no app compilado, ao invés de serem mostrados usando um navegador.)
A popularidade do React Native tem bons motivos: ele permite que um desenvolvedor aproveite seus conhecimentos de React e Javascript sem precisar aprender a usar uma Stack especializada, e o código escrito para Android e iOS é o mesmo.
Ele não te livra de pensar sobre código nativo; todas as configurações de certificados, assinaturas criptográficas e limitações de plataforma (ex.: você precisa do macOS para desenvolver para iOS) ainda existem e precisam fazer parte dos conhecimentos da equipe. Porém, o dia a dia de quem trabalha no código passa a ser no Node, tendo acesso a bibliotecas escritas em Javascript, o que é especialmente útil quando o aplicativo precisa usar algum conhecimento especializado como processamento geométrico ou um SDK disponível em poucas linguagens.
Código desduplicado
O React Native e outras plataformas híbridas têm a vantagem significativa de expressar a lógica da aplicação uma vez só, reduzindo drasticamente o comportamento diferente entre as plataformas.
O reuso de UI/UX permite o uso de um design system ou outro conjunto padronizado de componentes sem exigir duas implementações, e permite escrever a lógica da aplicação uma vez somente, evitando a possibilidade de expressá-la de maneira inconsistente. Plataformas híbridas modernas possuem componentes suficientemente refinados para replicar a aparência de um aplicativo nativo se necessário, com a flexibilidade de se adaptar ao estilo da marca.
Híbrido ou Nativo?
Quanto exatamente da lógica você consegue economizar usando uma base de código ao invés de duas?
Em um aplicativo moderno, você evita praticamente toda a duplicação.
Há um contra-argumento que consiste em apontar que toda a lógica de negócios crítica fica no back-end, e portanto o aplicativo somente trata lógica de apresentação, e isso deve ficar livre para variar dependendo da plataforma. Consequentemente, um app mobile deve conter uma quantidade mínima de código.
É verdade que a lógica de negócios fica no back-end, mas um aplicativo moderno é bem mais do que telas que delegam todo o processamento para outro sistema. O app em si precisa de código para manter um estado interno consistente, apresentar dados de forma intuitiva, e acessar serviços externos e do dispositivo.
Modelo simplificado da arquitetura Flutter com BLoCs
Arquitetura e boas práticas de código não são um problema só do back-end, e tudo isso é código que precisaria ser desenhado e implementado separadamente no nativo, mas que pode ser criado uma vez em uma plataforma híbrida e aprendido uma vez pelos desenvolvedores.
Performance e produtividade
Preocupações de performance são levantadas com frequência quando falamos de plataformas híbridas, mas processadores modernos são rápidos o bastante para atender as necessidades de um aplicativo típico. Um código bem escrito e otimizado corretamente consegue entregar uma experiência fluida independente de ter usado uma plataforma nativa ou híbrida.
Vamos notar, no entanto, que existem casos em que a plataforma deve ser escolhida com cuidado para não se tornar uma limitação. Um exemplo comum é que muitas plataformas híbridas precisam serializar dados para realizar a comunicação com o código nativo, e isso significa que o aplicativo pode sofrer uma perda de performance significante se precisar trabalhar com volumes muito grandes de dados trafegados entre o código compartilhado e o código nativo.
Para trabalhar com SDKs nativos que trafegam streams com muitos dados, prefira não sair do código nativo.
Aplicativos que precisam realizar processamento intenso também devem considerar a linguagem, pois uma plataforma como o React Native que executa o código dentro de uma Engine Javascript causará uma perda de performance.
Porém, considerando um aplicativo típico como uma rede social, um app de e-commerce e assim por diante, quaisquer problemas de lentidão são, com toda a probabilidade, falhas no código e não na plataforma. Embora o código perfeito nativo seja mais eficiente e performático que o código perfeito híbrido, na prática pode até compensar escolher uma tecnologia híbrida para usar uma linguagem que a equipe saiba otimizar melhor, como o Javascript com React.
É difícil para nós programadores reconhecer que os problemas no código são culpa nossa, mas isso também significa que é possível escrever código melhor. Plataformas modernas possuem ferramentas que nos permitem diagnosticar ineficiências, e uma arquitetura bem planejada não depende de uma linguagem específica para levar uma experiência agradável ao usuário.
Híbrido entre híbrido e nativo
Não é tudo que é possível de se expressar com código compartilhado. Há funcionalidades como compras dentro do app e acesso a memória externa que funcionam de maneiras diferentes no Android e iOS, ou só funcionam em um dos dois. Nestes casos, as bibliotecas híbridas tipicamente expõem estas funcionalidades com uma API comum que pode não oferecer tanta flexibilidade quanto programar em código nativo.
Felizmente, é sempre possível escrever partes do seu código em linguagem nativa e integrar com a plataforma híbrida conforme necessário. Isso quer dizer que o uso esporádico de alguma API ou SDK que exige implementação ou configuração nativa não inviabiliza o uso de uma plataforma híbrida para o resto da aplicação.
Lost in Translation
Usar código nativo em projetos híbridos não é só suportado, mas também é a melhor solução em vários casos; porém é bom evitar o exagero.
Como o código híbrido tipicamente é executado em seu próprio contexto isolado, você terá dificuldades em usar telas nativas junto com telas híbridas no mesmo aplicativo, e a interoperabilidade entre a lógica da aplicação que existe de cada lado depende de mapear objetos e chamadas, o que adiciona um trabalho a mais que é difícil de testar.
Se você optar por uma plataforma híbrida, procure não misturar UI e lógica nativa com frequência, pois as conversões exigem mais esforço do que usar uma linguagem só.
(Westminster Bridge, with the Lord Mayor's Procession on the Thames, https://artsandculture.google.com/asset/twH5GpSm6omCqw)
(Sejamos) aproveitadores do ecossistema
Outro ponto de vista a se considerar ao escolher uma determinada linguagem é o ecossistema. As stacks Node e Java são tão populares no back-end em boa parte graças à enorme quantidade de bibliotecas disponíveis.
A má notícia é que poucas plataformas mobile conseguem fazer uso irrestrito de outros ecossistemas:
A linguagem Kotlin, usada no Android nativo, tem interoperabilidade com Java, mas não executa na JVM e usa o SDK Android. Por conta disso, não é garantido que bibliotecas externas vão funcionar, e na prática o ecossistema Android é tratado como algo separado do ecossistema Java dos servidores;
A linguagem Swift possui um ecossistema limitado pois é voltada para o desenvolvimento de aplicações para hardware da Apple;
O Javascript usado no React Native não tem um ambiente Node, e por isso uma biblioteca que usa a API do runtime do Node precisará de ajustes para funcionar no mobile. Mesmo assim, o React Native e outras plataformas que usam o ecossistema Node têm o maior potencial de aproveitar bibliotecas existentes para domínios especializados, como processamento geométrico e processamento de texto;
O React Native não usa os mesmos componentes que o React na web, então não é possível compartilhar ou reusar código sem precisar de ajustes;
O Flutter tem a limitação de ser escrita na linguagem Dart, e por isso não tem um ecossistema pré-existente.
Essas considerações têm mais importância quando o aplicativo precisa de muita lógica de um domínio específico; para os casos mais básicos, todas as plataformas modernas fornecem os recursos suficientes para criar um aplicativo completo.
Mesmo assim, a disponibilidade de bibliotecas de terceiros ou a necessidade de compartilhar código com outras aplicações é um dos fatores mais importantes para escolher uma plataforma.
Casos e Casos
Em conclusão, existem casos e casos. O potencial ganho com cada plataforma depende de vários fatores que individualmente pesam mais para um lado ou para outro.
Aplicativos:
| Aplicativos
|
Muralis insigths | Escrito por: Rafael Takahashi, Arquiteto de Software.
Comentários