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 »

Como funciona o Garbage Collector do Go

O Garbage Collector (GC) é um dos elementos cruciais da linguagem Go, pois foi projetado para simplificar a gestão de memória para desenvolvedores. Ao contrário de linguagens como C e C++, onde os programadores devem gerenciar a alocação e liberação de memória manualmente, o GC em Go automatiza esse processo.

Neste post, vamos explorar o funcionamento do Garbage Collector em Go, entender como ele age em diferentes cenários e identificar armadilhas que podem causar memory leaks mesmo com o GC em ação.

O que é Garbage Collector

O Garbage Collector é um mecanismo automático responsável por liberar a memória alocada para objetos que não estão mais sendo utilizados no programa. Em Go, ele atua identificando quais variáveis e estruturas de dados não são mais acessíveis ou referenciadas no código e, em seguida, liberando essa memória para que possa ser reutilizada. Isso melhora a eficiência da aplicação e evita problemas como vazamento de memória (memory leaks).

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 »

Quando utilizar generics e interfaces

A linguagem Go é amplamente conhecida por sua simplicidade e pragmatismo. O design da linguagem sempre incentivou a criação de código claro e direto, evitando abstrações desnecessárias.

Com a introdução de generics no Go 1.18, desenvolvedores agora têm mais uma ferramenta para criar abstrações poderosas e reutilizáveis. Além disso, as interfaces já desempenham um papel fundamental na criação de designs flexíveis e desacoplados.

No entanto, é preciso cautela: abstrações excessivas podem facilmente adicionar complexidade sem trazer benefícios reais.

Neste post, vamos discutir quando utilizar generics e interfaces em Go e quando é melhor evitá-los.

Leia mais »

A importância de interfaces em arquiteturas de camadas

Um código organizado é essencial para manter a facilidade em sua manutenção. Go, com sua simplicidade e eficiência, oferece diversos recursos para garantir uma arquitetura bem estruturada.

Um desses recursos é o uso de interfaces, que desempenham um papel fundamental na separação de responsabilidades e na criação de abstrações entre as camadas da aplicação.

Neste post, exploraremos como as interfaces podem ser aplicadas dentro de uma arquitetura em camadas, promovendo um código desacoplado, testável e flexível.

O que é uma arquitetura em camadas

Uma arquitetura em camadas é um padrão de design de software que divide a aplicação em diferentes camadas, onde cada uma tem uma responsabilidade específica.

Leia mais »

Por que evitar o uso da função init

Nas últimas semanas, tenho focado muito em escrever sobre o que evitar na hora de escrever programas Go.

Tenho feito isso pois, em alguns casos, o melhor que se pode saber sobre uma feature ou package é exatamente quando não utilizar.

Por isso, dando continuidade nesse tipo de post, neste, vamos explorar o que é a função init, como ela funciona, porque seu uso pode ser problemático e quando ela deve ser utilizada de forma consciente.

O que é e para que serve a função init

A função init em Go é uma função especial que é automaticamente executada pelo runtime antes da função main, sem a necessidade de ser chamada explicitamente.

Leia mais »

Por que evitar panic e recover em produção

No desenvolvimento de software, especialmente em linguagens como Go, garantir a estabilidade e a resiliência da aplicação é essencial, especialmente em ambientes de produção.

Uma das funcionalidades controversas do Go é o uso de panic e recover. Apesar de serem recursos poderosos, o uso inadequado deles pode levar a sérios problemas em produção.

Neste post, exploraremos o que são panic e recover, suas implicações e por que você deve evitá-los em ambientes de produção.

O que é panic?

Em Go, panic é uma função que interrompe a execução normal da aplicação, imediatamente propagando um erro até o ponto mais alto da pilha de chamadas (stack). Quando uma função chama panic, a execução da função é interrompida, qualquer função chamada com defer é executada e o programa se encerra (a menos que o panic seja recuperado com recover).

Leia mais »

Por que evitar o package Reflect

O package reflect no Go é uma ferramenta poderosa que permite inspecionar e manipular tipos e valores em runtime. No entanto, como diria o tio Ben, “com grandes poderes vêm grandes responsabilidades”.

Embora possa parecer atraente em certos cenários, o uso excessivo ou inadequado do reflect pode introduzir problemas significativos no seu código, como dificuldades de manutenção, bugs difíceis de depurar e perda de performance.

Neste post, exploraremos o que é o package reflect, exemplos de sua utilização, onde ele é amplamente empregado e, mais importante, porque você deve evitá-lo quando possível.

O que é o package Reflect

O package reflect faz parte da biblioteca padrão do Go e oferece funcionalidades para inspecionar tipos e valores em runtime, ou seja, em tempo de execução.

Leia mais »