Padrões Arquiteturais em Go: como não se afogar em goroutines

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que a arquitetura não é um luxo, mas uma necessidade

\n\n

Quando você começa a programar em Go, parece que tudo é simples: as goroutines voam, os canais zumbem e o compilador agrada pela velocidade. Mas passa um mês ou dois, e seu projeto-pet se transforma em um monstro com package main de 3000 linhas e orações "tomara que não quebre". Familiar?

\n\n

Go oferece ferramentas poderosas, mas não impõe estruturas rígidas. Isso é um ponto positivo e negativo. Sem uma arquitetura clara, você rapidamente se perderá em suas próprias goroutines. É aqui que entram os padrões arquiteturais em Go — soluções comprovadas para problemas típicos de design.

\n\n

Neste artigo, vamos analisar quatro padrões principais que realmente simplificarão sua vida: Repository, Service Layer, Worker Pool e Pipeline. Você verá exemplos de código, entenderá quando aplicar cada padrão e poderá implementá-los imediatamente em seus projetos. Vamos lá!

\n\n

1. Repository Pattern: separando a lógica de negócios do banco de dados

\n\n

O primeiro padrão que todo desenvolvedor Go deve dominar é o Repository. Sua essência é simples: criar uma camada entre a lógica de negócios e o armazenamento de dados (BD, arquivos, APIs externas).

\n\n

Por que isso é necessário?

\n
    \n
  • Testabilidade: é possível substituir facilmente o BD real por um mock.
  • \n
  • Flexibilidade: migrar do PostgreSQL para o MongoDB? Basta alterar o repositório.
  • \n
  • Limpeza do código: o handler não sabe de onde vêm os dados — essa é a função do repositório.
  • \n
\n\n

Exemplo de implementação

\n

Suponha que temos um modelo de usuário:

\n\n
type User struct {\n    ID    int64\n    Name  string\n    Email string\n}
\n\n

Definimos a interface do repositório:

\n\n
type UserRepository interface {\n    GetByID(ctx context.Context, id int64) (*User, error)\n    Create(ctx context.Context, user *User) error\n    Update(ctx context.Context, user *User) error\n    Delete(ctx context.Context, id int64) error\n}
\n\n

E sua implementação para PostgreSQL:

\n\n
type PostgresUserRepo struct {\n    db *sql.DB\n}\n\nfunc (r *PostgresUserRepo) GetByID(ctx context.Context, id int64) (*User, error) {\n    user := &User{}\n    err := r.db.QueryRowContext(ctx, "SELECT id, name, email FROM users WHERE id = $1", id).\n        Scan(&user.ID, &user.Name, &user.Email)\n    if err != nil {\n        return nil, fmt.Errorf("get user by id: %w", err)\n    }\n    return user, nil\n}
\n\n

Agora seu handler ou serviço trabalha apenas com a interface UserRepository, e não com um BD específico. Isso é o padrão arquitetural Repository em Go em ação.

\n\n

2. Service Layer: lógica de negócios sob controle

\n\n

Se o Repository é responsável pelos dados, o Service Layer é responsável pelas regras de negócios. Esse padrão reúne operações dispersas em ações significativas.

\n\n

Problema sem o Service Layer

\n

Frequentemente vejo código onde o handler faz tudo: valida a requisição, verifica permissões, escreve no BD e registra logs. Isso viola o princípio da responsabilidade única (SRP).

\n\n

Como corrigir isso?

\n

Introduzimos a camada de serviço:

\n\n
type UserService interface {\n    Register(ctx context.Context, name, email string) (*User, error)\n    GetProfile(ctx context.Context, userID int64) (*User, error)\n}\n\ntype userService struct {\n    repo UserRepository\n    mail MailSender\n}\n\nfunc (s *userService) Register(ctx context.Context, name, email string) (*User, error) {\n    // 1. Validação\n    if name == "" || email == "" {\n        return nil, ErrInvalidInput\n    }\n\n    // 2. Lógica de negócios: verificar se o email já está em uso\n    existing, _ := s.repo.GetByEmail(ctx, email)\n    if existing != nil {\n        return nil, ErrEmailAlreadyExists\n    }\n\n    // 3. Criar usuário\n    user := &User{Name: name, Email: e                

Blogs

Book Recommendations