Publicado em: novembro 10, 2025
O Retorno ao Metal Nu: Por Que Chegamos ao Fim das Aparências
Durante quase duas décadas, nos venderam uma história sobre produtividade de desenvolvedores. A proposta era mais ou menos a seguinte: linguagens interpretadas e frameworks de alto nível abstraem a complexidade da programação de sistemas, permitindo que os desenvolvedores trabalhem mais rápido e se concentrem na lógica de negócios em vez do gerenciamento de memória. Python, JavaScript e seus diversos ambientes de execução se tornaram a escolha padrão para tudo, desde serviços web e pipelines de dados até aplicativos móveis.
Sempre foi um argumento questionável. Mas agora? É comprovadamente falso.
O mito da produtividade está se desfazendo.
A promessa era simples: sacrificar um pouco de desempenho em troca de ganhos massivos na velocidade de desenvolvimento. Escrever menos código, entregar mais rápido, iterar rapidamente. Por um tempo, aceitamos essa troca sem muita análise crítica. Mas algo interessante aconteceu nos últimos anos — a equação mudou fundamentalmente.
Linguagens de sistemas modernas como Rust e Go não são o C++ do seu avô. Elas não exigem que você gerencie memória manualmente, evitando estouros de buffer e lidando com sistemas de compilação arcaicos. Rust te dá memória. safeObrigado sem coleta de lixo. Go oferece simplicidade e primitivas de concorrência que realmente fazem sentido. Até mesmo o próprio C++ evoluiu drasticamente, com bibliotecas compostas apenas por arquivos de cabeçalho que fornecem funcionalidades sofisticadas sem o inferno de dependências que assolava as gerações anteriores.
Enquanto isso, o que aconteceu com aquelas linguagens interpretadas "produtivas"? Tente configurar um ambiente Python moderno com as versões corretas das dependências em desenvolvimento, homologação e produção. Aprecie as árvores de dependências aninhadas do npm e os ataques frequentes à cadeia de suprimentos. Maravilhe-se com a complexidade de configurar um sistema de compilação React Native ou Flutter que realmente funcione de forma consistente em todas as plataformas.
A suposta vantagem de produtividade evaporou. Em muitos casos, o efeito foi o oposto.
O pesadelo da segurança sobre o qual não estamos falando o suficiente.
Vamos abordar o elefante na sala: linguagens interpretadas e frameworks híbridos são desastres de segurança prestes a acontecer e, no mundo mobile, são verdadeiros cenários de crime.
Cada camada de abstração é uma superfície de ataque. Cada ambiente de execução é uma vulnerabilidade potencial. Cada dependência é um risco. Ao desenvolver em Node.js, você está confiando em milhares de pacotes escritos por desconhecidos, muitos dos quais não recebem manutenção há anos. O ecossistema JavaScript normalizou os ataques à cadeia de suprimentos a tal ponto que eles quase não são mais notícia.
Frameworks para dispositivos móveis como React Native e Flutter são particularmente problemáticos. Essencialmente, você está executando um mecanismo JavaScript ou uma máquina virtual Dart dentro de um aplicativo móvel, adicionando enorme complexidade ao seu modelo de segurança. Cada ponte entre o ambiente de execução e o código nativo é um vetor de exploração em potencial. Cada plugin de terceiros é uma caixa-preta que pode estar fazendo qualquer coisa.
O código nativo — código que é compilado diretamente para assembly — tem uma superfície de ataque muito menor. Sim, você ainda pode escrever código nativo inseguro. Mas você parte de uma posição fundamentalmente mais defensável quando toda a sua aplicação não depende de um ambiente de execução com suas próprias vulnerabilidades e um ecossistema de dependências questionáveis.
A Armadilha do Desempenho
Eis a maior ironia: mesmo as equipes que escolhem linguagens interpretadas pela sua suposta produtividade acabam por se deparar com limitações de desempenho que as obrigam a escrever extensões nativas de qualquer maneira.
Seu pipeline de dados em Python está muito lento? Hora de escrever extensões em C. Seu serviço em Node.js não aguenta a carga? Melhor recorrer a módulos nativos. Seu aplicativo React Native está lento? Provavelmente você terá que escrever módulos nativos para os caminhos críticos de desempenho.
Então você acaba fazendo exatamente o que dizia evitar — escrever código nativo — mas agora está fazendo da pior maneira possível. Você está mantendo uma base de código híbrida com toda a complexidade de interagir entre diferentes linguagens, gerenciar os sistemas de compilação para ambos os ambientes e depurar na fronteira entre código interpretado e nativo.
Se você vai escrever código nativo de qualquer maneira, por que não começar por aí?
Estamos num ponto de inflexão.
A combinação de linguagens de sistemas maduras, posturas de segurança deterioradas em ecossistemas interpretados e o colapso do argumento da produtividade significa que estamos em um verdadeiro ponto de inflexão.
A pergunta certa não é "Podemos nos dar ao luxo de usar Rust ou Go?", mas sim "Podemos nos dar ao luxo de não usar nenhum dos dois?".
Ao escolher sua pilha de tecnologias, você está fazendo uma aposta no futuro do seu projeto. Você está decidindo com que tipo de problemas está disposto a lidar daqui a três anos. Você está apostando no inferno das dependências, vulnerabilidades de segurança e gargalos de desempenho? Ou está apostando em um binário compilado que faça exatamente o que deve fazer, nada mais, nada menos?
Hora das perguntas difíceis
Chegou a hora de reexaminar as premissas que nortearam as decisões de plataforma e desenvolvimento na última década:
Essa configuração é realmente mais produtiva? Não em teoria, não baseado em um post de blog de 2015, mas na realidade, na sua equipe, com os seus problemas. Seus desenvolvedores estão gastando mais tempo lutando com o framework do que resolvendo problemas?
Qual é a verdadeira postura de segurança? Não se trata apenas de "executamos verificações de segurança", mas sim de qual é a sua superfície de ataque real? Em quantas dependências você confia? Quantas delas possuem vulnerabilidades conhecidas que você ainda não corrigiu?
Você está sendo honesto sobre os requisitos de código nativo? Se você já está escrevendo extensões nativas para melhorar o desempenho, por que continua acreditando que está evitando o desenvolvimento nativo?
Qual é a sua história de manutenção dos últimos cinco anos? Essa estrutura ainda receberá manutenção? Você conseguirá encontrar desenvolvedores que a conheçam? Ou estará construindo sobre areia movediça?
O caminho a seguir
Não se trata de devoção religiosa a linguagens compiladas ou de rejeitar toda e qualquer abstração. Trata-se de tomar decisões técnicas lúcidas com base na realidade atual, em vez de suposições ultrapassadas.
Rust e Go provaram que a programação de sistemas pode ser acessível. Bibliotecas C++ compostas apenas por arquivos de cabeçalho demonstraram que o desenvolvimento nativo não exige um gerenciamento de dependências complexo. As ferramentas amadureceram. As comunidades cresceram. As bibliotecas existem.
A justificativa para escolher linguagens interpretadas por padrão desmoronou sob o peso de suas próprias contradições. Fingimos que elas eram mais simples — não são. Fingimos que eram mais seguras — são menos. Fingimos que nos permitiam evitar código nativo — não permitem.
Chegou a hora de parar de fingir e começar a construir sobre bases sólidas novamente. O metal nu está chamando, e nunca esteve tão convidativo.
Também recomendamos
Como atender (e superar!) os requisitos da norma IEEE 1735
No mês passado, recebi um e-mail de recrutamento de alguém que afirmava…
Os três argumentos mais contundentes contra a criptografia de caixa branca — e por que eles não fazem sentido.
Na parte 1 desta série, analisamos onde…
O mito da implementação de software "desmontando e substituindo" em empresas regulamentadas
Em setores regulamentados, a pressão para “modernizar a cadeia de ferramentas de entrega”…