Domain-Driven Design em Go: Como não se afogar em camadas de abstração

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 seu projeto Go precisa de DDD?

\n\n

Você já escreveu um serviço em Go que começou com alguns endpoints e três tabelas no banco, e depois de seis meses se transformou em um monstro com arquivos handler.go quilométricos e números mágicos espalhados por todo o código? Familiar. Eu também passei por isso.

\n\n

O problema do desenvolvimento Go clássico é que pensamos cedo demais em bancos de dados e JSON, esquecendo o principal: a lógica de negócio. O Domain-Driven Design (DDD) vem em socorro exatamente quando queremos colocar ordem no caos. Mas como aplicar DDD em Go, se a linguagem não nos mima com classes e herança? Vamos descobrir.

\n\n

Neste artigo, mostrarei como aplicar Domain-Driven Design em projetos Go sem fanatismo excessivo, com exemplos de código funcionais e uma estrutura clara. Você aprenderá como separar o joio do trigo e criar um código que seja compreensível não apenas para a máquina, mas também para o analista de negócios.

\n\n

O que é DDD e por que ele é necessário para o desenvolvedor Go?

\n\n

Domain-Driven Design não é sobre tecnologia. É sobre linguagem. É sobre o código falar a linguagem do negócio. Se o seu domínio é uma loja virtual, no código devem existir Order, Product, Cart, e não DataTransferObject e EntityManager.

\n\n

Go, com sua simplicidade e ausência de magia, é ideal para DDD. Aqui não há classes proxy ou reflexão que escondam a essência. Em Go, você é forçado a ser honesto: se você tem um agregado, é uma estrutura explícita; se tem um repositório, é uma interface.

\n\n

Os principais blocos de construção do DDD que abordaremos:

\n
    \n
  • Entity (Entidade) — objeto com um identificador único (ex.: User).
  • \n
  • Value Object (Objeto de Valor) — objeto imutável que descreve características (ex.: Address).
  • \n
  • Aggregate (Agregado) — cluster de entidades que garante consistência (ex.: Order com OrderItem).
  • \n
  • Repository (Repositório) — coleção de objetos que oculta os detalhes de armazenamento.
  • \n
  • Domain Service (Serviço de Domínio) — operação que não se encaixa em uma única entidade.
  • \n
\n\n

Agora, vamos traduzir isso para Go.

\n\n

Estrutura do projeto: como não se perder nas pastas

\n\n

A boa notícia: Go não impõe nenhuma estrutura. A má notícia: sem estrutura, você se afogará rapidamente. Para DDD em Go, recomendo a seguinte organização de código:

\n\n
your-project/\n├── cmd/\n│   └── server/\n│       └── main.go\n├── internal/\n│   ├── domain/          # Núcleo puro: entidades, regras\n│   │   ├── order.go\n│   │   ├── product.go\n│   │   └── errors.go\n│   ├── application/     # Use cases / serviços da aplicação\n│   │   ├── order_service.go\n│   │   └── product_service.go\n│   └── infrastructure/  # Bancos, APIs externas, HTTP handlers\n│       ├── postgres/\n│       │   └── order_repository.go\n│       └── http/\n│           └── handler.go\n└── go.mod
\n\n

Observe: domain não importa infrastructure. Esta é a regra de ouro do DDD — o domínio não sabe nada sobre bancos de dados e HTTP. Ele vive no vácuo de estruturas e interfaces puras.

\n\n

Escrevendo o domínio: Order e Value Objects

\n\n

Vamos começar pelo núcleo. Suponha que estamos construindo um sistema de gerenciamento de pedidos. Veja como a entidade Order pode ser:

\n\n
// internal/domain/order.go\npackage domain\n\nimport (\n    "errors"\n    "time"\n)\n\ntype OrderStatus string\n\nconst (\n    OrderStatusPending   OrderStatus = "pending"\n    OrderStatusConfirmed OrderStatus = "confirmed"\n    OrderStatusCancelled OrderStatus = "cancelled"\n)\n\ntype OrderID string\n\ntype Order struct {\n    ID         OrderID\n    CustomerID string\n    Items      []OrderItem\n    Status     OrderStatus\n    CreatedAt  time.Time\n    Upd                

Blogs

Book Recommendations