Artigo · Blog
Flutter resolve o problema errado quando você tem um app Kotlin que já funciona
A decisão de ir multiplataforma quase sempre é tomada antes de entender qual problema está sendo resolvido. Trabalhei nos dois lados dessa decisão e o erro que vi se repetir não foi técnico. Foi de diagnóstico.
Flutter resolve o problema errado quando você tem um app Kotlin que já funciona
Numa fintech onde trabalhei, o argumento para adotar Flutter foi "reduzir custo de manutenção com dois times". O app Android já tinha dois anos, Kotlin, arquitetura modular, cobertura de testes razoável. O app iOS era menor, mais novo.
Seis meses depois, tínhamos três bases de código. O app Flutter novo, o app Kotlin legado que precisava continuar rodando enquanto a migração não terminava, e o app iOS que ninguém mais sabia o que fazer.
O custo de manutenção não caiu. Triplicou temporariamente. E o Flutter ficou com a conta de um débito técnico que não era dele.
O problema que multiplataforma promete resolver
A promessa é clara: um time, uma linguagem, dois apps.
Na prática, o que você está comprando é uma camada de abstração entre o seu produto e a plataforma. Essa camada tem custo. E esse custo não aparece na primeira sprint. Ele aparece quando você precisa de algo que a plataforma entrega nativamente mas o framework ainda não expõe, quando um bug de renderização afeta só um vendor de Android, quando a atualização do SDK da plataforma chega e o framework demora três meses pra acompanhar.
Eu vi isso com Flutter em apps de pagamento. A integração com alguns SDKs de antifraude exigia código nativo de qualquer forma. O canal de plataforma virou o lugar onde a promessa de "escrever uma vez" se quebrava silenciosamente.
O app ficava 80% Flutter, 20% Kotlin e Swift espalhados em platform channels que ninguém queria tocar.
O que a maioria faz errado sem perceber
A decisão de ir multiplataforma é tomada com base em comparação de linguagens. Deveria ser tomada com base em comparação de produtos.
Existe uma diferença enorme entre:
- Começar um produto novo do zero, sem base instalada, sem débito técnico, com um time pequeno que precisa cobrir duas plataformas.
- Migrar um app Android maduro, com base de usuários estabelecida, arquitetura já definida e time que conhece o código.
No primeiro cenário, Flutter ou React Native fazem sentido como escolha inicial. No segundo, a migração quase nunca se paga no horizonte de tempo esperado.
O que eu observei repetidamente: a decisão é tomada com o roadmap do cenário 1 aplicado ao contexto do cenário 2.
O que Kotlin bem estruturado entrega que Flutter não consegue imitar
Trabalhei em apps Android com Kotlin, Clean Architecture e Coroutines. E trabalhei em apps Flutter com a mesma intenção arquitetural.
A diferença que mais apareceu em produção não foi de linguagem. Foi de integração.
Kotlin com Jetpack, ViewModel, StateFlow e integração nativa com o ciclo de vida do Android entrega um modelo mental coerente. Você está sempre trabalhando com as abstrações que o sistema operacional espera. O framework e a plataforma falam a mesma língua.
Flutter entrega consistência visual entre plataformas, mas ao custo de ficar um passo atrás do sistema operacional. Widgets que se comportam diferente em versões antigas de Android. Animações que o iOS renderiza de um jeito e o Android de outro. Back gesture handling que mudou no Android 13 e quebrou o navigator de metade dos apps Flutter que vi em produção.
Esses são problemas resolvíveis. Mas são problemas que um app Kotlin nativo nunca teria tido.
Onde multiplataforma realmente ganha
Não estou dizendo que Flutter ou React Native são escolhas ruins. Estou dizendo que eles resolvem um problema específico que precisa existir para a escolha fazer sentido.
O problema que eles resolvem bem: velocidade de cobertura de plataforma com time pequeno e produto que não depende de integração profunda com o sistema operacional.
Apps de conteúdo, ferramentas internas, produtos com UI relativamente simples e fluxos previsíveis. Nesses contextos, Flutter entrega o que promete.
Apps financeiros com biometria, câmera para OCR, integração com SDKs de terceiros, notificações ricas, widgets nativos de homescreen, deep links complexos, e acessibilidade que precisa funcionar de verdade em modo de alto contraste no Android 14. Nesses contextos, o canal de plataforma vira uma dívida que cresce a cada feature.
A tese que defendo
Multiplataforma não é uma decisão de arquitetura. É uma decisão de produto. E a maioria dos times trata como decisão de tecnologia.
Quando você decide ir multiplataforma por causa do custo de manutenção de dois times, você está assumindo que o problema é ter dois times. Mas o problema real pode ser outro: falta de documentação compartilhada, arquitetura inconsistente entre plataformas, decisões de design que ignoram convenções nativas, ou simplesmente um time Android e um time iOS que nunca falaram entre si sobre como resolver o mesmo problema.
Esses problemas não desaparecem com Flutter. Eles se escondem dentro do código Dart e ressurgem quando o produto precisa crescer.
O que eu faria diferente hoje
Numa situação onde o app Android já existe, já tem usuários, já tem arquitetura, eu faria uma pergunta antes de qualquer decisão de multiplataforma:
O iOS ainda não existe ou está atrasado porque falta engenheiro ou porque falta produto?
Se for engenheiro, Flutter pode fazer sentido para cobrir iOS enquanto o time cresce. Se for produto, a decisão de plataforma é prematura.
A outra coisa que eu evitaria: tratar o app legado como problema a ser migrado. Apps Kotlin maduros com boa arquitetura são ativos. Migrá-los pra Flutter não é modernização. É troca de um sistema que você conhece por um sistema que você ainda vai conhecer.
Às vezes o melhor movimento é manter o Android em Kotlin, construir o iOS nativo em Swift, e investir em convenções compartilhadas de arquitetura, nomenclatura e contrato de API entre os dois times.
Dois apps nativos bem arquitetados entregam mais do que um app multiplataforma mal arquitetado.
A armadilha real
Multiplataforma reduz o número de linguagens. Não reduz a complexidade do produto.
Você ainda vai ter que decidir como tratar comportamento diferente entre plataformas. Vai ter que lidar com guidelines de UI que divergem. Vai ter que testar em devices com características diferentes. Vai ter que manter dois conjuntos de testes de UI porque as telas não se comportam igual.
A complexidade não some. Ela muda de lugar.
E o risco é que, no novo lugar, ela fique menos visível. Escondida em platform channels, em condicionais if (Platform.isAndroid) espalhados pelo código, em workarounds de renderização que ninguém documenta porque "funcionou".
Multiplataforma bem feita não é menos complexidade. É complexidade redistribuída de um jeito diferente.
A pergunta que vale fazer antes de qualquer decisão: você está redistribuindo a complexidade pra um lugar que o time consegue enxergar e controlar, ou pra um lugar que vai aparecer só quando o usuário reclamar?