Tema: go
-
Escolher entre Go e Rust para um novo serviço: um procedimento de decisão sem benchmarks
Como decidir entre Go e Rust para um serviço com base nas propriedades documentadas das linguagens e nas restrições da equipe, e não em folclore de benchmarks: modelo de gerenciamento de memória, estilo de erros e concorrência, perfil da carga, bibliotecas com as quais o serviço precisa se comunicar e quem fará a manutenção daqui a dois anos.
-
Cancelamento e prazos em Go com context.Context
Propague um context.Context desde a requisição recebida por todas as chamadas que podem bloquear, derive contextos filhos com WithTimeout ou WithCancel, sempre chame a função cancel e verifique ctx.Done() em laços, para que a desconexão do cliente ou um prazo esgotado interrompa toda a árvore de goroutines em vez de deixá-las em execução.
-
Tempo decorrido em Go: a serialização perde o componente do relógio monotônico
Mantenha a medição local de duração separada dos timestamps persistidos e das políticas de prazo entre processos.
-
Interfaces em Go: satisfação implícita e o nil que não é nil
Um tipo em Go satisfaz uma interface simplesmente por ter os métodos dela, sem nenhuma declaração. Isso torna barato definir interfaces pequenas onde são usadas, mas um valor de interface é um par de tipo e valor, então um ponteiro nil guardado numa interface error não é igual a nil.
-
Aliasing em append no Go: teste os caminhos com capacidade sobressalente e com realocação
Torne explícita a propriedade (ownership) do slice quando um append sobre uma view pode modificar o armazenamento observado em outro ponto do código.
-
Tratamento de erros em Go: encapsulamento com %w, errors.Is e errors.As
Em Go, as funções retornam erros como valores comuns; adicione contexto com fmt.Errorf e o verbo %w para manter o erro original acessível, e depois inspecione a cadeia com errors.Is para valores sentinela e errors.As (ou o genérico errors.AsType) para tipos, em vez de comparar strings ou usar ==.
-
Goroutines, channels e o pacote sync: visão geral da concorrência em Go
Uma instrução go executa uma chamada de função de forma concorrente, em uma pilha barata e expansível; os channels transportam valores entre goroutines e bloqueiam até que os dois lados estejam prontos; sync.WaitGroup, Mutex e Once cobrem os casos em que compartilhar memória é mais simples. Uma data race é um bug cujo resultado o modelo de memória restringe apenas em parte, e o detector -race é a ferramenta para encontrá-la.
-
Quanto mais tempo um engenheiro vindo de uma linguagem dinâmica leva para ser produtivo em Rust do que em Go, e quais conceitos explicam a diferença?
Pergunta em aberto: Go costuma ser descrita como rápida de aprender e Rust como exigente, e a pesquisa State of Rust 2024 indica que cerca de 31% dos não usuários citam a dificuldade percebida. Poucas fontes, porém, medem o tempo até a primeira alteração integrada, até a revisão de código sem supervisão ou quais conceitos (ownership, lifetimes, async, traits) consomem esse tempo para quem vem de Python, Ruby ou JavaScript.
-
Testes orientados por tabela em Go com subtestes
Escreva uma única função de teste que percorre um slice de casos nomeados e executa cada um com t.Run; os casos passam a ser dados, um caso isolado pode ser selecionado com go test -run 'TestX/name', e t.Parallel, t.Helper e t.Cleanup mantêm o laço rápido e legível.
-
Cobertura do detector de data races do Go: uma execução limpa não diz nada sobre caminhos não executados
Relacione os resultados de go test -race aos caminhos concorrentes realmente exercitados, incluindo a inicialização e o encerramento.
-
Traits do Rust e interfaces do Go: impl explícito versus satisfação implícita
As duas linguagens abstraem comportamento sem hierarquias de classes, mas em Go um tipo satisfaz uma interface apenas por ter os métodos, enquanto em Rust um tipo implementa um trait somente por meio de um bloco impl explícito, sujeito à orphan rule. Rust ainda separa generics em tempo de compilação (monomorfizados) de trait objects `dyn` (despacho dinâmico), uma escolha que em Go é feita pela própria linguagem.
-
Go modules: go.mod, go.sum e o sufixo de versão major
Um módulo Go é uma árvore versionada de pacotes descrita pelo go.mod; o comando go escolhe as versões das dependências por seleção de versão mínima, verifica os downloads contra o go.sum e exige um sufixo no estilo /v2 no caminho do módulo para toda versão major acima de 1, de modo que versões incompatíveis tenham caminhos de importação diferentes.
-
Cópia de mutex em Go: mantenha a identidade do lock junto com o estado que ele protege
Audite receivers por valor, atribuições e operações em contêineres que possam copiar uma estrutura contendo um mutex em uso.
Legível por máquina: JSON