Fuzzing em Go: Encontre Bugs Automaticamente com Testes Nativos
Aprenda fuzzing em Go com testes nativos: escreva fuzz tests, use seed corpus, encontre bugs em parsers e validações, e integre fuzzing no CI/CD do seu projeto.
Fuzz testing (ou fuzzing) é uma técnica que alimenta sua função com entradas aleatórias e mutadas para encontrar bugs que testes manuais jamais encontrariam. Desde o Go 1.18, a linguagem possui suporte nativo a fuzzing integrado ao go test — sem precisar de ferramentas externas.
Neste guia, você vai aprender a escrever fuzz tests, entender como o motor de fuzzing funciona, encontrar bugs reais e integrar fuzzing no seu workflow de desenvolvimento.
Padrões de Concorrência em Go: Worker Pools, Fan-Out e Pipelines
Domine padrões de concorrência em Go: worker pools, fan-out/fan-in, pipelines, rate limiting e context para cancelamento. Exemplos práticos e prontos para uso.
Go nasceu para concorrência. Goroutines leves, channels tipados e o modelo CSP (Communicating Sequential Processes) tornam Go uma das linguagens mais produtivas para escrever código concorrente. Mas goroutines e channels são primitivas — para resolver problemas reais, você precisa de padrões.
Neste guia, vamos cobrir os padrões de concorrência mais importantes em Go, com exemplos prontos para produção. Se você ainda não domina os fundamentos, comece pelo nosso guia de concorrência em Go.
Iteradores em Go: Range Over Func Explicado
Aprenda iteradores em Go com range over func: iter.Seq, iter.Seq2, iter.Pull, iteradores customizados e composição de iteradores na prática.
O Go 1.23 trouxe uma das funcionalidades mais aguardadas da linguagem: range over functions, ou iteradores baseados em funções. Esse recurso permite usar for range sobre funções customizadas, abrindo um novo paradigma para processar sequências de dados em Go. Combinado com generics, os iteradores tornam o código mais expressivo sem sacrificar a performance.
O que Muda com Range Over Func?
Antes do Go 1.23, o for range funcionava apenas com tipos nativos: slices, maps, strings, channels e inteiros. Se você tinha uma estrutura de dados customizada, precisava expor o estado interno ou retornar um slice completo para iterar.
slog em Go: Logging Estruturado com a Biblioteca Padrão
Aprenda slog em Go: logging estruturado com TextHandler, JSONHandler, log levels, atributos, handlers customizados e integração com context na prática.
O pacote log/slog foi introduzido no Go 1.21 como a solução oficial para logging estruturado na biblioteca padrão. Antes dele, o pacote log era limitado a mensagens de texto simples, forçando a maioria dos projetos a depender de bibliotecas externas como zerolog ou zap. Com slog, você tem logging estruturado nativo, de alta performance, pronto para produção.
Por que Logging Estruturado?
Logs tradicionais em texto puro funcionam para debugging local, mas em ambientes de produção com centenas de serviços, você precisa de logs que sejam pesquisáveis, filtráveis e agregáveis. Logging estruturado emite cada entrada como um conjunto de pares chave-valor, facilitando a ingestão por ferramentas como Elasticsearch, Grafana Loki ou Datadog.
Context em Go: Como Usar context.Context Corretamente
Domine context.Context em Go: cancellation, timeouts, deadlines, WithValue, boas práticas em HTTP handlers e banco de dados. Evite os erros mais comuns.
O pacote context é uma das peças mais importantes do ecossistema Go. Ele resolve um problema fundamental em sistemas concorrentes: como sinalizar cancelamento, deadlines e passar metadados entre goroutines de forma segura e padronizada. Se você escreve APIs, acessa bancos de dados ou trabalha com concorrência em Go, dominar context.Context é essencial.
O que é Context?
context.Context é uma interface que carrega deadlines, sinais de cancelamento e valores request-scoped através das fronteiras de uma API. Toda chamada que pode demorar ou ser cancelada deve receber um context.Context como primeiro parâmetro.
Generics em Go: Guia Prático com Exemplos Reais
Aprenda Generics em Go com exemplos práticos: type parameters, constraints, funções e structs genéricas, repository pattern e quando não usar generics.
Generics foram introduzidos no Go 1.18 e representam uma das maiores mudanças na linguagem desde sua criação. Com eles, você pode escrever funções e tipos reutilizáveis sem sacrificar a segurança de tipos que Go oferece. Neste guia, vamos explorar generics na prática com exemplos que você pode usar no dia a dia.
O que São Generics?
Antes de generics, quando precisávamos de uma função que operasse sobre diferentes tipos, tínhamos duas opções ruins: duplicar código para cada tipo ou usar interface{} (agora any) e perder a segurança de tipos em tempo de compilação.
Go Fix: A Revolução na Modernização de Código com Inlining Inteligente
O Go 1.26 introduziu uma nova implementação do comando `go fix`, projetada para auxiliar na atualização e modernização do código Go. Uma das...
O Go 1.26 introduziu uma nova implementação do comando go fix, projetada para auxiliar na atualização e modernização do código Go. Uma das funcionalidades mais notáveis é o “source-level inliner”, que permite a autores de pacotes expressarem migrações e atualizações de API de forma simples e segura. Este resumo detalha o funcionamento do inliner, seus casos de uso e a tecnologia por trás dele.
O Que é Source-Level Inlining?
O inlining, em geral, é uma técnica de otimização de compiladores que substitui uma chamada de função pelo corpo da função chamada, substituindo os argumentos pelos parâmetros. O “source-level inlining” faz isso diretamente no código fonte, modificando-o de forma duradoura. Isso difere do inlining tradicional feito pelo compilador, que opera em representações intermediárias e é descartado após a compilação.
**Go Acelera: Alocação na Stack para um Desempenho Imbatível**
O artigo do blog oficial do Go discute otimizações recentes no compilador Go para reduzir alocações na heap, substituindo-as por alocações na stack....
O artigo do blog oficial do Go discute otimizações recentes no compilador Go para reduzir alocações na heap, substituindo-as por alocações na stack. Alocações na stack são significativamente mais rápidas e não sobrecarregam o garbage collector, resultando em programas mais eficientes em termos de tempo de execução e uso de memória. O artigo explora diferentes cenários e as melhorias introduzidas em versões recentes do Go (1.25 e 1.26) para otimizar a alocação de slices.
Go Fix: Modernizando seu Código Go Automaticamente
O artigo do blog oficial do Go discute a nova versão do `go fix`, introduzida no Go 1.26, e como essa ferramenta pode ser usada para modernizar...
O artigo do blog oficial do Go discute a nova versão do go fix, introduzida no Go 1.26, e como essa ferramenta pode ser usada para modernizar automaticamente o código Go, aproveitando os recursos mais recentes da linguagem e da biblioteca padrão. O artigo também aborda a infraestrutura por trás do go fix e como ela está evoluindo, além de apresentar o conceito de ferramentas de análise “self-service” para ajudar os mantenedores de módulos e organizações a codificar suas próprias diretrizes e boas práticas.
Go Security: Boas Práticas de Segurança
Aprenda boas práticas de segurança para aplicações Go. Guia completo sobre validação de input, autenticação, autorização, vulnerabilidades comuns e OWASP para Go.
Go Security: Boas Práticas de Segurança
Introdução
Segurança em aplicações Go é fundamental para proteger dados sensíveis, prevenir ataques e garantir conformidade com regulamentações como LGPD e GDPR. Embora Go seja uma linguagem segura por design (memory safety, type safety), vulnerabilidades de segurança ainda ocorrem principalmente devido a práticas de codificação inadequadas.
Neste guia, você vai aprender as melhores práticas de segurança para desenvolver aplicações Go robustas e protegidas contra as ameaças mais comuns.
Go e RabbitMQ: Mensageria Assíncrona Completa
Aprenda a usar RabbitMQ com Go para mensageria assíncrona. Tutorial completo com exemplos práticos de publishers, consumers, exchanges e padrões de mensageria.
Go e RabbitMQ: Mensageria Assíncrona Completa
Introdução
RabbitMQ é um dos brokers de mensagens mais populares do mundo, usado por empresas como Uber, Reddit e Stripe para processar bilhões de mensagens diariamente. Quando combinado com Go, criamos sistemas altamente performáticos, confiáveis e escaláveis.
Neste guia completo, você vai aprender desde os conceitos fundamentais até padrões avançados de mensageria com Go e RabbitMQ.
O que é RabbitMQ?
RabbitMQ é um message broker (corretor de mensagens) de código aberto que implementa o protocolo AMQP (Advanced Message Queuing Protocol). Ele atua como um intermediário entre aplicações, permitindo comunicação assíncrona e desacoplada.
Go e Kubernetes: Deploy de Containers
Guia completo para fazer deploy de aplicações Go em Kubernetes. Aprenda a containerizar apps Go, criar manifests K8s e implementar health checks.
Go e Kubernetes: Deploy de Containers
Neste guia completo, você aprenderá a fazer deploy de aplicações Go em Kubernetes, desde a containerização até a configuração de health checks e boas práticas de produção. Se você está construindo microserviços ou APIs REST em Go, o Kubernetes é a plataforma ideal para orquestrar seus containers.
Por que Kubernetes para Go?
Go foi projetada para a era dos containers. Sua compilação para binário único, baixo consumo de memória e startup instantâneo tornam aplicações Go perfeitas para Kubernetes:
Go CLI: Criando Ferramentas de Linha de Comando Poderosas
Aprenda a construir CLI tools profissionais em Go. Domine a biblioteca Cobra, gerenciamento de flags, subcomandos, arquivos de configuração e crie ferramentas de linha de comando com excelente UX.
Ferramentas de linha de comando (CLI) são essenciais no arsenal de qualquer desenvolvedor. Desde gerenciadores de pacotes como npm e pip até infraestrutura como kubectl e terraform, CLIs bem projetadas aumentam a produtividade exponencialmente. Go é a linguagem perfeita para criar CLIs rápidas, portáteis e eficientes.
Neste guia completo, você aprenderá a construir CLI tools profissionais usando Go, desde flags simples até ferramentas complexas com subcomandos e auto-complete.
Por Que Go para CLI Tools?
Vantagens Competitivas
┌─────────────────────────────────────────────────────────────────┐
│ CARACTERÍSTICA │ GO │ PYTHON │ NODE.JS │ RUST │
├─────────────────────────────────────────────────────────────────┤
│ Startup │ ~5ms │ ~100ms │ ~200ms │ ~10ms │
├─────────────────────────────────────────────────────────────────┤
│ Binário único │ ✅ │ ❌ │ ❌ │ ✅ │
├─────────────────────────────────────────────────────────────────┤
│ Cross-compile │ ✅ │ ❌ │ ❌ │ ✅ │
├─────────────────────────────────────────────────────────────────┤
│ Memória │ Baixa │ Alta │ Média │ Baixa │
├─────────────────────────────────────────────────────────────────┤
│ Curva de aprend. │ Média │ Baixa │ Baixa │ Alta │
└─────────────────────────────────────────────────────────────────┘
Casos de Sucesso
- Docker: Container runtime escrito em Go
- Kubernetes: Orquestração de containers
- Hugo: Gerador de sites estáticos
- Terraform: Infrastructure as Code
- Cobra: Framework CLI usado por Kubernetes, etcd, e muitos outros
Fundamentos de CLI em Go
Flags Nativas com flag Package
Go inclui um pacote flag na biblioteca padrão para parsing de argumentos:
Go e Docker: Containerização de Aplicações com Multi-Stage Builds
Aprenda a containerizar aplicações Go com Docker. Guia completo de Dockerfiles otimizados, multi-stage builds, Docker Compose para desenvolvimento, boas práticas de produção e segurança. Reduza imagens de 1GB para 15MB.
Go e Docker são uma combinação poderosa. Enquanto aplicações em outras linguagens precisam de runtimes pesados, Go compila para binários nativos que rodam em containers minimalistas de 10-20MB. Neste guia, você vai aprender a criar imagens Docker otimizadas, seguras e prontas para produção.
Por Que Docker com Go?
Vantagens da Combinação
| Aspecto | Go + Docker | Outras Linguagens |
|---|---|---|
| Tamanho da Imagem | 10-50MB | 100MB-1GB+ |
| Tempo de Startup | < 100ms | 1-30 segundos |
| Memory Footprint | 10-50MB | 100MB-1GB |
| Runtime | Nenhum (binário nativo) | JVM, Node, Python |
| Security Surface | Mínima (scratch/alpine) | Grande (SO completo) |
Casos de Uso
- Microserviços: Deploy rápido e escalável
- CI/CD: Builds reproduzíveis
- Desenvolvimento: Ambiente consistente
- Produção: Alta densidade de containers
Dockerfile Básico para Go
O Problema: Dockerfile Inicial
# ❌ NÃO FAÇA ISSO - Imagem gigante (~1GB)
FROM golang:1.21
WORKDIR /app
COPY . .
RUN go build -o main .
CMD ["./main"]
Problemas:
Go e MongoDB: CRUD e Agregações Completas
Aprenda a integrar Go com MongoDB de forma profissional. Domine operações CRUD, aggregation pipeline, indexing, transações e padrões de produção com o driver oficial.
MongoDB é o banco de dados NoSQL mais popular do mundo, ideal para aplicações modernas que precisam de flexibilidade e escalabilidade. Combinado com Go, você tem uma stack poderosa para lidar com dados não estruturados e semi-estruturados. Neste guia, você aprenderá tudo sobre MongoDB em Go, desde operações básicas até agregações complexas.
Por Que MongoDB com Go?
Quando Escolher MongoDB
┌─────────────────────────────────────────────────────────────────┐
│ MONGODB É IDEAL PARA: │
├─────────────────────────────────────────────────────────────────┤
│ ✅ Dados flexíveis e em evolução │
│ ✅ Alta velocidade de escrita │
│ ✅ Escalabilidade horizontal (sharding) │
│ ✅ Documentos JSON-like nativos │
│ ✅ Geolocalização e queries espaciais │
│ ✅ Prototipagem rápida │
├─────────────────────────────────────────────────────────────────┤
│ MONGODB + GO = Type-safe + Flexibilidade │
└─────────────────────────────────────────────────────────────────┘
MongoDB vs PostgreSQL com Go
| Aspecto | MongoDB | PostgreSQL |
|---|---|---|
| Esquema | Flexível (schema-less) | Rígido (schema-full) |
| Relacionamentos | Embutidos ou referências | JOINs nativos |
| Escalabilidade | Horizontal (sharding) | Vertical + Replicação |
| Casos de uso | CMS, IoT, Analytics | Financeiro, ERP, ACID |
| Performance | Excelente para reads | Excelente para ACID |
Configuração do Projeto
Instalação do Driver
# Driver oficial MongoDB para Go
go get go.mongodb.org/mongo-driver/v2/mongo
# BSON utilities
go get go.mongodb.org/mongo-driver/v2/bson
# Options e configs
go get go.mongodb.org/mongo-driver/v2/mongo/options
Estrutura do Projeto
mongo-project/
├── cmd/
│ └── api/
│ └── main.go
├── internal/
│ ├── config/
│ │ └── mongodb.go
│ ├── models/
│ │ └── user.go
│ ├── repository/
│ │ └── user_repository.go
│ └── service/
│ └── user_service.go
├── go.mod
└── .env
Conexão com MongoDB
Configuração da Conexão
// internal/config/mongodb.go
package config
import (
"context"
"fmt"
"log"
"os"
"time"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)
// MongoConfig armazena configurações de conexão
type MongoConfig struct {
URI string
Database string
Timeout time.Duration
}
// NewMongoConfig cria configuração a partir de variáveis de ambiente
func NewMongoConfig() *MongoConfig {
return &MongoConfig{
URI: getEnv("MONGODB_URI", "mongodb://localhost:27017"),
Database: getEnv("MONGODB_DATABASE", "myapp"),
Timeout: 10 * time.Second,
}
}
// Connect estabelece conexão com MongoDB
func (cfg *MongoConfig) Connect() (*mongo.Client, error) {
ctx, cancel := context.WithTimeout(context.Background(), cfg.Timeout)
defer cancel()
// Configurar opções do cliente
clientOptions := options.Client().
ApplyURI(cfg.URI).
SetMaxPoolSize(100).
SetMinPoolSize(10).
SetMaxConnIdleTime(30 * time.Second).
SetServerSelectionTimeout(5 * time.Second)
// Conectar
client, err := mongo.Connect(clientOptions)
if err != nil {
return nil, fmt.Errorf("falha ao conectar ao MongoDB: %w", err)
}
// Verificar conexão
if err := client.Ping(ctx, nil); err != nil {
return nil, fmt.Errorf("falha ao ping MongoDB: %w", err)
}
log.Println("✅ Conectado ao MongoDB")
return client, nil
}
// GetCollection retorna uma coleção específica
func (cfg *MongoConfig) GetCollection(client *mongo.Client, name string) *mongo.Collection {
return client.Database(cfg.Database).Collection(name)
}
// Disconnect fecha a conexão gracefully
func Disconnect(client *mongo.Client) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := client.Disconnect(ctx); err != nil {
return fmt.Errorf("falha ao desconectar: %w", err)
}
log.Println("🔌 Desconectado do MongoDB")
return nil
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
String de Conexão (Connection String)
// Exemplos de URI para diferentes cenários
// Local
mongodb://localhost:27017/myapp
// Com autenticação
mongodb://user:password@localhost:27017/myapp?authSource=admin
// Replica Set
mongodb://user:password@host1:27017,host2:27017,host3:27017/myapp?replicaSet=rs0
// MongoDB Atlas (cloud)
mongodb+srv://user:password@cluster.mongodb.net/myapp?retryWrites=true&w=majority
// Com opções adicionais
mongodb://localhost:27017/myapp?maxPoolSize=100&serverSelectionTimeoutMS=5000
Modelos e Estruturas
Definindo Documentos
// internal/models/user.go
package models
import (
"time"
"go.mongodb.org/mongo-driver/v2/bson/primitive"
)
// User representa um usuário no MongoDB
type User struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"id"`
Email string `bson:"email" json:"email" validate:"required,email"`
Name string `bson:"name" json:"name" validate:"required,min=3,max=100"`
Password string `bson:"password" json:"-"` // Não serializar
Profile UserProfile `bson:"profile" json:"profile"`
Roles []string `bson:"roles" json:"roles"`
Active bool `bson:"active" json:"active"`
Tags []string `bson:"tags,omitempty" json:"tags,omitempty"`
Metadata map[string]interface{} `bson:"metadata,omitempty" json:"metadata,omitempty"`
CreatedAt time.Time `bson:"created_at" json:"created_at"`
UpdatedAt time.Time `bson:"updated_at" json:"updated_at"`
}
// UserProfile dados aninhados
type UserProfile struct {
Bio string `bson:"bio,omitempty" json:"bio,omitempty"`
Avatar string `bson:"avatar,omitempty" json:"avatar,omitempty"`
BirthDate time.Time `bson:"birth_date,omitempty" json:"birth_date,omitempty"`
Location string `bson:"location,omitempty" json:"location,omitempty"`
Website string `bson:"website,omitempty" json:"website,omitempty"`
}
// UserCreate DTO para criação
type UserCreate struct {
Email string `json:"email" validate:"required,email"`
Name string `json:"name" validate:"required,min=3,max=100"`
Password string `json:"password" validate:"required,min=8"`
Profile UserProfile `json:"profile,omitempty"`
Tags []string `json:"tags,omitempty"`
}
// UserUpdate DTO para atualização parcial
type UserUpdate struct {
Name *string `json:"name,omitempty"`
Email *string `json:"email,omitempty"`
Profile *UserProfile `json:"profile,omitempty"`
Roles []string `json:"roles,omitempty"`
Tags []string `json:"tags,omitempty"`
Active *bool `json:"active,omitempty"`
}
// CollectionName retorna o nome da coleção
func (User) CollectionName() string {
return "users"
}
Trabalhando com ObjectID
// Criar novo ObjectID
id := primitive.NewObjectID()
// Converter string para ObjectID
id, err := primitive.ObjectIDFromHex("507f1f77bcf86cd799439011")
if err != nil {
// Handle error
}
// Converter ObjectID para string
idString := id.Hex()
// Timestamp do ObjectID
timestamp := id.Timestamp()
Operações CRUD
Repository Pattern
// internal/repository/user_repository.go
package repository
import (
"context"
"errors"
"fmt"
"time"
"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/bson/primitive"
"go.mongodb.org/mongo-driver/v2/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options"
"project/internal/models"
)
var (
ErrUserNotFound = errors.New("usuário não encontrado")
ErrEmailExists = errors.New("email já existe")
ErrInvalidID = errors.New("ID inválido")
)
// UserRepository interface
type UserRepository interface {
Create(ctx context.Context, user *models.UserCreate) (*models.User, error)
GetByID(ctx context.Context, id string) (*models.User, error)
GetByEmail(ctx context.Context, email string) (*models.User, error)
List(ctx context.Context, filter ListFilter) ([]*models.User, int64, error)
Update(ctx context.Context, id string, update *models.UserUpdate) (*models.User, error)
Delete(ctx context.Context, id string) error
Count(ctx context.Context, filter bson.M) (int64, error)
Exists(ctx context.Context, email string) (bool, error)
}
// userRepo implementação
type userRepo struct {
collection *mongo.Collection
}
// NewUserRepository cria nova instância
func NewUserRepository(db *mongo.Database) UserRepository {
return &userRepo{
collection: db.Collection(models.User{}.CollectionName()),
}
}
CREATE (Inserção)
// Create insere novo usuário
func (r *userRepo) Create(ctx context.Context, user *models.UserCreate) (*models.User, error) {
now := time.Now()
newUser := models.User{
ID: primitive.NewObjectID(),
Email: user.Email,
Name: user.Name,
Password: hashPassword(user.Password),
Profile: user.Profile,
Roles: []string{"user"},
Active: true,
Tags: user.Tags,
CreatedAt: now,
UpdatedAt: now,
}
// Inserir documento
result, err := r.collection.InsertOne(ctx, newUser)
if err != nil {
// Verificar erro de duplicação
if mongo.IsDuplicateKeyError(err) {
return nil, ErrEmailExists
}
return nil, fmt.Errorf("falha ao criar usuário: %w", err)
}
// O InsertedID já é o ID do documento
newUser.ID = result.InsertedID.(primitive.ObjectID)
// Limpar senha antes de retornar
newUser.Password = ""
return &newUser, nil
}
// CreateMany insere múltiplos documentos
func (r *userRepo) CreateMany(ctx context.Context, users []*models.UserCreate) ([]string, error) {
docs := make([]interface{}, len(users))
now := time.Now()
for i, user := range users {
docs[i] = models.User{
ID: primitive.NewObjectID(),
Email: user.Email,
Name: user.Name,
Password: hashPassword(user.Password),
Active: true,
CreatedAt: now,
UpdatedAt: now,
}
}
result, err := r.collection.InsertMany(ctx, docs)
if err != nil {
return nil, fmt.Errorf("falha ao criar usuários: %w", err)
}
// Converter IDs para strings
ids := make([]string, len(result.InsertedIDs))
for i, id := range result.InsertedIDs {
ids[i] = id.(primitive.ObjectID).Hex()
}
return ids, nil
}
func hashPassword(password string) string {
// Use bcrypt em produção!
// import "golang.org/x/crypto/bcrypt"
return "hashed_" + password
}
READ (Consultas)
// GetByID busca por ID
func (r *userRepo) GetByID(ctx context.Context, id string) (*models.User, error) {
objectID, err := primitive.ObjectIDFromHex(id)
if err != nil {
return nil, ErrInvalidID
}
var user models.User
err = r.collection.FindOne(ctx, bson.M{"_id": objectID}).Decode(&user)
if err != nil {
if errors.Is(err, mongo.ErrNoDocuments) {
return nil, ErrUserNotFound
}
return nil, fmt.Errorf("falha ao buscar usuário: %w", err)
}
user.Password = "" // Não retornar senha
return &user, nil
}
// GetByEmail busca por email
func (r *userRepo) GetByEmail(ctx context.Context, email string) (*models.User, error) {
var user models.User
err := r.collection.FindOne(ctx, bson.M{"email": email}).Decode(&user)
if err != nil {
if errors.Is(err, mongo.ErrNoDocuments) {
return nil, ErrUserNotFound
}
return nil, fmt.Errorf("falha ao buscar usuário: %w", err)
}
return &user, nil // Retornar com senha para autenticação
}
// ListFilter filtros para listagem
type ListFilter struct {
Active *bool
Roles []string
Tags []string
Search string
SortBy string
SortDesc bool
Page int64
Limit int64
}
// List retorna lista paginada
func (r *userRepo) List(ctx context.Context, filter ListFilter) ([]*models.User, int64, error) {
// Construir filtro
query := bson.M{}
if filter.Active != nil {
query["active"] = *filter.Active
}
if len(filter.Roles) > 0 {
query["roles"] = bson.M{"$in": filter.Roles}
}
if len(filter.Tags) > 0 {
query["tags"] = bson.M{"$in": filter.Tags}
}
if filter.Search != "" {
query["$or"] = []bson.M{
{"name": bson.M{"$regex": filter.Search, "$options": "i"}},
{"email": bson.M{"$regex": filter.Search, "$options": "i"}},
}
}
// Contar total
total, err := r.collection.CountDocuments(ctx, query)
if err != nil {
return nil, 0, fmt.Errorf("falha ao contar documentos: %w", err)
}
// Configurar paginação
if filter.Page < 1 {
filter.Page = 1
}
if filter.Limit < 1 || filter.Limit > 100 {
filter.Limit = 10
}
skip := (filter.Page - 1) * filter.Limit
// Configurar ordenação
sortOrder := 1 // Ascendente
if filter.SortDesc {
sortOrder = -1
}
sortField := filter.SortBy
if sortField == "" {
sortField = "created_at"
}
opts := options.Find().
SetSkip(skip).
SetLimit(filter.Limit).
SetSort(bson.D{{Key: sortField, Value: sortOrder}})
// Executar query
cursor, err := r.collection.Find(ctx, query, opts)
if err != nil {
return nil, 0, fmt.Errorf("falha ao listar usuários: %w", err)
}
defer cursor.Close(ctx)
var users []*models.User
if err := cursor.All(ctx, &users); err != nil {
return nil, 0, fmt.Errorf("falha ao decodificar resultados: %w", err)
}
// Limpar senhas
for _, u := range users {
u.Password = ""
}
return users, total, nil
}
// Exists verifica se email existe
func (r *userRepo) Exists(ctx context.Context, email string) (bool, error) {
count, err := r.collection.CountDocuments(ctx, bson.M{"email": email})
if err != nil {
return false, err
}
return count > 0, nil
}
// Count retorna contagem com filtro
func (r *userRepo) Count(ctx context.Context, filter bson.M) (int64, error) {
return r.collection.CountDocuments(ctx, filter)
}
UPDATE (Atualização)
// Update atualiza usuário parcialmente
func (r *userRepo) Update(ctx context.Context, id string, update *models.UserUpdate) (*models.User, error) {
objectID, err := primitive.ObjectIDFromHex(id)
if err != nil {
return nil, ErrInvalidID
}
// Construir update dinâmico
setFields := bson.M{
"updated_at": time.Now(),
}
unsetFields := bson.M{}
if update.Name != nil {
setFields["name"] = *update.Name
}
if update.Email != nil {
setFields["email"] = *update.Email
}
if update.Active != nil {
setFields["active"] = *update.Active
}
if update.Profile != nil {
setFields["profile"] = *update.Profile
}
if update.Roles != nil {
setFields["roles"] = update.Roles
}
if update.Tags != nil {
if len(update.Tags) == 0 {
unsetFields["tags"] = ""
} else {
setFields["tags"] = update.Tags
}
}
updateDoc := bson.M{"$set": setFields}
if len(unsetFields) > 0 {
updateDoc["$unset"] = unsetFields
}
opts := options.FindOneAndUpdate().
SetReturnDocument(options.After)
var user models.User
err = r.collection.FindOneAndUpdate(
ctx,
bson.M{"_id": objectID},
updateDoc,
opts,
).Decode(&user)
if err != nil {
if errors.Is(err, mongo.ErrNoDocuments) {
return nil, ErrUserNotFound
}
if mongo.IsDuplicateKeyError(err) {
return nil, ErrEmailExists
}
return nil, fmt.Errorf("falha ao atualizar usuário: %w", err)
}
user.Password = ""
return &user, nil
}
// UpdateMany atualiza múltiplos documentos
func (r *userRepo) UpdateMany(ctx context.Context, filter bson.M, update bson.M) (int64, error) {
result, err := r.collection.UpdateMany(ctx, filter, update)
if err != nil {
return 0, err
}
return result.ModifiedCount, nil
}
// Replace substitui documento completo
func (r *userRepo) Replace(ctx context.Context, id string, user *models.User) error {
objectID, err := primitive.ObjectIDFromHex(id)
if err != nil {
return ErrInvalidID
}
user.UpdatedAt = time.Now()
result, err := r.collection.ReplaceOne(ctx, bson.M{"_id": objectID}, user)
if err != nil {
return err
}
if result.MatchedCount == 0 {
return ErrUserNotFound
}
return nil
}
DELETE (Exclusão)
// Delete remove usuário
func (r *userRepo) Delete(ctx context.Context, id string) error {
objectID, err := primitive.ObjectIDFromHex(id)
if err != nil {
return ErrInvalidID
}
result, err := r.collection.DeleteOne(ctx, bson.M{"_id": objectID})
if err != nil {
return fmt.Errorf("falha ao deletar usuário: %w", err)
}
if result.DeletedCount == 0 {
return ErrUserNotFound
}
return nil
}
// SoftDelete (delete lógico)
func (r *userRepo) SoftDelete(ctx context.Context, id string) error {
objectID, err := primitive.ObjectIDFromHex(id)
if err != nil {
return ErrInvalidID
}
update := bson.M{
"$set": bson.M{
"active": false,
"deleted_at": time.Now(),
"updated_at": time.Now(),
},
}
result, err := r.collection.UpdateOne(ctx, bson.M{"_id": objectID}, update)
if err != nil {
return err
}
if result.MatchedCount == 0 {
return ErrUserNotFound
}
return nil
}
// DeleteMany remove múltiplos documentos
func (r *userRepo) DeleteMany(ctx context.Context, filter bson.M) (int64, error) {
result, err := r.collection.DeleteMany(ctx, filter)
if err != nil {
return 0, err
}
return result.DeletedCount, nil
}
Aggregation Pipeline
Pipeline Básica
// AggregateUsersStats estatísticas de usuários
func (r *userRepo) AggregateUsersStats(ctx context.Context) (*UserStats, error) {
pipeline := mongo.Pipeline{
// Agrupar por status ativo
{{Key: "$group", Value: bson.M{
"_id": "$active",
"count": bson.M{"$sum": 1},
"avgAge": bson.M{"$avg": "$profile.age"},
}}},
// Ordenar
{{Key: "$sort", Value: bson.M{"_id": 1}}},
}
cursor, err := r.collection.Aggregate(ctx, pipeline)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var results []bson.M
if err := cursor.All(ctx, &results); err != nil {
return nil, err
}
// Processar resultados
stats := &UserStats{}
for _, r := range results {
active := r["_id"].(bool)
count := r["count"].(int32)
if active {
stats.ActiveUsers = int(count)
} else {
stats.InactiveUsers = int(count)
}
}
return stats, nil
}
type UserStats struct {
ActiveUsers int `json:"active_users"`
InactiveUsers int `json:"inactive_users"`
}
Pipeline Avançada com Join (Lookup)
// GetUsersWithPosts usuários com seus posts (simulação de JOIN)
func (r *userRepo) GetUsersWithPosts(ctx context.Context, userID string) (*UserWithPosts, error) {
objectID, err := primitive.ObjectIDFromHex(userID)
if err != nil {
return nil, ErrInvalidID
}
pipeline := mongo.Pipeline{
// Match usuário específico
{{Key: "$match", Value: bson.M{"_id": objectID}}},
// Lookup posts do usuário (coleção separada)
{{Key: "$lookup", Value: bson.M{
"from": "posts",
"localField": "_id",
"foreignField": "author_id",
"as": "posts",
}}},
// Adicionar contagem de posts
{{Key: "$addFields", Value: bson.M{
"posts_count": bson.M{"$size": "$posts"},
}}},
// Projetar campos desejados
{{Key: "$project", Value: bson.M{
"password": 0, // Excluir senha
}}},
}
cursor, err := r.collection.Aggregate(ctx, pipeline)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var results []UserWithPosts
if err := cursor.All(ctx, &results); err != nil {
return nil, err
}
if len(results) == 0 {
return nil, ErrUserNotFound
}
return &results[0], nil
}
type UserWithPosts struct {
models.User `bson:",inline"`
Posts []Post `bson:"posts" json:"posts"`
PostsCount int `bson:"posts_count" json:"posts_count"`
}
type Post struct {
ID primitive.ObjectID `bson:"_id" json:"id"`
Title string `bson:"title" json:"title"`
Content string `bson:"content" json:"content"`
AuthorID primitive.ObjectID `bson:"author_id" json:"author_id"`
}
Faceted Search
// FacetedSearch busca com facets
func (r *userRepo) FacetedSearch(ctx context.Context, query string) (*FacetedResult, error) {
pipeline := mongo.Pipeline{
// Match na busca
{{Key: "$match", Value: bson.M{
"$or": []bson.M{
{"name": bson.M{"$regex": query, "$options": "i"}},
{"email": bson.M{"$regex": query, "$options": "i"}},
},
}}},
// Facet para múltiplas agregações
{{Key: "$facet", Value: bson.M{
"results": []bson.M{
{"$limit": 20},
{"$project": bson.M{"password": 0}},
},
"totalCount": []bson.M{
{"$count": "count"},
},
"byRole": []bson.M{
{"$unwind": "$roles"},
{"$group": bson.M{
"_id": "$roles",
"count": bson.M{"$sum": 1},
}},
},
"byStatus": []bson.M{
{"$group": bson.M{
"_id": "$active",
"count": bson.M{"$sum": 1},
}},
},
}},
}
cursor, err := r.collection.Aggregate(ctx, pipeline)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var results []FacetedResult
if err := cursor.All(ctx, &results); err != nil {
return nil, err
}
if len(results) == 0 {
return &FacetedResult{}, nil
}
return &results[0], nil
}
type FacetedResult struct {
Results []models.User `bson:"results" json:"results"`
TotalCount []struct {
Count int `bson:"count" json:"count"`
} `bson:"totalCount" json:"total_count"`
ByRole []struct {
Role string `bson:"_id" json:"role"`
Count int `bson:"count" json:"count"`
} `bson:"byRole" json:"by_role"`
ByStatus []struct {
Active bool `bson:"_id" json:"active"`
Count int `bson:"count" json:"count"`
} `bson:"byStatus" json:"by_status"`
}
Indexing Strategies
Criar Índices
// CreateIndexes cria índices necessários
func (r *userRepo) CreateIndexes(ctx context.Context) error {
// Índice único para email
emailIndex := mongo.IndexModel{
Keys: bson.D{
{Key: "email", Value: 1},
},
Options: options.Index().SetUnique(true),
}
// Índice composto para busca
nameIndex := mongo.IndexModel{
Keys: bson.D{
{Key: "name", Value: "text"},
{Key: "email", Value: "text"},
},
Options: options.Index().
SetName("text_search").
SetWeights(bson.M{"name": 10, "email": 5}),
}
// Índice para filtro de ativo + data
activeDateIndex := mongo.IndexModel{
Keys: bson.D{
{Key: "active", Value: 1},
{Key: "created_at", Value: -1},
},
}
// Índice TTL para sessões (exemplo)
ttlIndex := mongo.IndexModel{
Keys: bson.D{
{Key: "expires_at", Value: 1},
},
Options: options.Index().
SetExpireAfterSeconds(0).
SetName("session_ttl"),
}
indexes := []mongo.IndexModel{
emailIndex,
nameIndex,
activeDateIndex,
ttlIndex,
}
names, err := r.collection.Indexes().CreateMany(ctx, indexes)
if err != nil {
return fmt.Errorf("falha ao criar índices: %w", err)
}
log.Printf("✅ Índices criados: %v", names)
return nil
}
Gerenciar Índices
// ListIndexes lista todos os índices
func (r *userRepo) ListIndexes(ctx context.Context) ([]bson.M, error) {
cursor, err := r.collection.Indexes().List(ctx)
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var indexes []bson.M
if err := cursor.All(ctx, &indexes); err != nil {
return nil, err
}
return indexes, nil
}
// DropIndex remove um índice
func (r *userRepo) DropIndex(ctx context.Context, name string) error {
_, err := r.collection.Indexes().DropOne(ctx, name)
return err
}
Transações
Transações Multi-Documento
// TransferSubscription transação com múltiplas operações
func (r *userRepo) TransferSubscription(
ctx context.Context,
fromUserID, toUserID string,
plan string,
) error {
// Converter IDs
fromID, err := primitive.ObjectIDFromHex(fromUserID)
if err != nil {
return ErrInvalidID
}
toID, err := primitive.ObjectIDFromHex(toUserID)
if err != nil {
return ErrInvalidID
}
// Iniciar sessão para transação
session, err := r.collection.Database().Client().StartSession()
if err != nil {
return fmt.Errorf("falha ao iniciar sessão: %w", err)
}
defer session.EndSession(ctx)
// Callback da transação
callback := func(sessCtx mongo.SessionContext) (interface{}, error) {
// 1. Remover plano do usuário origem
_, err := r.collection.UpdateOne(
sessCtx,
bson.M{"_id": fromID},
bson.M{
"$pull": bson.M{"subscriptions": bson.M{"plan": plan}},
"$set": bson.M{"updated_at": time.Now()},
},
)
if err != nil {
return nil, fmt.Errorf("falha ao remover do origem: %w", err)
}
// 2. Adicionar plano ao usuário destino
_, err = r.collection.UpdateOne(
sessCtx,
bson.M{"_id": toID},
bson.M{
"$push": bson.M{"subscriptions": bson.M{
"plan": plan,
"transferred_at": time.Now(),
}},
"$set": bson.M{"updated_at": time.Now()},
},
)
if err != nil {
return nil, fmt.Errorf("falha ao adicionar ao destino: %w", err)
}
// 3. Registrar transferência (outra coleção)
transfers := r.collection.Database().Collection("transfers")
_, err = transfers.InsertOne(sessCtx, bson.M{
"from_user_id": fromID,
"to_user_id": toID,
"plan": plan,
"created_at": time.Now(),
})
if err != nil {
return nil, fmt.Errorf("falha ao registrar transferência: %w", err)
}
return nil, nil
}
// Executar transação
_, err = session.WithTransaction(ctx, callback)
if err != nil {
return fmt.Errorf("transação falhou: %w", err)
}
return nil
}
Boas Práticas
1. Context com Timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
user, err := repo.GetByID(ctx, id)
2. Connection Pool
clientOptions := options.Client().
SetMaxPoolSize(100).
SetMinPoolSize(10).
SetMaxConnIdleTime(30 * time.Second)
3. Tratamento de Erros
func mapMongoError(err error) error {
if err == nil {
return nil
}
if errors.Is(err, mongo.ErrNoDocuments) {
return ErrNotFound
}
if mongo.IsDuplicateKeyError(err) {
return ErrDuplicate
}
if mongo.IsTimeout(err) {
return ErrTimeout
}
return err
}
4. Paginação Eficiente
// Use cursor-based pagination para grandes datasets
func (r *userRepo) ListWithCursor(ctx context.Context, lastID string, limit int) ([]*models.User, string, error) {
filter := bson.M{}
if lastID != "" {
id, _ := primitive.ObjectIDFromHex(lastID)
filter["_id"] = bson.M{"$gt": id}
}
opts := options.Find().
SetLimit(int64(limit + 1)). // Buscar um extra para saber se há mais
SetSort(bson.M{"_id": 1})
cursor, err := r.collection.Find(ctx, filter, opts)
if err != nil {
return nil, "", err
}
defer cursor.Close(ctx)
var users []*models.User
if err := cursor.All(ctx, &users); err != nil {
return nil, "", err
}
var nextCursor string
if len(users) > limit {
nextCursor = users[limit].ID.Hex()
users = users[:limit]
}
return users, nextCursor, nil
}
5. Projeções para Performance
// Retornar apenas campos necessários
opts := options.Find().SetProjection(bson.M{
"password": 0, // Excluir
"metadata": 0, // Excluir
"name": 1, // Incluir
"email": 1, // Incluir
})
Checklist para Produção
- Índices criados para queries frequentes
- Connection pool configurado adequadamente
- Timeouts em todas as operações
- Transações para operações multi-documento
- Projeções para limitar dados transferidos
- Paginação para grandes datasets
- Replica Set configurado (não standalone)
- Autenticação habilitada
- TLS/SSL para conexões
- Backup automatizado
Próximos Passos
Aprofunde seus conhecimentos:
Go e PostgreSQL: CRUD Completo com Boas Práticas
Aprenda a integrar Go com PostgreSQL de forma profissional. Domine CRUD operations, transações, migrations, query builders e a ferramenta sqlc para type-safe SQL.
PostgreSQL é um dos bancos de dados relacionais mais robustos e populares do mundo. Combinado com Go, você tem uma stack poderosa para aplicações de alta performance. Neste guia, você aprenderá todas as técnicas essenciais para trabalhar com PostgreSQL em Go, desde operações básicas até padrões avançados de produção.
Por Que PostgreSQL com Go?
O Match Perfeito
┌─────────────────────────────────────────────────────────────────┐
│ POSTGRESQL │ GO │
├─────────────────────────────────────────────────────────────────┤
│ Confiável │ Type-safe, compilação rigorosa │
├─────────────────────────────────────────────────────────────────┤
│ ACID transactions │ Error handling explícito │
├─────────────────────────────────────────────────────────────────┤
│ Alto desempenho │ Runtime eficiente, baixa latência │
├─────────────────────────────────────────────────────────────────┤
│ Extensível │ Interfaces flexíveis │
├─────────────────────────────────────────────────────────────────┤
│ Open source │ Open source │
└─────────────────────────────────────────────────────────────────┘
Configuração do Projeto
Instalação das Dependências
# Driver padrão PostgreSQL
go get -u github.com/lib/pq
# Driver alternativo (mais performático)
go get -u github.com/jackc/pgx/v5
# sqlc - type-safe SQL
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
# Migration tool
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
Estrutura do Projeto
project/
├── cmd/
│ └── api/
│ └── main.go
├── internal/
│ ├── config/
│ │ └── database.go
│ ├── models/
│ │ └── user.go
│ ├── repository/
│ │ └── user_repository.go
│ └── service/
│ └── user_service.go
├── migrations/
│ ├── 001_create_users_table.up.sql
│ ├── 001_create_users_table.down.sql
│ └── ...
├── queries/
│ └── user.sql
├── sqlc.yaml
├── go.mod
└── .env
Conexão com PostgreSQL
Usando database/sql (Padrão)
// internal/config/database.go
package config
import (
"database/sql"
"fmt"
"log"
"os"
"time"
_ "github.com/lib/pq"
)
// Configurações do banco
type DBConfig struct {
Host string
Port int
User string
Password string
Database string
SSLMode string
}
func NewDBConfig() *DBConfig {
return &DBConfig{
Host: getEnv("DB_HOST", "localhost"),
Port: getEnvAsInt("DB_PORT", 5432),
User: getEnv("DB_USER", "postgres"),
Password: getEnv("DB_PASSWORD", "password"),
Database: getEnv("DB_NAME", "myapp"),
SSLMode: getEnv("DB_SSLMODE", "disable"),
}
}
func (c *DBConfig) ConnectionString() string {
return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
c.Host, c.Port, c.User, c.Password, c.Database, c.SSLMode)
}
// Conexão com pool
func NewDB(cfg *DBConfig) (*sql.DB, error) {
db, err := sql.Open("postgres", cfg.ConnectionString())
if err != nil {
return nil, fmt.Errorf("falha ao abrir conexão: %w", err)
}
// Configurar pool de conexões
db.SetMaxOpenConns(25) // Máximo de conexões abertas
db.SetMaxIdleConns(10) // Máximo de conexões idle
db.SetConnMaxLifetime(time.Hour) // Tempo máximo de vida
db.SetConnMaxIdleTime(30 * time.Minute)
// Verificar conexão
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil {
return nil, fmt.Errorf("falha ao ping banco de dados: %w", err)
}
log.Println("✅ Conectado ao PostgreSQL")
return db, nil
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
func getEnvAsInt(key string, defaultValue int) int {
if value := os.Getenv(key); value != "" {
var intValue int
fmt.Sscanf(value, "%d", &intValue)
return intValue
}
return defaultValue
}
Usando pgx (Recomendado)
// internal/config/pgx_database.go
package config
import (
"context"
"fmt"
"log"
"github.com/jackc/pgx/v5/pgxpool"
)
func NewPgxPool(cfg *DBConfig) (*pgxpool.Pool, error) {
connString := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=%s&pool_max_conns=25",
cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Database, cfg.SSLMode)
pool, err := pgxpool.New(context.Background(), connString)
if err != nil {
return nil, fmt.Errorf("falha ao criar pool: %w", err)
}
// Verificar conexão
if err := pool.Ping(context.Background()); err != nil {
return nil, fmt.Errorf("falha ao ping: %w", err)
}
log.Println("✅ Conectado ao PostgreSQL com pgx")
return pool, nil
}
Modelos e Estruturas
// internal/models/user.go
package models
import (
"time"
)
// User representa um usuário no banco
type User struct {
ID int64 `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
Password string `json:"-"` // Não serializar
Active bool `json:"active"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// UserCreate é usado para criar usuários
type UserCreate struct {
Email string `json:"email" validate:"required,email"`
Name string `json:"name" validate:"required,min=3,max=100"`
Password string `json:"password" validate:"required,min=8"`
}
// UserUpdate é usado para atualizar usuários
type UserUpdate struct {
Email *string `json:"email,omitempty"`
Name *string `json:"name,omitempty"`
Active *bool `json:"active,omitempty"`
}
// TableName retorna o nome da tabela
func (User) TableName() string {
return "users"
}
Operações CRUD
Repository Pattern
// internal/repository/user_repository.go
package repository
import (
"context"
"database/sql"
"errors"
"fmt"
"project/internal/models"
)
var (
ErrUserNotFound = errors.New("usuário não encontrado")
ErrEmailExists = errors.New("email já existe")
)
// UserRepository define operações de banco
type UserRepository interface {
Create(ctx context.Context, user *models.UserCreate) (*models.User, error)
GetByID(ctx context.Context, id int64) (*models.User, error)
GetByEmail(ctx context.Context, email string) (*models.User, error)
List(ctx context.Context, limit, offset int) ([]*models.User, error)
Update(ctx context.Context, id int64, update *models.UserUpdate) (*models.User, error)
Delete(ctx context.Context, id int64) error
Count(ctx context.Context) (int64, error)
}
// userRepo implementa UserRepository
type userRepo struct {
db *sql.DB
}
// NewUserRepository cria nova instância
func NewUserRepository(db *sql.DB) UserRepository {
return &userRepo{db: db}
}
CREATE
// Create insere novo usuário
func (r *userRepo) Create(ctx context.Context, user *models.UserCreate) (*models.User, error) {
query := `
INSERT INTO users (email, name, password, active, created_at, updated_at)
VALUES ($1, $2, $3, $4, NOW(), NOW())
RETURNING id, email, name, active, created_at, updated_at
`
// Em produção, faça hash da senha!
hashedPassword := hashPassword(user.Password)
var created models.User
err := r.db.QueryRowContext(ctx, query,
user.Email,
user.Name,
hashedPassword,
true,
).Scan(
&created.ID,
&created.Email,
&created.Name,
&created.Active,
&created.CreatedAt,
&created.UpdatedAt,
)
if err != nil {
// Verificar erro de duplicação
if isDuplicateKeyError(err) {
return nil, ErrEmailExists
}
return nil, fmt.Errorf("falha ao criar usuário: %w", err)
}
return &created, nil
}
func hashPassword(password string) string {
// Use bcrypt em produção!
// import "golang.org/x/crypto/bcrypt"
// hashed, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
// return string(hashed)
return "hashed_" + password
}
func isDuplicateKeyError(err error) bool {
if err == nil {
return false
}
// Verificar código de erro PostgreSQL para duplicação
return strings.Contains(err.Error(), "duplicate key")
}
READ
// GetByID busca usuário por ID
func (r *userRepo) GetByID(ctx context.Context, id int64) (*models.User, error) {
query := `
SELECT id, email, name, active, created_at, updated_at
FROM users
WHERE id = $1
`
var user models.User
err := r.db.QueryRowContext(ctx, query, id).Scan(
&user.ID,
&user.Email,
&user.Name,
&user.Active,
&user.CreatedAt,
&user.UpdatedAt,
)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrUserNotFound
}
return nil, fmt.Errorf("falha ao buscar usuário: %w", err)
}
return &user, nil
}
// GetByEmail busca usuário por email
func (r *userRepo) GetByEmail(ctx context.Context, email string) (*models.User, error) {
query := `
SELECT id, email, name, active, created_at, updated_at
FROM users
WHERE email = $1
`
var user models.User
err := r.db.QueryRowContext(ctx, query, email).Scan(
&user.ID,
&user.Email,
&user.Name,
&user.Active,
&user.CreatedAt,
&user.UpdatedAt,
)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrUserNotFound
}
return nil, fmt.Errorf("falha ao buscar usuário: %w", err)
}
return &user, nil
}
// List retorna lista paginada de usuários
func (r *userRepo) List(ctx context.Context, limit, offset int) ([]*models.User, error) {
query := `
SELECT id, email, name, active, created_at, updated_at
FROM users
ORDER BY created_at DESC
LIMIT $1 OFFSET $2
`
if limit <= 0 {
limit = 10
}
if limit > 100 {
limit = 100 // Máximo por página
}
rows, err := r.db.QueryContext(ctx, query, limit, offset)
if err != nil {
return nil, fmt.Errorf("falha ao listar usuários: %w", err)
}
defer rows.Close()
var users []*models.User
for rows.Next() {
var user models.User
err := rows.Scan(
&user.ID,
&user.Email,
&user.Name,
&user.Active,
&user.CreatedAt,
&user.UpdatedAt,
)
if err != nil {
return nil, fmt.Errorf("falha ao scan usuário: %w", err)
}
users = append(users, &user)
}
if err = rows.Err(); err != nil {
return nil, fmt.Errorf("erro ao iterar rows: %w", err)
}
return users, nil
}
// Count retorna total de usuários
func (r *userRepo) Count(ctx context.Context) (int64, error) {
query := `SELECT COUNT(*) FROM users`
var count int64
err := r.db.QueryRowContext(ctx, query).Scan(&count)
if err != nil {
return 0, fmt.Errorf("falha ao contar usuários: %w", err)
}
return count, nil
}
UPDATE
// Update atualiza usuário
func (r *userRepo) Update(ctx context.Context, id int64, update *models.UserUpdate) (*models.User, error) {
// Construir query dinamicamente
var setParts []string
var args []interface{}
argIndex := 1
if update.Email != nil {
setParts = append(setParts, fmt.Sprintf("email = $%d", argIndex))
args = append(args, *update.Email)
argIndex++
}
if update.Name != nil {
setParts = append(setParts, fmt.Sprintf("name = $%d", argIndex))
args = append(args, *update.Name)
argIndex++
}
if update.Active != nil {
setParts = append(setParts, fmt.Sprintf("active = $%d", argIndex))
args = append(args, *update.Active)
argIndex++
}
if len(setParts) == 0 {
return nil, errors.New("nenhum campo para atualizar")
}
// Sempre atualizar updated_at
setParts = append(setParts, fmt.Sprintf("updated_at = $%d", argIndex))
args = append(args, time.Now())
argIndex++
// Adicionar ID
args = append(args, id)
query := fmt.Sprintf(`
UPDATE users
SET %s
WHERE id = $%d
RETURNING id, email, name, active, created_at, updated_at
`, strings.Join(setParts, ", "), argIndex)
var user models.User
err := r.db.QueryRowContext(ctx, query, args...).Scan(
&user.ID,
&user.Email,
&user.Name,
&user.Active,
&user.CreatedAt,
&user.UpdatedAt,
)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrUserNotFound
}
if isDuplicateKeyError(err) {
return nil, ErrEmailExists
}
return nil, fmt.Errorf("falha ao atualizar usuário: %w", err)
}
return &user, nil
}
DELETE
// Delete remove usuário
func (r *userRepo) Delete(ctx context.Context, id int64) error {
query := `DELETE FROM users WHERE id = $1`
result, err := r.db.ExecContext(ctx, query, id)
if err != nil {
return fmt.Errorf("falha ao deletar usuário: %w", err)
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("falha ao obter rows afetadas: %w", err)
}
if rowsAffected == 0 {
return ErrUserNotFound
}
return nil
}
// SoftDelete (alternativa ao delete físico)
func (r *userRepo) SoftDelete(ctx context.Context, id int64) error {
query := `
UPDATE users
SET active = false, deleted_at = NOW()
WHERE id = $1
`
result, err := r.db.ExecContext(ctx, query, id)
if err != nil {
return fmt.Errorf("falha ao deletar usuário: %w", err)
}
rowsAffected, _ := result.RowsAffected()
if rowsAffected == 0 {
return ErrUserNotFound
}
return nil
}
Transações
// WithTransaction executa função dentro de transação
func (r *userRepo) WithTransaction(ctx context.Context, fn func(*sql.Tx) error) error {
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("falha ao iniciar transação: %w", err)
}
defer func() {
if p := recover(); p != nil {
tx.Rollback()
panic(p)
}
}()
if err := fn(tx); err != nil {
tx.Rollback()
return err
}
if err := tx.Commit(); err != nil {
return fmt.Errorf("falha ao commit: %w", err)
}
return nil
}
// TransferBalance exemplo de transação
func TransferBalance(ctx context.Context, db *sql.DB, fromID, toID int64, amount float64) error {
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer tx.Rollback()
// Verificar saldo
var balance float64
err = tx.QueryRowContext(ctx,
"SELECT balance FROM accounts WHERE id = $1 FOR UPDATE",
fromID,
).Scan(&balance)
if err != nil {
return err
}
if balance < amount {
return errors.New("saldo insuficiente")
}
// Debitar
_, err = tx.ExecContext(ctx,
"UPDATE accounts SET balance = balance - $1 WHERE id = $2",
amount, fromID,
)
if err != nil {
return err
}
// Creditar
_, err = tx.ExecContext(ctx,
"UPDATE accounts SET balance = balance + $1 WHERE id = $2",
amount, toID,
)
if err != nil {
return err
}
// Registrar transação
_, err = tx.ExecContext(ctx,
`INSERT INTO transactions (from_id, to_id, amount, created_at)
VALUES ($1, $2, $3, NOW())`,
fromID, toID, amount,
)
if err != nil {
return err
}
return tx.Commit()
}
sqlc: Type-Safe SQL
Configuração
# sqlc.yaml
version: "2"
sql:
- schema: "migrations/"
queries: "queries/"
engine: "postgresql"
gen:
go:
package: "db"
out: "internal/db"
sql_package: "pgx/v5"
emit_json_tags: true
emit_prepared_queries: true
emit_interface: true
emit_empty_slices: true
Queries SQL
-- queries/user.sql
-- name: CreateUser :one
INSERT INTO users (email, name, password, active)
VALUES ($1, $2, $3, $4)
RETURNING *;
-- name: GetUser :one
SELECT * FROM users
WHERE id = $1;
-- name: GetUserByEmail :one
SELECT * FROM users
WHERE email = $1;
-- name: ListUsers :many
SELECT * FROM users
ORDER BY created_at DESC
LIMIT $1 OFFSET $2;
-- name: UpdateUser :one
UPDATE users
SET email = COALESCE($2, email),
name = COALESCE($3, name),
active = COALESCE($4, active),
updated_at = NOW()
WHERE id = $1
RETURNING *;
-- name: DeleteUser :exec
DELETE FROM users WHERE id = $1;
-- name: CountUsers :one
SELECT COUNT(*) FROM users;
Gerar Código
# Gerar código Go a partir das queries
sqlc generate
# Estrutura gerada:
# internal/db/
# ├── db.go
# ├── models.go
# ├── querier.go (interface)
# └── user.sql.go
Uso do sqlc
// internal/repository/user_sqlc.go
package repository
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
"project/internal/db"
)
type UserSQLCRepository struct {
queries *db.Queries
}
func NewUserSQLCRepository(queries *db.Queries) *UserSQLCRepository {
return &UserSQLCRepository{queries: queries}
}
func (r *UserSQLCRepository) Create(ctx context.Context, email, name, password string) (*db.User, error) {
user, err := r.queries.CreateUser(ctx, db.CreateUserParams{
Email: email,
Name: name,
Password: password,
Active: true,
})
if err != nil {
return nil, err
}
return &user, nil
}
func (r *UserSQLCRepository) List(ctx context.Context, limit, offset int32) ([]db.User, error) {
return r.queries.ListUsers(ctx, db.ListUsersParams{
Limit: limit,
Offset: offset,
})
}
func (r *UserSQLCRepository) Update(ctx context.Context, id int64, email, name *string, active *bool) (*db.User, error) {
var emailParam, nameParam pgtype.Text
var activeParam pgtype.Bool
if email != nil {
emailParam = pgtype.Text{String: *email, Valid: true}
}
if name != nil {
nameParam = pgtype.Text{String: *name, Valid: true}
}
if active != nil {
activeParam = pgtype.Bool{Bool: *active, Valid: true}
}
user, err := r.queries.UpdateUser(ctx, db.UpdateUserParams{
ID: id,
Email: emailParam,
Name: nameParam,
Active: activeParam,
})
if err != nil {
return nil, err
}
return &user, nil
}
Migrations
Usando golang-migrate
# Criar nova migration
migrate create -ext sql -dir migrations -seq create_users_table
# Aplicar migrations
migrate -path migrations -database "postgres://user:pass@localhost/db?sslmode=disable" up
# Reverter última migration
migrate -path migrations -database "postgres://user:pass@localhost/db?sslmode=disable" down 1
Migration Files
-- migrations/001_create_users_table.up.sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
password VARCHAR(255) NOT NULL,
active BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
deleted_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_active ON users(active);
-- Trigger para atualizar updated_at
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
CREATE TRIGGER update_users_updated_at
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
-- migrations/001_create_users_table.down.sql
DROP TRIGGER IF EXISTS update_users_updated_at ON users;
DROP FUNCTION IF EXISTS update_updated_at_column();
DROP INDEX IF EXISTS idx_users_active;
DROP INDEX IF EXISTS idx_users_email;
DROP TABLE IF EXISTS users;
Boas Práticas
1. Context para Timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
user, err := repo.GetByID(ctx, id)
2. Prepared Statements
// database/sql já usa prepared statements internamente
// Para queries repetidas, use Prepare
stmt, err := db.PrepareContext(ctx, "SELECT * FROM users WHERE id = $1")
if err != nil {
return err
}
defer stmt.Close()
for _, id := range ids {
row := stmt.QueryRowContext(ctx, id)
// ...
}
3. Connection Pool
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(time.Hour)
4. Error Handling
var (
ErrNotFound = errors.New("recurso não encontrado")
ErrDuplicate = errors.New("recurso já existe")
ErrConstraint = errors.New("violação de constraint")
)
func mapError(err error) error {
if err == nil {
return nil
}
if errors.Is(err, sql.ErrNoRows) {
return ErrNotFound
}
pqErr, ok := err.(*pq.Error)
if ok {
switch pqErr.Code {
case "23505": // unique_violation
return ErrDuplicate
case "23503": // foreign_key_violation
return ErrConstraint
}
}
return err
}
5. Logging
// Log queries em desenvolvimento
func logQuery(query string, args ...interface{}) {
if os.Getenv("ENV") == "development" {
log.Printf("[SQL] %s | Args: %v", query, args)
}
}
Checklist para Produção
- Connection pool configurado corretamente
- Timeouts em todas as queries (context)
- Migrations automatizadas no deploy
- Prepared statements para queries frequentes
- Índices otimizados
- Hash de senhas (bcrypt/argon2)
- Soft delete para dados importantes
- Auditoria (created_at, updated_at)
- SSL para conexões (sslmode=require)
- Backup automatizado
Próximos Passos
Aprofunde seus conhecimentos:
Go Observability: Logs, Métricas e Traces - Guia Completo
Aprenda observabilidade em Go com logging estruturado, métricas Prometheus, distributed tracing e OpenTelemetry. Tutorial completo para monitorar aplicações Go em produção.
Observabilidade é essencial para aplicações em produção. Este guia completo mostra como implementar logging estruturado, métricas, traces e alerting em Go usando as melhores práticas e ferramentas modernas.
Pilares da Observabilidade
┌─────────────────────────────────────────────────────────┐
│ OBSERVABILITY │
├─────────────┬─────────────┬─────────────────────────────┤
│ LOGS │ METRICS │ TRACES │
│ │ │ │
│ O que │ Quanto/ │ Onde/O │
│ aconteceu │ Quando │ quando │
│ │ │ │
│ Eventos │ Números │ Request flow │
│ detalhados │ agregados │ distribuído │
└─────────────┴─────────────┴─────────────────────────────┘
1. Structured Logging
Logging estruturado é fundamental para debug e análise de incidentes.
Go Performance: Profiling e Otimização de Alto Desempenho
Domine profiling e otimização em Go. Aprenda a usar pprof para CPU e memory profiling, escrever benchmarks com testing.B, identificar gargalos e aplicar estratégias avançadas de otimização. Guia completo com casos reais.
Performance é diferencial competitivo. Enquanto concorrentes lutam com latência, aplicações Go otimizadas processam milhões de requisições por segundo. Neste guia completo, você vai dominar as ferramentas e técnicas usadas por engenheiros da Google, Netflix e Uber para criar sistemas de alto desempenho.
Por Que Performance Importa em Go?
O Custo da Lentidão
| Métrica | Impacto no Negócio |
|---|---|
| +100ms de latência | -1% de conversão (Amazon) |
| +500ms de latência | -20% de tráfego (Google) |
| +1s de latência | -11% pageviews (Bing) |
| 3s de carga | 53% abandonam mobile |
Em Go, cada microssegundo conta. Um serviço que processa 10M requests/dia economiza 2.7 horas de CPU por dia com apenas 1ms de otimização por request.
Go Testing: TDD e Integração Contínua - Guia Completo
Aprenda Test-Driven Development (TDD) e CI/CD para Go. Tutorial completo com GitHub Actions, testes automatizados, pipelines e deploy contínuo para projetos Go profissionais.
Test-Driven Development (TDD) e Integração Contínua (CI/CD) são práticas essenciais para desenvolvimento de software profissional. Este guia completo mostra como implementar TDD e pipelines de CI/CD em projetos Go, desde testes unitários até deploy automatizado.
Por Que TDD + CI/CD em Go?
Go é ideal para TDD e CI/CD porque:
- Testes rápidos — Compilação e execução em segundos
- Binário único — Deploy simplificado
- Biblioteca padrão robusta — Sem dependências complexas
- Cross-compilation nativa — Build para múltiplas plataformas
Fundamentos de TDD
O Ciclo Red-Green-Refactor
┌─────────┐ ┌─────────┐ ┌─────────┐
│ RED │ → │ GREEN │ → │ REFACTOR│
│ (Falha)│ │ (Passa) │ │(Melhora)│
└─────────┘ └─────────┘ └─────────┘
↑ │
└──────────────────────────────┘
Exemplo Prático: Calculadora com TDD
Passo 1: Escreva o teste (RED)
Go 1.26 Chegou: Novidades e Melhorias que Você Precisa Conhecer!
Go 1.26 traz Green Tea GC como padrao, go fix para modernizar codigo automaticamente, melhorias no linker e novas APIs. Resumo completo em portugues.
A equipe Go tem o prazer de anunciar o lançamento do Go 1.26, uma versão que traz refinamentos na linguagem, ganhos de performance significativos e melhorias nas ferramentas. Este resumo detalha as principais mudanças e adições, oferecendo uma visão geral do que esperar desta nova versão.
Mudanças na Linguagem
O Go 1.26 introduz duas mudanças notáveis na sintaxe e no sistema de tipos:
Inicialização Simplificada com
new: A função built-innewagora aceita uma expressão como operando, permitindo especificar o valor inicial da variável criada. Isso simplifica o código, eliminando a necessidade de declarar a variável e depois atribuir um valor a ela.
Go Clean Architecture: Organizando Projetos Escaláveis
Domine a Clean Architecture em Go. Aprenda a organizar projetos com ports e adapters, dependency injection, repository pattern e testes eficientes. Estrutura profissional para aplicações Go.
Clean Architecture (Arquitetura Limpa) é o padrão usado por empresas como Netflix, Uber e Google para construir sistemas escaláveis e testáveis. Em Go, ela brilha pela simplicidade que combina com a filosofia da linguagem. Neste guia, você vai aprender a organizar projetos Go profissionais.
Por Que Clean Architecture em Go?
Os Problemas Sem Arquitetura
📁 projeto-caotico/
├── main.go # 2000 linhas
├── handlers.go # Tudo misturado
├── database.go # SQL espalhado
├── models.go # Regras de negócio aqui
└── utils.go # Deus sabe o que tem aqui
Problemas:
Go Concurrency Patterns: Goroutines e Channels Avançados
Aprenda patterns avançados de concorrência em Go: worker pools, fan-out/fan-in, rate limiting com channels, e context package. Tutorial completo com exemplos práticos de código.
A concorrência é um dos recursos mais poderosos de Go. Enquanto muitas linguagens tratam concorrência como um recurso avançado complexo, Go a torna acessível através de goroutines e channels. Este tutorial explora patterns avançados que você encontrará em aplicações Go de produção.
Pré-requisitos: Conhecimento básico de Go (variáveis, funções, structs) e familiaridade com goroutines e channels. Se você é novo em Go, confira nosso guia para iniciantes.
Sumário dos Patterns
| Pattern | Use Case | Complexidade |
|---|---|---|
| Worker Pool | Processar tarefas em paralelo com controle | Intermediario |
| Fan-Out/Fan-In | Distribuir trabalho e agregar resultados | Avancado |
| Pipeline | Processar dados em estágios sequenciais | Intermediario |
| Rate Limiting | Controlar throughput de requisições | Avancado |
| Context Cancellation | Cancelar operações de forma segura | Intermediario |
| Select Statement | Multiplexar channels | Avancado |
1. Worker Pool Pattern
O pattern Worker Pool é essencial quando você precisa processar um grande número de tarefas de forma concorrente, mas quer limitar o número de goroutines simultâneas.
Go para APIs REST: Guia Completo de Desenvolvimento Web
Aprenda a criar APIs REST robustas em Go. Tutorial completo cobrindo rotas, JSON, middleware, autenticação, banco de dados e deploy. Exemplos práticos incluídos.
Go é uma das melhores linguagens para desenvolvimento de APIs REST. Com sua performance nativa, concorrência eficiente via goroutines e biblioteca padrão robusta, Go permite criar serviços web escaláveis e de alta performance. Neste guia completo, vamos construir uma API REST do zero, cobrindo desde conceitos básicos até padrões avançados usados em produção.
Por Que Go para APIs REST?
Vantagens de Go para Backend
┌─────────────────────────────────────────────────────────┐
│ PERFORMANCE │ Goroutines leves (2KB stack) │
├─────────────────────────────────────────────────────────┤
│ CONFIABILIDADE │ Tipagem forte, erro explícito │
├─────────────────────────────────────────────────────────┤
│ PRODUTIVIDADE │ Compilação rápida, stdlib rica │
├─────────────────────────────────────────────────────────┤
│ DEPLOY │ Binário único, cross-compile │
├─────────────────────────────────────────────────────────┤
│ ECOSISTEMA │ Gin, Echo, Chi, Fiber │
└─────────────────────────────────────────────────────────┘
Empresas usando Go em produção:
Go para Microserviços: Arquitetura e Práticas de Produção
Domine a arquitetura de microserviços em Go. Aprenda padrões de comunicação, service discovery, circuit breakers, distributed tracing e estratégias de deploy com exemplos práticos.
Microserviços transformaram a forma como desenvolvemos sistemas escaláveis. Go é a linguagem preferida para microserviços em empresas como Netflix, Uber, e Kubernetes. Neste guia completo, você aprenderá a arquitetar, construir e operar microserviços robustos em Go.
Por Que Go é Perfeito para Microserviços
O Match Perfeito
┌─────────────────────────────────────────────────────────────────┐
│ MICROSERVIÇO │ GO │
├─────────────────────────────────────────────────────────────────┤
│ Leve e rápido │ Binário único, startup < 100ms │
├─────────────────────────────────────────────────────────────────┤
│ Escalável │ Goroutines (milhões simultâneas) │
├─────────────────────────────────────────────────────────────────┤
│ Confiável │ Tipagem forte, sem runtime pesado │
├─────────────────────────────────────────────────────────────────┤
│ Eficiente │ Memória mínima (10-50MB por serviço) │
├─────────────────────────────────────────────────────────────────┤
│ Portátil │ Cross-compile, Docker nativo │
├─────────────────────────────────────────────────────────────────┤
│ Simples │ Código explícito, fácil manutenção │
└─────────────────────────────────────────────────────────────────┘
Comparação com Outras Linguagens
| Aspecto | Go | Java | Node.js | Python |
|---|---|---|---|---|
| Startup | ~50ms | ~5s | ~2s | ~1s |
| Memória | 10-50MB | 200-500MB | 100-300MB | 150-400MB |
| Concorrência | Nativa | Threads pesadas | Callbacks | GIL limita |
| Binário | Único | JVM necessária | Node runtime | Interpreter |
| Performance | Nativa | Boa (JIT) | Média | Lenta |
Arquitetura de um Microserviço Go
Estrutura de Projeto Recomendada
order-service/
├── cmd/
│ └── api/
│ └── main.go # Entry point
├── internal/
│ ├── domain/
│ │ ├── order.go # Entidades
│ │ └── errors.go # Erros de domínio
│ ├── application/
│ │ ├── service.go # Lógica de negócio
│ │ └── dto.go # Data Transfer Objects
│ ├── infrastructure/
│ │ ├── http/
│ │ │ ├── handler.go # HTTP handlers
│ │ │ ├── router.go # Configuração de rotas
│ │ │ └── middleware.go # Middlewares
│ │ ├── persistence/
│ │ │ ├── postgres.go # Implementação do repo
│ │ │ └── redis.go # Cache
│ │ └── messaging/
│ │ └── kafka.go # Event publisher
│ └── config/
│ └── config.go # Configurações
├── pkg/
│ └── logger/ # Shared packages
├── api/
│ └── proto/ # Protocol Buffers
├── deployments/
│ ├── docker/
│ └── k8s/
├── go.mod
└── Makefile
Implementação Completa
// internal/domain/order.go
package domain
import (
"errors"
"time"
)
var (
ErrInvalidAmount = errors.New("valor do pedido inválido")
ErrOrderNotFound = errors.New("pedido não encontrado")
)
type Order struct {
ID string `json:"id"`
UserID string `json:"user_id"`
Items []Item `json:"items"`
Total float64 `json:"total"`
Status Status `json:"status"`
CreatedAt time.Time `json:"created_at"`
}
type Item struct {
ProductID string `json:"product_id"`
Quantity int `json:"quantity"`
Price float64 `json:"price"`
}
type Status string
const (
StatusPending Status = "PENDING"
StatusPaid Status = "PAID"
StatusShipped Status = "SHIPPED"
StatusDelivered Status = "DELIVERED"
)
func (o *Order) CalculateTotal() {
var total float64
for _, item := range o.Items {
total += item.Price * float64(item.Quantity)
}
o.Total = total
}
func (o *Order) Validate() error {
if o.Total <= 0 {
return ErrInvalidAmount
}
return nil
}
// internal/application/service.go
package application
import (
"context"
"fmt"
"time"
"order-service/internal/domain"
)
// Portas (interfaces) para dependências
type OrderRepository interface {
Save(ctx context.Context, order *domain.Order) error
GetByID(ctx context.Context, id string) (*domain.Order, error)
Update(ctx context.Context, order *domain.Order) error
}
type PaymentService interface {
Process(ctx context.Context, orderID string, amount float64) error
}
type EventPublisher interface {
PublishOrderCreated(ctx context.Context, order *domain.Order) error
}
type OrderService struct {
repo OrderRepository
payment PaymentService
publisher EventPublisher
}
func NewOrderService(
repo OrderRepository,
payment PaymentService,
publisher EventPublisher,
) *OrderService {
return &OrderService{
repo: repo,
payment: payment,
publisher: publisher,
}
}
func (s *OrderService) CreateOrder(ctx context.Context, userID string, items []domain.Item) (*domain.Order, error) {
order := &domain.Order{
ID: generateID(),
UserID: userID,
Items: items,
Status: domain.StatusPending,
CreatedAt: time.Now(),
}
order.CalculateTotal()
if err := order.Validate(); err != nil {
return nil, err
}
// Salvar no banco
if err := s.repo.Save(ctx, order); err != nil {
return nil, fmt.Errorf("falha ao salvar pedido: %w", err)
}
// Publicar evento assíncrono
go func() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
s.publisher.PublishOrderCreated(ctx, order)
}()
return order, nil
}
func (s *OrderService) ProcessPayment(ctx context.Context, orderID string) error {
order, err := s.repo.GetByID(ctx, orderID)
if err != nil {
return err
}
if err := s.payment.Process(ctx, orderID, order.Total); err != nil {
return fmt.Errorf("pagamento falhou: %w", err)
}
order.Status = domain.StatusPaid
return s.repo.Update(ctx, order)
}
func generateID() string {
return fmt.Sprintf("ORD-%d", time.Now().UnixNano())
}
Padrões de Comunicação
1. Síncrono: HTTP REST
Já coberto no guia de APIs REST. Para microserviços, adicione:
Go Testing: TDD e Benchmarks - Guia Completo
Aprenda testes em Go com TDD, testes unitários, mock, benchmarks e coverage. Tutorial completo com exemplos práticos para testar aplicações Go profissionalmente.
Testar código é essencial para garantir qualidade, confiança e manutenibilidade de software. Go possui uma biblioteca de testes robusta e bem integrada na linguagem. Neste guia completo, vamos explorar desde testes unitários básicos até TDD, mocks, benchmarks e testes de integração.
Por Que Testar em Go?
Go torna testes simples com:
- Package
testingembutido - sem dependências externas - Testes compilados - rápidos e eficientes
- Coverage nativo -
go test -cover - Benchmarks - testes de performance integrados
- Paralelismo -
t.Parallel()para testes concorrentes
Testes Unitários Básicos
Arquivos de teste terminam com _test.go:
Concorrência em Go: Goroutines e Channels - Guia Completo
Domine concorrência em Go. Tutorial completo sobre goroutines, channels, select, sync e padrões de concorrência. Exemplos práticos para iniciantes.
A concorrência é uma das features mais poderosas e distintivas de Go. Enquanto outras linguagens tornam a programação paralela complexa e cheia de boilerplate, Go a torna simples e elegante com goroutines e channels.
Neste quarto artigo da série “Golang para Iniciantes”, vamos desvendar os segredos da concorrência em Go. Você aprenderá a executar múltiplas tarefas simultaneamente de forma segura e eficiente.
Se você está chegando agora:
Controle de Fluxo em Go: if, switch, loops - Tutorial Completo
Aprenda controle de fluxo em Go. Tutorial completo sobre if/else, switch, for loops, range e controle de execução. Exemplos práticos para iniciantes.
Neste terceiro artigo da série “Golang para Iniciantes”, vamos explorar as estruturas de controle de fluxo em Go. Você aprenderá a tomar decisões com if/else, selecionar entre múltiplas opções com switch, e repetir operações com loops for.
Se você está chegando agora, recomendamos começar pela introdução:
📖 ← Artigo Anterior: Sintaxe Básica de Go
If e Else
Go tem uma sintaxe de condicionais limpa e direta.
If Básico
package main
import "fmt"
func main() {
idade := 18
if idade >= 18 {
fmt.Println("Maior de idade")
}
}
If-Else
package main
import "fmt"
func main() {
nota := 7.5
if nota >= 7.0 {
fmt.Println("Aprovado!")
} else if nota >= 5.0 {
fmt.Println("Recuperação")
} else {
fmt.Println("Reprovado")
}
}
If com Inicialização
Uma característica única de Go: você pode inicializar variáveis no if:
Criando sua Primeira API REST em Go: Tutorial Completo Passo a Passo
Construa uma API REST completa em Go. Tutorial prático com HTTP handlers, JSON, routing, middleware e banco de dados. Do zero à produção.
Neste quinto e último artigo da série “Golang para Iniciantes”, vamos aplicar tudo o que aprendemos para construir uma API REST completa do zero. Você criará um servidor web funcional com rotas, handlers, JSON, persistência em memória e testes.
Se você está chegando agora, recomendamos revisar os artigos anteriores:
📖 ← Série Completa: Golang para Iniciantes
O Que Vamos Construir
Vamos criar uma API de Gerenciamento de Tarefas (Todo API) com as seguintes funcionalidades:
Golang para Iniciantes: Primeiros Passos - Guia Completo 2026
Aprenda Go do zero. Tutorial completo de instalação, configuração do ambiente e primeiro programa. Guia passo a passo para iniciantes em Golang.
Go (ou Golang) é uma das linguagens de programação mais populares para desenvolvimento backend, microserviços e ferramentas de infraestrutura. Criada pelo Google em 2009, ela combina simplicidade, performance e produtividade de uma forma única.
Se você está começando sua jornada em Go, este é o lugar certo. Neste primeiro artigo da série “Golang para Iniciantes”, vamos cobrir tudo o que você precisa para dar os primeiros passos: desde a instalação até escrever seu primeiro programa funcional.
Sintaxe Básica de Go: Variáveis, Tipos e Funções - Tutorial Completo
Aprenda a sintaxe de Go na prática: variáveis com :=, 15 tipos de dados, funções com múltiplos retornos, structs e métodos. Exemplos que você pode copiar e rodar.
Neste segundo artigo da série “Golang para Iniciantes”, vamos mergulhar nos fundamentos da linguagem. Você aprenderá tudo sobre variáveis, tipos de dados, funções, structs e métodos — os blocos de construção essenciais de qualquer programa Go.
Se você ainda não leu o primeiro artigo, recomendamos começar por lá:
📖 ← Artigo Anterior: Golang para Iniciantes: Primeiros Passos
Variáveis em Go
Go oferece várias formas de declarar variáveis, desde a forma explícita até a inferência de tipos.
Go em 2025: Um Retrato da Satisfação, Desafios e o Crescente Papel da IA
Resultados da pesquisa Go 2025 com 5.379 devs: 93% satisfeitos, IA em alta, desafios com error handling e documentacao. Veja os dados completos.
O artigo apresenta os resultados da pesquisa de 2025 com desenvolvedores Go, revelando insights importantes sobre o estado da linguagem, seus desafios e a crescente adoção de ferramentas de IA. A pesquisa, que contou com a participação de 5.379 desenvolvedores, destaca a alta satisfação com Go, a necessidade de melhores práticas e documentação, e o impacto da IA no desenvolvimento.
Demografia dos Respondentes
A maioria dos participantes se identificou como desenvolvedores profissionais (87%) que usam Go em seus trabalhos principais (82%). Uma grande parcela também utiliza Go em projetos pessoais ou open-source (72%). A faixa etária predominante é entre 25 e 45 anos (68%), com pelo menos seis anos de experiência profissional em desenvolvimento (75%). Um dado interessante é que 81% dos respondentes possuem mais experiência profissional em desenvolvimento do que experiência específica com Go, o que sugere que Go geralmente não é a primeira linguagem que aprendem. Isso cria um atrito quando a forma de realizar uma tarefa em Go é muito diferente de linguagens mais familiares, forçando os desenvolvedores a aprenderem e lembrarem de padrões idiomáticos específicos de Go.
Go Chega à Maioridade: 16 Anos de Inovação e Amadurecimento
Go completa 16 anos com generics maduros, Green Tea GC, FIPS 140-3 nativo e GOMAXPROCS container-aware. Retrospectiva das versoes 1.24 e 1.25.
O artigo do blog oficial do Go celebra o 16º aniversário do lançamento do Go como projeto de código aberto, destacando as principais novidades e avanços implementados nas versões Go 1.24 e Go 1.25, além de vislumbrar o futuro da linguagem no contexto da inteligência artificial generativa. O texto aborda melhorias no núcleo da linguagem e nas bibliotecas padrão, avanços na segurança do software, otimizações internas e o aprimoramento do ecossistema de ferramentas de desenvolvimento.
Go 1.25 e o Coletor de Lixo "Chá Verde": Uma Nova Abordagem para Performance
O Green Tea GC do Go 1.25 reduz ate 40% do tempo de garbage collection. Saiba como ativar com GOEXPERIMENT=greenteagc e os resultados em producao no Google.
O Go 1.25 introduziu um novo coletor de lixo (garbage collector - GC) experimental, apelidado de “Green Tea” (Chá Verde), que promete melhorias significativas na performance de diversas aplicações. Ativado através da flag GOEXPERIMENT=greenteagc durante a compilação, o Green Tea GC já demonstra reduções de até 40% no tempo gasto com coleta de lixo em alguns cenários, com uma média de 10% de melhora. O coletor já está em uso no Google, o que indica sua prontidão para produção. A equipe Go incentiva a comunidade a testá-lo e reportar resultados, positivos ou negativos, para ajudar a aprimorar a implementação. A expectativa é que o Green Tea se torne o coletor de lixo padrão no Go 1.26.
Desvendando Gargalos com o Gravador de Voo do Go: Diagnóstico Preciso de Problemas de Performance
Flight Recorder no Go 1.25: capture traces de execucao seletivos para diagnosticar gargalos de performance em servidores Go de longa duracao.
O artigo do blog oficial do Go introduz o “gravador de voo” (flight recorder), uma nova ferramenta de diagnóstico disponível a partir do Go 1.25, que permite capturar traces de execução (execution traces) de forma seletiva, focando em momentos críticos do programa. Ele complementa os execution traces já existentes, oferecendo uma abordagem mais direcionada para identificar e resolver problemas de performance em aplicações Go de longa duração, como servidores web.
Sua Voz Molda o Futuro do Go: Participe da Pesquisa Anual de Desenvolvedores!
Pesquisa anual Go 2025: compartilhe suas experiencias e ajude a moldar o futuro da linguagem Go. Participe da survey oficial do Go Team.
O Go Team convida a comunidade global de desenvolvedores Go a participar da pesquisa anual de desenvolvedores Go de 2025. Esta pesquisa é uma oportunidade crucial para os desenvolvedores compartilharem suas experiências, necessidades e preocupações com a linguagem Go, ajudando a equipe Go a priorizar e planejar o futuro da linguagem.
A Importância da Sua Participação
A pesquisa anual de desenvolvedores Go é uma ferramenta fundamental para a equipe Go entender como a linguagem está sendo usada no mundo real e quais áreas precisam de melhorias. Os resultados da pesquisa influenciam diretamente as decisões sobre o desenvolvimento futuro da linguagem, incluindo novos recursos, otimizações e melhorias na documentação e nas ferramentas.
Go JSON Evolui: Uma Nova API Experimental para o Futuro
Nova API experimental encoding/json/v2 em Go resolve problemas de 15 anos do pacote JSON original. Conheça as melhorias de comportamento, API e performance.
O artigo do blog oficial do Go anuncia o lançamento de uma nova API experimental para JSON, presente nos pacotes encoding/json/v2 e encoding/json/jsontext, com o objetivo de abordar as limitações e problemas existentes no pacote encoding/json (denominado v1 neste contexto). Após quase 15 anos desde a introdução do suporte a JSON em Go, e com o JSON se tornando o formato de dados mais popular na internet, a equipe de desenvolvimento do Go reconheceu a necessidade de evoluir o pacote padrão para atender às demandas modernas e corrigir falhas identificadas ao longo do tempo.
Testando o Tempo: Simplificando Testes Assíncronos em Go
O pacote testing/synctest do Go 1.25 simplifica testes de codigo assincrono e concorrente. Aprenda a testar goroutines, channels e timers facilmente.
O artigo do blog oficial do Go discute a importância e os desafios de testar código assíncrono, introduzindo o pacote testing/synctest, que agora está disponível para uso geral desde o Go 1.25, após um período como pacote experimental no Go 1.24. O pacote visa simplificar significativamente a escrita de testes para código concorrente e assíncrono.
O que é uma Função Assíncrona?
O artigo começa definindo a diferença entre funções síncronas e assíncronas. Uma função síncrona executa uma ação e retorna um resultado imediatamente, enquanto uma função assíncrona retorna imediatamente após ser chamada, executando a ação em segundo plano, em algum momento no futuro. Um exemplo simples é a função Cleanup que remove um diretório de cache de forma síncrona, em contraste com CleanupInBackground, que executa a remoção em uma goroutine separada.
Go e Containers: Uma Nova Inteligência para GOMAXPROCS
Go 1.25 torna GOMAXPROCS container-aware: detecta limites de CPU em Kubernetes e Docker automaticamente, eliminando throttling e melhorando latencia.
O Go 1.25 traz uma mudança importante na forma como a linguagem lida com ambientes de containers, com um novo comportamento padrão para a variável GOMAXPROCS. Essa atualização visa otimizar o desempenho de aplicações Go em containers, evitando o “throttling” (estrangulamento) que pode impactar a latência e melhorando a “production-readiness” da linguagem.
Entendendo o GOMAXPROCS
O Go oferece um modelo de concorrência poderoso e fácil de usar através das goroutines. Goroutines são semelhantes a threads do sistema operacional, mas muito mais leves, permitindo a criação e destruição sob demanda sem grande impacto no desempenho.
Go 1.25 Chegou: O Que Há de Novo?
Go 1.25 traz GOMAXPROCS container-aware, Green Tea GC experimental com 10-40% menos overhead, nova diretiva ignore no go.mod e melhorias no vet.
A equipe Go tem o prazer de anunciar o lançamento do Go 1.25. Esta versão traz melhorias significativas nas ferramentas, no runtime, no compilador, no linker e na biblioteca padrão, além de introduzir um novo pacote. Algumas adições estão em fase experimental e requerem ativação explícita para serem utilizadas.
Melhorias e Novidades do Go 1.25
O Go 1.25 apresenta uma série de aprimoramentos em diversos componentes da linguagem. Vamos explorar as principais áreas de foco:
Go 1.25: Novidades e Recursos
Go 1.25 traz Green Tea GC (-40% overhead), GOMAXPROCS container-aware, diretiva ignore no go.mod, go doc -http e novos analyzers. Veja todas as mudanças.
Novidades do Go 1.25: Uma Análise Detalhada
A versão Go 1.25, lançada em 12 de agosto de 2025, traz uma série de melhorias e adições que visam aprimorar a experiência do desenvolvedor, otimizar o desempenho e expandir as capacidades da linguagem. Esta análise detalhada explora as principais novidades, mudanças na biblioteca padrão e oferece orientações sobre como atualizar para esta versão.
Principais Novidades do Go 1.25
O Go 1.25 foca em refinamentos e otimizações, em vez de introduzir grandes mudanças de paradigma. As principais novidades incluem melhorias no gerenciamento de memória, otimizações no compilador e novas funcionalidades na biblioteca padrão.
Go Simplifica a Conformidade com FIPS 140-3: Segurança e Facilidade para Ambientes Regulamentados
Modulo Criptografico Go FIPS 140-3 nativo: conformidade simplificada com seguranca integrada na stdlib desde Go 1.24. Certificado CAVP A6650.
O artigo do blog oficial do Go anuncia a disponibilidade do Módulo Criptográfico Go FIPS 140-3, integrado nativamente à biblioteca padrão e à ferramenta go. Essa novidade visa simplificar a conformidade com o padrão FIPS 140, um requisito comum em ambientes regulamentados que adotam cada vez mais a linguagem Go. Anteriormente, a conformidade com FIPS 140 era um obstáculo significativo para os usuários de Go, exigindo soluções não suportadas com problemas de segurança, experiência do desenvolvedor, funcionalidade, velocidade de lançamento e conformidade.
Go 1.24: Novidades e Recursos
Go 1.24 traz generic type aliases completos, swiss tables no runtime (maps mais rápidos), melhorias no crypto/tls e weak pointers. Resumo completo das mudanças.
Go 1.24: O Que Há de Novo Nesta Versão
A versão 1.24 da linguagem Go foi lançada em 11 de fevereiro de 2025, trazendo consigo uma série de aprimoramentos e novas funcionalidades que visam otimizar o desenvolvimento e a performance das aplicações Go. Esta versão foca em melhorias na biblioteca padrão, otimizações no compilador e no garbage collector, além de adicionar suporte experimental para novas funcionalidades da linguagem. Este artigo detalha as principais mudanças e como elas impactam o dia a dia do desenvolvedor Go.
Go 1.23: Novidades e Recursos
Go 1.23 trouxe range over func (iterators customizados), pacote unique para interning, melhorias no timer/ticker e suporte a OpenBSD 7.6. Resumo completo.
Go 1.23: Novidades e Melhorias na Linguagem
O Go 1.23, lançado em 13 de agosto de 2024, traz consigo uma série de melhorias e adições à linguagem, visando otimizar o desenvolvimento, a performance e a usabilidade. Esta versão continua o compromisso do Go com a estabilidade e compatibilidade, introduzindo mudanças que aprimoram a experiência do desenvolvedor sem causar grandes rupturas.
Principais Novidades
O Go 1.23 apresenta diversas novidades, com foco em melhorias na linguagem, na biblioteca padrão e no desempenho. Abaixo, destacamos algumas das principais adições:
Go 1.22: Novidades e Recursos
Go 1.22 trouxe range over integers, routing patterns no net/http (GET /users/{id}), loop variable fix e workspace improvements. Resumo completo.
Go 1.22: O Que Há de Novo na Linguagem do Google
A versão Go 1.22 foi lançada em 6 de fevereiro de 2024, trazendo diversas melhorias e novidades para a linguagem. Esta versão se concentra em aprimorar a experiência do desenvolvedor, otimizar o desempenho e refinar a biblioteca padrão. Este artigo detalha as principais mudanças e como elas impactam o desenvolvimento em Go.
Loop Variable Capture: Um Novo Comportamento
Uma das mudanças mais significativas no Go 1.22 é a alteração no comportamento do loop variable capture. Em versões anteriores, variáveis declaradas em loops for eram compartilhadas entre todas as iterações, o que frequentemente levava a erros sutis e inesperados, especialmente quando se usava goroutines dentro do loop.
Go 1.21: Novidades e Recursos
Go 1.21 trouxe builtins min/max/clear, log/slog estruturado, suporte WASI (WebAssembly), PGO ativado por padrao e toolchain management. Veja todas as mudancas.
Go 1.21: O Que Há de Novo na Linguagem da Google
A versão 1.21 da linguagem Go foi lançada em 8 de agosto de 2023, trazendo consigo uma série de melhorias e novidades que visam otimizar o desenvolvimento, aprimorar a performance e expandir as capacidades da linguagem. Esta versão foca em estabilidade, usabilidade e refinamento das funcionalidades existentes. Vamos explorar as principais mudanças e como elas impactam o desenvolvimento em Go.
Go 1.20: Novidades e Recursos
Go 1.20 trouxe PGO (Profile-Guided Optimization) preview, coverage profiling para binarios, errors.Join, melhorias no crypto/ecdh e slice-to-array nativo.
Go 1.20: As Novidades da Linguagem e do Ecossistema
A versão 1.20 da linguagem Go foi lançada em 1 de fevereiro de 2023, trazendo consigo uma série de melhorias e novidades que visam aprimorar a experiência do desenvolvedor, otimizar o desempenho das aplicações e fortalecer o ecossistema Go. Este artigo explora as principais mudanças introduzidas nesta versão, oferecendo exemplos práticos e referências à documentação oficial para auxiliar na transição e adoção das novas funcionalidades.
Go 1.19: Novidades e Recursos
Go 1.19 trouxe doc comments reformatados, memory model atualizado (alinhado com C++/Java/Rust), soft memory limit via GOMEMLIMIT e melhorias no GC.
Go 1.19: O que há de novo na linguagem Go?
A versão 1.19 da linguagem Go foi lançada em 2 de agosto de 2022, trazendo diversas melhorias e novidades que visam aprimorar a experiência de desenvolvimento, o desempenho e a segurança das aplicações Go. Esta versão foca em refinamentos da linguagem, melhorias na biblioteca padrão e otimizações de desempenho. Este artigo detalha as principais mudanças, fornecendo exemplos práticos e links para a documentação oficial.
Go 1.18: Novidades e Recursos
Go 1.18 foi a maior release da historia do Go: generics (type parameters), fuzzing nativo para testes, go workspace para multi-module e 20% mais rapido no ARM.
Go 1.18: As Novidades da Linguagem
A versão 1.18 do Go, lançada em 15 de março de 2022, trouxe mudanças significativas para a linguagem, com destaque para a introdução de generics, workspaces e melhorias de performance. Esta atualização representa um marco importante na evolução do Go, expandindo suas capacidades e oferecendo novas ferramentas para os desenvolvedores.
Generics: Programação Genérica no Go
A principal novidade do Go 1.18 é, sem dúvida, a introdução de generics (tipos genéricos). Generics permitem escrever código que pode operar com diferentes tipos de dados sem a necessidade de duplicação de código ou uso de interface{} (a interface vazia) com type assertions. Essa funcionalidade promove maior reutilização, segurança de tipos e legibilidade.
Go 1.17: Novidades e Recursos
Go 1.17 trouxe conversao slice-to-array, register-based calling convention (ate 15% mais rapido), pruned module graph e melhorias no go vet.
Novidades do Go 1.17: Um mergulho nas melhorias e otimizações
A versão 1.17 da linguagem Go foi lançada em 16 de agosto de 2021, trazendo uma série de melhorias significativas em performance, sintaxe e na biblioteca padrão. Essa atualização foca em otimizar o desempenho do código gerado, simplificar a conversão de slices, e introduzir novas funcionalidades que facilitam o desenvolvimento e a manutenção de aplicações Go. As mudanças visam tornar o código Go mais eficiente, legível e fácil de trabalhar.
Go 1.16: Novidades e Recursos
Go 1.16 trouxe embed package (//go:embed), io/fs abstraction, suporte nativo Apple Silicon (M1), go install sem go.mod e modules on por padrao.
Novidades do Go 1.16: Um Guia Detalhado
O Go 1.16, lançado em 16 de fevereiro de 2021, trouxe uma série de melhorias e novas funcionalidades que visam otimizar o desenvolvimento e a implantação de aplicações Go. Esta versão foca significativamente na incorporação de módulos, no aprimoramento do embedding de arquivos estáticos e em diversas melhorias na biblioteca padrão. Este artigo explora em detalhes as principais mudanças, oferecendo exemplos práticos e links para a documentação oficial.
Go 1.15: Novidades e Recursos
Descubra as principais novidades do Go 1.15, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Novidades do Go 1.15: Um Guia Detalhado
A versão 1.15 do Go, lançada em 11 de agosto de 2020, trouxe um conjunto significativo de melhorias e adições à linguagem. Focada na performance, segurança e usabilidade, esta versão consolidou o Go como uma ferramenta poderosa para o desenvolvimento de software moderno. Este artigo explora as principais mudanças e seus impactos práticos.
Compilador e Runtime
Melhorias no Garbage Collector (GC)
O Go 1.15 aprimorou significativamente o garbage collector. A principal mudança reside na otimização do agendamento do GC, reduzindo a latência e o overhead. Isso é particularmente notável em aplicações com alta alocação de memória.
Go 1.14: Novidades e Recursos
Descubra as principais novidades do Go 1.14, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Go 1.14: Um Olhar Detalhado nas Novidades
A versão 1.14 da linguagem Go foi lançada em 25 de fevereiro de 2020, trazendo consigo uma série de melhorias e adições que impactam tanto o desempenho quanto a usabilidade da linguagem. Esta versão foca em aprimorar o suporte a módulos, otimizar o desempenho do garbage collector e introduzir funcionalidades que facilitam o desenvolvimento concorrente. Este artigo explora as principais novidades, as mudanças na biblioteca padrão e fornece um guia prático para a atualização.
Go 1.13: Novidades e Recursos
Go 1.13 trouxe errors.Is/errors.As para error wrapping, novos number literals (0b, 0o, _), Go Modules como padrao e GOPROXY=proxy.golang.org.
Go 1.13: O que há de novo na linguagem da Google?
Go 1.13 foi lançado em 3 de setembro de 2019, trazendo diversas melhorias e novidades para a linguagem. Esta versão se concentra em melhorar a experiência do desenvolvedor, a performance da linguagem e aprimorar a biblioteca padrão. Este artigo explora as principais mudanças e como elas podem impactar seu código.
Erros Embrulhados (Wrapped Errors)
Uma das adições mais significativas do Go 1.13 é o suporte para erros embrulhados (wrapped errors). Essa funcionalidade permite que você adicione contexto a um erro sem perder a informação original, facilitando o diagnóstico e tratamento de falhas.
Go 1.12: Novidades e Recursos
Descubra as principais novidades do Go 1.12, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Novidades do Go 1.12: Uma Análise Detalhada
O Go 1.12, lançado em 25 de fevereiro de 2019, trouxe uma série de melhorias e adições que, embora não revolucionárias, refinaram a linguagem e a tornaram ainda mais robusta e eficiente. Esta versão focou em performance, usabilidade e consistência, solidificando o Go como uma escolha popular para desenvolvimento de software. Este artigo explora as principais novidades e mudanças introduzidas no Go 1.12, fornecendo exemplos práticos e links para a documentação oficial para auxiliar na compreensão e adoção dessas atualizações.
Go 1.11: Novidades e Recursos
Descubra as principais novidades do Go 1.11, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Novidades do Go 1.11: Uma Análise Detalhada
A versão 1.11 do Go, lançada em 24 de agosto de 2018, introduziu mudanças significativas na linguagem, com destaque para o suporte experimental a módulos, melhorias no compilador e na biblioteca padrão. Esta versão marcou um passo importante na evolução do Go, facilitando o gerenciamento de dependências e oferecendo novas ferramentas para os desenvolvedores.
Suporte Experimental a Módulos
A principal novidade do Go 1.11 foi a introdução do suporte experimental a módulos. Antes dos módulos, o gerenciamento de dependências em Go era frequentemente realizado através de ferramentas externas como dep ou utilizando a convenção de colocar o código dentro do $GOPATH. Os módulos visavam simplificar e padronizar esse processo.
Go 1.10: Novidades e Recursos
Descubra as principais novidades do Go 1.10, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Novidades do Go 1.10: Um Guia Prático
O Go 1.10, lançado em 16 de fevereiro de 2018, trouxe uma série de melhorias e adições à linguagem, focando em desempenho, ferramentas e bibliotecas. Embora não introduza mudanças drásticas na sintaxe da linguagem, essa versão consolidou o ecossistema Go, preparando o terreno para futuras evoluções. Este artigo explora as principais novidades e como elas podem impactar o desenvolvimento em Go.
Principais Novidades
Suporte a Vendor no Comando go test
Uma das adições mais bem-vindas no Go 1.10 foi o suporte a vendor no comando go test. Anteriormente, ao executar testes em um projeto que utilizava vendor, era necessário tomar cuidado para garantir que as dependências vendidas fossem corretamente resolvidas. O Go 1.10 simplificou esse processo, permitindo que o comando go test reconhecesse automaticamente as dependências vendidas.
Go 1.9: Novidades e Recursos
Descubra as principais novidades do Go 1.9, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Novidades do Go 1.9: Uma Análise Detalhada
O Go 1.9, lançado em 24 de agosto de 2017, introduziu diversas melhorias significativas na linguagem, oferecendo recursos novos e otimizações que impactaram tanto o desenvolvimento quanto o desempenho de aplicações Go. Esta versão focou em aprimorar a concorrência, a legibilidade do código e a modularidade. Vamos explorar as principais novidades e mudanças que foram introduzidas.
Type Aliases: Simplificando a Refatoração e a Evolução de APIs
Uma das adições mais importantes no Go 1.9 é o conceito de type aliases. Um type alias permite que um novo nome seja dado a um tipo existente, sem criar um novo tipo distinto. Isso é particularmente útil para refatoração de código e evolução de APIs, permitindo que tipos sejam renomeados ou movidos sem quebrar a compatibilidade com código existente.
Go 1.8: Novidades e Recursos
Descubra as principais novidades do Go 1.8, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Go 1.8: O Que Há de Novo?
Go 1.8, lançado em 16 de fevereiro de 2017, trouxe uma série de melhorias significativas para a linguagem, tanto em termos de desempenho quanto de funcionalidades da biblioteca padrão. Esta versão focou em otimizações de performance, suporte a plugins, contexto em net/http e uma série de adições e correções menores. Vamos explorar as principais novidades e mudanças desta versão.
Plugins
Uma das adições mais notáveis do Go 1.8 é o suporte a plugins. Plugins permitem estender a funcionalidade de um programa Go em tempo de execução, carregando código compilado separadamente. Isso oferece uma grande flexibilidade, permitindo que você adicione ou modifique o comportamento de um programa sem recompilá-lo.
Go 1.7: Novidades e Recursos
Descubra as principais novidades do Go 1.7, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Novidades do Go 1.7: Uma Análise Detalhada
O Go 1.7, lançado em 15 de agosto de 2016, trouxe consigo uma série de melhorias e novas funcionalidades que impactaram significativamente o desenvolvimento em Go. Esta versão focou em otimizações de performance, especialmente na compilação, e introduziu novos recursos para facilitar o desenvolvimento de aplicações mais robustas e eficientes. Este artigo explora as principais mudanças e novidades introduzidas no Go 1.7, oferecendo exemplos práticos e links para a documentação oficial para auxiliar na compreensão e adoção dessas novidades.
Go 1.6: Novidades e Recursos
Descubra as principais novidades do Go 1.6, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Novidades do Go 1.6: Uma Análise Detalhada
O Go 1.6, lançado em 17 de fevereiro de 2016, trouxe uma série de melhorias e adições significativas à linguagem. Embora não tenha introduzido mudanças radicais na sintaxe, focou-se em otimizações de performance, aprimoramentos na biblioteca padrão e novas funcionalidades para facilitar o desenvolvimento e a implantação de aplicações Go. Este artigo explora as principais novidades desta versão, oferecendo uma visão detalhada para desenvolvedores que buscam aprimorar seus conhecimentos e tirar o máximo proveito do Go.
Go 1.5: Novidades e Recursos
Descubra as principais novidades do Go 1.5, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Go 1.5: Uma Virada Significativa no Ecossistema Go
O Go 1.5, lançado em 19 de agosto de 2015, representou um marco fundamental na evolução da linguagem Go. Esta versão introduziu mudanças significativas na implementação do compilador, no garbage collector e no suporte a concorrência, além de diversas melhorias na biblioteca padrão. O impacto do Go 1.5 foi profundo, pavimentando o caminho para o Go se tornar uma linguagem ainda mais robusta e eficiente para o desenvolvimento de aplicações de alta performance.
Go 1.4: Novidades e Recursos
Descubra as principais novidades do Go 1.4, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Go 1.4: Uma Análise Detalhada das Novidades e Melhorias
Lançado em 10 de dezembro de 2014, o Go 1.4 marcou um ponto de inflexão na evolução da linguagem Go. Esta versão introduziu mudanças significativas sob o capô, focando na portabilidade, ferramentas e, crucialmente, no suporte ao Android e iOS. Embora não tenha apresentado grandes alterações na sintaxe da linguagem, o Go 1.4 pavimentou o caminho para o futuro do Go, estabelecendo bases sólidas para as versões subsequentes. Este artigo explora as principais novidades, melhorias de performance e mudanças na biblioteca padrão que definiram o Go 1.4.
Go 1.3: Novidades e Recursos
Descubra as principais novidades do Go 1.3, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Novidades do Go 1.3: Uma Análise Detalhada
O Go 1.3, lançado em 18 de junho de 2014, representou um marco importante na evolução da linguagem Go. Embora não introduzisse mudanças drásticas na sintaxe ou semântica da linguagem, o Go 1.3 focou-se em otimizações internas, melhorias no coletor de lixo, e aprimoramentos na portabilidade e desempenho. Esta versão pavimentou o caminho para a adoção em larga escala do Go em ambientes de produção, solidificando sua reputação como uma linguagem eficiente e confiável.
Go 1.2: Novidades e Recursos
Descubra as principais novidades do Go 1.2, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Novidades do Go 1.2: Uma Análise Detalhada
O Go 1.2, lançado em 1 de dezembro de 2013, representou um marco importante na evolução da linguagem Go. Embora possa parecer distante no tempo, esta versão introduziu melhorias significativas que pavimentaram o caminho para as versões mais modernas. Este artigo explora as principais novidades e aprimoramentos do Go 1.2, com foco em suas implicações práticas para desenvolvedores.
Principais Novidades e Aprimoramentos
O Go 1.2 trouxe várias mudanças notáveis, desde melhorias na performance até adições à biblioteca padrão. Examinaremos algumas das mais impactantes:
Go 1.1: Novidades e Recursos
Descubra as principais novidades do Go 1.1, incluindo novos recursos, melhorias de performance e mudancas na biblioteca padrao.
Novidades do Go 1.1: Uma Análise Detalhada
O Go 1.1, lançado em 13 de maio de 2013, marcou um ponto de inflexão importante na evolução da linguagem Go. Embora não tenha introduzido mudanças radicais na sintaxe, essa versão refinou a linguagem e sua biblioteca padrão, além de trazer melhorias significativas de desempenho. Este artigo explora as principais novidades do Go 1.1, fornecendo exemplos práticos e links para a documentação oficial para que você possa entender e aproveitar ao máximo essas melhorias.
Go 1.0: Novidades e Recursos
Go 1.0 (marco 2012): o primeiro release estavel do Golang. Garantia de compatibilidade, goroutines, garbage collector, e o inicio da revolucao no backend.
Go 1.0: A Estabilidade e o Início de uma Jornada
O lançamento do Go 1.0 em 28 de março de 2012 marcou um ponto crucial na história da linguagem. Após anos de desenvolvimento e refinamento, a equipe do Google apresentou uma versão considerada estável e com garantia de retrocompatibilidade. Isso significava que o código escrito para o Go 1.0 continuaria funcionando em versões futuras, um compromisso fundamental para a adoção em larga escala.