Introdução: Por que seu projeto Go precisa de DDD?
\n\nVocê 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.
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\nNeste 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\nO que é DDD e por que ele é necessário para o desenvolvedor Go?
\n\nDomain-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.
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\nOs 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.:
OrdercomOrderItem). \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
Agora, vamos traduzir isso para Go.
\n\nEstrutura do projeto: como não se perder nas pastas
\n\nA 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\nyour-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\nObserve: 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.
Escrevendo o domínio: Order e Value Objects
\n\nVamos começar pelo núcleo. Suponha que estamos construindo um sistema de gerenciamento de pedidos. Veja como a entidade Order pode ser:
// 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