Gerenciando ferramentas com go tool

A versão 1.24 do Go trouxe diversas melhorias significativas, incluindo suporte completo a aliases de tipos genéricos, aprimoramentos no desempenho do runtime e novas funcionalidades no sistema de módulos.

Entre essas novidades, destaca-se a introdução do comando go tool, que simplifica o gerenciamento de dependências de ferramentas auxiliares, como linters e geradores de código, diretamente no arquivo go.mod.

Nesse post, vamos ver como utilizar esse novo comando e como essa mudança elimina a necessidade de soluções alternativas anteriormente utilizadas para rastrear ferramentas como linters e geradores de código.

Como Era Antes

Antes do Go 1.24, gerenciar ferramentas auxiliares em projetos Go exigia abordagens não oficiais.

Leia mais »

Estratégias para gerenciar múltiplas versões de APIs

No universo do desenvolvimento de software, as APIs (Application Programming Interfaces) desempenham um papel fundamental na comunicação entre diferentes sistemas. No entanto, à medida que uma API evolui, surge um desafio inevitável: como gerenciar múltiplas versões sem comprometer a experiência dos usuários e sem introduzir instabilidade no sistema?

Neste post, exploraremos as principais estratégias para gerir e versionar APIs de forma eficaz. Vamos discutir diferentes abordagens, suas vantagens e desvantagens, além de apresentar ferramentas que podem facilitar o processo.

Versionamento por URL

O versionamento por URL é uma das abordagens mais comuns e simples. Nesta estratégia, a versão da API é incluída diretamente na URL, como por exemplo:

<https://api.exemplo.com/v1/recursos>
<https://api.exemplo.com/v2/recursos>
Leia mais »

Melhores práticas para tratar erros em Go

O tratamento de erros é um aspecto fundamental do desenvolvimento de software, garantindo que suas aplicações lidem adequadamente com situações inesperadas.

Em Go, o gerenciamento de erros é tratado de forma explícita e diferenciada quando comparado a outras linguagens populares como Java, Python ou JavaScript. Esse design deliberado busca tornar os erros mais visíveis e gerenciáveis, mas também exige atenção especial por parte dos desenvolvedores para evitar armadilhas comuns.

Neste post, vamos explorar as melhores práticas para tratamento de erros em Go, garantindo que suas aplicações permaneçam robustas, legíveis e fáceis de manter.

Tratamento de Erros em Go

A maneira como o Go lida com erros difere significativamente do tradicional mecanismo de try/catch encontrado em outras linguagens de programação.

Em vez de capturar exceções, o Go utiliza um retorno explícito de erros nas funções. Esse design torna o erro parte da assinatura da função, forçando os desenvolvedores a reconhecer e lidar com os erros de forma explícita.

Leia mais »

Implementando CQRS com Go

No mundo do desenvolvimento de software, arquiteturas monolíticas e baseadas em CRUD (Create, Read, Update, Delete) têm sido amplamente utilizadas. No entanto, conforme as aplicações crescem em complexidade e demanda, essas abordagens podem se tornar limitadas, especialmente em termos de escalabilidade e separação de responsabilidades.

Nesse contexto surge o CQRS (Command Query Responsibility Segregation), um padrão arquitetural que separa as operações de escrita (commands) das operações de leitura (queries).

O que é CQRS

CQRS é um padrão que propõe a separação das responsabilidades de leitura e escrita de uma aplicação. Em um sistema tradicional, uma única camada de aplicação é responsável tanto por manipular dados quanto por recuperá-los. Com CQRS, essa responsabilidade é dividida em duas partes:

Leia mais »

Como funciona for com range

Em Go, o for é uma ferramenta poderosa e flexível para realizar iterações. Dentro desse contexto, o uso do range é uma forma comum de percorrer slices, maps, strings, arrays e channels. Porém, entender como o range funciona internamente é essencial para evitar erros sutis, especialmente ao lidar com ponteiros.

Neste post, exploraremos os fundamentos do range em Go, destacaremos diferenças entre loopings com e sem range, e discutiremos erros comuns que surgem ao usar o range com ponteiros.

Avaliando a expressão

Sem range

O for em Go pode ser usado de forma simples e direta para controlar iterações com base em uma condição.

Leia mais »

Propagação de context

Propagar o mesmo context por toda uma aplicação pode fazer sentido em alguns casos, mas não é uma prática ideal ou recomendada para todas as situações. O context deve ser utilizado cuidadosamente e com objetivos específicos.

Nesse post, vamos explorar os cenários e cuidados ao se utilizar propagação de context.

O package context

O package context é parte da biblioteca padrão do Go e foi introduzido para resolver problemas relacionados ao gerenciamento de deadlines e cancelamentos em goroutines.

Ele fornece uma maneira de passar informações importantes, como limites de tempo e sinais de cancelamento, por meio de chamadas de funções e entre diferentes partes do código.

Para entender um pouco mais sobre esse package, recomendo a leitura dos posts:

Leia mais »

Como comparar valores em Go

Comparar valores é uma das operações mais comuns em qualquer linguagem de programação, e em Go não é diferente. Porém, a simplicidade da linguagem esconde algumas nuances importantes sobre como certos tipos podem ou não ser comparados diretamente.

Neste post, exploraremos os operadores de comparação em Go, suas limitações e alternativas.

Operadores de Comparação

De modo geral, Go oferece dois operadores para comparação direta de valores:

  • ==: Verifica se os valores dos dois operandos são iguais.
  • !=: Verifica se os valores dos dois operandos são diferentes.

Esses operadores funcionam para os tipos chamados de “comparáveis”, como por exemplo o boolean, int, float, tipos complexos, string, channels, arrays, structs e ponteiros.

Para os tipos numéricos (int, float e tipos complexos) também podemos utilizar >, <, <= e >=.

Leia mais »

Melhores práticas na utilização de ENUMs

Em linguagens de programação, enums (abreviação de enumerations) são amplamente utilizados para representar conjuntos de valores nomeados. No Go, embora não exista um tipo enum nativo, podemos alcançar um comportamento similar usando constantes tipadas.

Embora já haja um post aqui no blog sobre esse tema, resolvi criar uma versão atualizada dele onde iremos, além de explorar como implementar enums em Go, veremos as diferenças em relação a outras linguagens, e as melhores práticas na hora de utilizá-los.

ENUM em Go vs Outras Linguagens

Linguagens como Java e C# oferecem suporte nativo a enums, permitindo a criação de tipos enumerados com validação e métodos associados, como podemos ver no exemplo abaixo:

public enum Color {
    RED, GREEN, BLUE;
}
Leia mais »

Memory leaks em slices

Go é uma linguagem de programação reconhecida por sua eficiência e pelo gerenciamento automático de memória através do Garbage Collector (GC). No entanto, mesmo com essas vantagens, é possível que aplicações escritas em Go sofram de vazamentos de memória, especialmente quando se lida com slices de forma inadequada.

Neste post, exploraremos o que são memory leaks, como eles podem ocorrer em slices, e as melhores práticas para evitá-los.

O que é memory leak

Um memory leak (vazamento de memória) acontece quando um programa reserva espaço na memória para uso temporário e não o libera após o uso. Isso resulta em um consumo crescente de memória, podendo levar à degradação de desempenho ou até ao esgotamento da memória disponível, causando falhas na aplicação.

Em linguagens com gerenciamento automático de memória, como Go, o Garbage Collector é responsável por liberar a memória não utilizada. Porém, se houver referências ativas a áreas da memória que não são mais necessárias, o GC não consegue liberá-las, causando um vazamento de memória.

Leia mais »

Functional Options Pattern

No desenvolvimento de software, a flexibilidade na configuração de objetos é uma necessidade comum, especialmente quando lidamos com funções e estruturas que possuem múltiplos parâmetros opcionais.

Em Go, por ser uma linguagem que não suporta sobrecarga de funções e parâmetros opcionais, encontrar uma solução elegante para esse problema pode ser desafiador. É aqui que o Functional Options Pattern entra como uma abordagem eficaz e idiomática.

O que é Functional Options Pattern?

O Functional Options Pattern é um padrão de design amplamente utilizado em Go para facilitar a configuração de estruturas complexas ou funções, principalmente quando há múltiplos parâmetros opcionais. Ele permite que você construa objetos ou configure funções de maneira flexível, utilizando funções que atuam como “opções”.

Em vez de passar diretamente todos os parâmetros para o construtor ou para a função, você cria funções separadas que aplicam configurações de maneira incremental e opcional. Essa abordagem ajuda a evitar funções com longas listas de parâmetros ou a necessidade de múltiplos construtores para diferentes casos de uso.

Leia mais »