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 »

Diferenças entre structs e classes

No Go, uma struct é um tipo de dado fundamental que agrupa “variáveis” (atributos) sob um único nome, similar a como uma classe agrupa propriedades e métodos em linguagens orientadas a objetos como Java ou C#. No entanto, existem diferenças significativas tanto na sintaxe quanto nos conceitos e funcionalidades oferecidos por structs em Go quando comparada com classes em outras linguagens.

Estrutura e Sintaxe

Struct

Em Go, uma struct é definida usando a palavra-chave struct. A definição de uma struct envolve apenas a declaração de atributos.

type Pessoa struct {
	Nome  string
	Idade int
}
Leia mais »

Otimização automatizada com PGO

A otimização de desempenho é uma preocupação constante no desenvolvimento de software, e a linguagem Go não é uma exceção. Uma técnica que tem ganhado bastante atenção nesse contexto é a Profile-Guided Optimization (PGO). Neste post, vamos explorar o que é PGO, sua história na linguagem Go, e como você pode utilizar essa técnica tanto em aplicações de linha de comando (CLI) quanto em APIs.

O que é PGO?

PGO é uma técnica de otimização que utiliza dados de execução de uma aplicação para guiar o processo de compilação. Ao contrário da otimização tradicional, onde o compilador faz suposições gerais, o PGO permite ao compilador otimizar o código com base em dados reais de uso, levando a um desempenho significativamente melhorado.

Leia mais »

Como implementar mTLS em aplicações Go

Hoje vamos explorar como implementar o mTLS (Mutual TLS), que é uma técnica de segurança para autenticação mútua entre cliente e servidor, em uma aplicação Go.

Mas antes de começar, vamos entender um pouco melhor o que é TLS (Transport Layer Security) e qual sua diferença com mTLS.

TLS vs mTLS

O TLS é usado para criptografar a comunicação entre cliente e servidor. Nele, comumente usado em conexões HTTPS, apenas o servidor se autentica perante o cliente, usando um certificado digital para garantir que o cliente está se comunicando com o servidor correto.

Leia mais »

O que é e como aplicar Dependency Inversion Principle

Nesse segundo post da série de posts sobre SOLID em Go, foquemos na letra ‘D’, ou seja, no Dependency Inversion Principle.

Se você não viu o primeiro post da série, recomendo a leitura para ter uma visão geral do que é SOLID.

Antes de ver como aplicar Dependency Inversion Principle em Go, vamos relembrar seu conceito.

Dependências devem ser abstraídas, para que os módulos de alto nível não dependam dos módulos de baixo nível.

Para facilitar o entendimento, vejamos um pouco de código. Para começar, um exemplo de como violar o Dependency Inversion Principle.

Leia mais »
crop nurse with syringe ready to vaccinate patients

O que é e como utilizar Dependency Injection

Se você já ouviu falar mas não sabe ao certo o que é Dependency Injection ou como a utilizar em Golang, nesse post espero te ajudar a sanar as duas dúvidas.

Para que todos estejam na mesma página, antes de ver como utilizar, vamos falar um pouco sobre o que é essa tal Dependency Injection ou DI para os íntimos.

Podemos definir DI (Dependency Injection) como uma técnica onde os módulos recebem todas ou parte de suas dependências de forma indireta, ou seja, por parâmetro em uma função/método ou sendo passada diretamente para o campo de uma struct, onde tais parâmetros ou campos não tenham um tipo definido, mas sim uma interface.

Vantagens da Dependency Injection

Utilizar essa técnica ajuda com que nosso código tenha baixo acoplamento, o que torna a tarefa de refatorar partes do sistema muito mais fácil.

Leia mais »
photo of gray faucet

Como resolver memory leaks em maps

Uma das formas mais comuns de se fazer cache em aplicações Go é utilizando um map. Se você já fez isso, deve ter notado um aumento gradual no consumo de memória, e que normalmente após um restart da máquina ou pod volta ao “normal”.

Isso acontece devido a forma como o map funciona. Por isso, antes de ver o que podemos fazer para resolver esse tipo de problema, vamos entender melhor o map.

Para exemplificar o problema, vamos considerar uma variável do tipo map[int][128]byte, que será “carregada” com 1 milhão de elementos e que na sequência serão removidas.

package main

import (
	"fmt"
	"runtime"
)

func main() {
	n := 1_000_000
	m := make(map[int][128]byte)
	printAlloc()

	for i := 0; i < n; i++ {
		m[i] = [128]byte{}
	}
	printAlloc()

	for i := 0; i < n; i++ {
		delete(m, i)
	}

	runtime.GC()
	printAlloc()
	runtime.KeepAlive(m)
}

func printAlloc() {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	fmt.Printf("%d KB\\n", m.Alloc/1024)
}
Leia mais »
gray concrete road near forest

Mutex ou channels? Como resolver race condition

Existem basicamente duas formas para resolver problemas de race condition. Mutex e Channels.

Se você não está familiarizado com o termo race condition, não se preocupe. Esse termo é utilizado para descrever um pedaço do código que será executado por múltiplas goroutines e que, a cada execução, seu resultado pode variar devido a forma como o Go alterna a execução entre goroutines.

Para ficar um pouco mais claro, vamos dar uma olhada no código abaixo.

package main

import (
	"fmt"
	"sync"
)

var total = 0

func count(wg *sync.WaitGroup) {
	total++
	wg.Done()
}

func main() {
	var wg sync.WaitGroup

	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go count(&wg)
	}
	wg.Wait()
	fmt.Println("total: ", total)
}
Leia mais »
snow top mountain under clear sky

Como diminuir o tamanho da sua aplicação com ldflags

Como você deve ter visto no vídeo que postamos no canal, uma das formas de reduzir o tamanho de uma imagem docker para aplicações Go é utilizando a imagem scratch como base.

Mas e o binário? Como podemos reduzi-lo sem remover código?

É isso que vamos ver nesse post.

Para que tenhamos uma base de programa para testar os comandos que vamos ver nesse post, vamos escrever uma API bem simples.

package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(rw, "Olá Mundo\\n")
	})

	log.Fatal(http.ListenAndServe(":8080", nil))
}
Leia mais »

Como colocar rótulo em looping

Não sei vocês, mas a primeira vez que “ouvi” falar dessa feature foi há algumas semanas atrás. Mais uma vez, não foi em nenhum blog post ou vídeo do youtube que ví a utilização dessa feature, mas sim no código fonte da linguagem.

Com a minha experiência em outras linguagens, sempre que tinha que lidar com um looping dentro de outro, a maneira mais comum de fazer um “break” dos 2 loopings era com uma variável de controle.

Nessa estratégia, o looping interno altera essa variável e faz um break. Com seu valor alterado, o looping externo também faz um “break”.

Leia mais »