Notas de um desenvolvedor · arquitetura web e ferramentas

dev.andreximenes

← Notas

Go vs TypeScript: otimizando a runtime da API

Migrei serviço de thumbnail de Node para Go no mesmo hardware. CPU caiu de 80% para 25% sob carga igual. Não era código ruim em TypeScript: decode PNG, resize, encode WebP bloqueia event loop. Uma requisição pesada atrasa todas as outras no processo single-threaded. Go distribuiu trabalho em goroutines e usou núcleos que Node deixava ociosos.

Escolher linguagem da API é escolher modelo de execução. V8 com event loop e JIT versus binário estático com scheduler nativo. Métrica manda mais que preferência de sintaxe.

Modelo de execução

Node brilha quando thread espera rede ou disco. Go brilha quando thread calcula. TypeScript compila para JS interpretado/JIT; Go compila para binário sem VM no caminho quente. Memória por conexão WebSocket aberta costuma ser menor em Go; milhares de sockets no mesmo pod viram problema de custo em Node antes de virar problema de código.

Isso não torna Go "melhor". Torna Go adequado quando CPU ou concorrência densa é o gargalo medido, não chute.

TypeScript: I/O bound e entrega rápida

API que consulta Postgres, chama Stripe e monta JSON raramente morre na runtime. Latência P99 segue query lenta ou API externa. Tipos compartilhados com front (zod ou tRPC no monorepo) aceleram feature que muda toda semana. CRUD, webhook handler, orquestrador de fila leve: Node entrega rápido, contrata dev com stack conhecida, debug com ferramentas maduras.

Microsserviço que só encadeia HTTP e publica evento não precisa de Go por reputação. Precisa de observabilidade e query indexada.

Go: CPU bound e muitas conexões

Proxy WebSocket com 20k clientes, worker de compressão, parser de log em stream, serviço de auth com bcrypt por requisição: event loop sofre. Goroutine barata permite um processo servir conexão longa sem thread OS por client. Cold start de binário pequeno ajuda em Lambda e Cloud Run quando função acorda frequente.

Criptografia, serialização pesada, transformação de mídia: perfil clássico de extração para serviço Go enquanto resto do produto fica em TypeScript.

Sinais para migrar (ou não)

Olhe métricas antes de reescrever. CPU alta com I/O idle aponta compute no Node. Latência P99 subindo com throughput de conexões simultâneas aponta pressão no event loop. Memória linear com contagem de socket idem.

Sintoma Provável gargalo Caminho
CPU 70%+ com DB wait baixo Compute JS Extrair hot path para Go
P99 domina query externa I/O Otimizar SQL/contrato, ficar em TS
RAM sobe com WebSockets Conexões Go ou separar hub de conexão
Time só TS, CRUD estável Organizacional Migrar só se métrica exigir

Reescrever tudo em Go por moda troca velocidade de produto por eficiência que talvez nunca use. Extrair um serviço quando flamegraph ou APM mostrar função quente: abordagem que já pagou em produção.

TypeScript para entregar e iterar. Go para trecho que medidor apontou como limite de runtime.