DDD - Domain-Driven Design
Visão Geral
Domain-Driven Design (DDD) é uma abordagem de desenvolvimento de software que coloca o domínio do negócio no centro do processo de desenvolvimento. O foco está em criar um modelo de domínio rico que reflita fielmente as regras e processos do negócio.
Definição: "DDD é uma abordagem para desenvolver software para necessidades complexas através de uma profunda conexão entre a implementação e os conceitos centrais do negócio." - Eric Evans
Conceitos Fundamentais
1. Ubiquitous Language (Linguagem Ubíqua)
Definição: Uma linguagem comum compartilhada entre desenvolvedores e especialistas do domínio.
Características:
- Mesma terminologia no código e nas conversas
- Nomes de classes, métodos e variáveis refletem o negócio
- Documentação usa os mesmos termos
- Reduz ambiguidade e mal-entendidos
Exemplo no Santa Mão:
// ❌ Evitar termos técnicos genéricos
public class Data { }
public class Manager { }
// ✅ Usar termos do domínio
public class Request { } // Solicitação de serviço
public class Job { } // Categoria de serviço
public class Order { } // Pedido confirmado
2. Bounded Context (Contexto Delimitado)
Definição: Um limite explícito dentro do qual um modelo de domínio é definido e aplicável.
No Santa Mão:

3. Domain Model (Modelo de Domínio)
Definição: Representação conceitual do domínio que incorpora tanto comportamento quanto dados.
Componentes:
- Entities (Entidades)
- Value Objects (Objetos de Valor)
- Aggregates (Agregados)
- Domain Services (Serviços de Domínio)
- Domain Events (Eventos de Domínio)
Building Blocks do DDD
1. Entities (Entidades)
Definição: Objetos definidos pela sua identidade, não pelos seus atributos.
Características:
- Possuem identidade única (ID)
- Podem mudar de estado ao longo do tempo
- Comparados pela identidade, não pelos atributos
Exemplo:
public class User : Entity
{
public Guid Id { get; private set; }
public Name Name { get; private set; }
public Email Email { get; private set; }
public Status Status { get; private set; }
private User() { }
public static User Create(string firstName, string lastName, string email)
{
var user = new User
{
Id = Guid.NewGuid(),
Name = new Name(firstName, lastName),
Email = new Email(email),
Status = Status.Active
};
user.AddDomainEvent(new UserCreatedEvent(user.Id));
return user;
}
}
2. Value Objects (Objetos de Valor)
Definição: Objetos sem identidade conceitual, definidos apenas pelos seus atributos.
Características:
- Imutáveis
- Comparados pelos valores, não pela identidade
- Podem ser compartilhados
- Sem efeitos colaterais
Exemplo:
public class Email : ValueObject
{
public string Value { get; private set; }
public Email(string value)
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("Email cannot be empty");
if (!IsValidEmail(value))
throw new ArgumentException("Invalid email format");
Value = value.ToLower();
}
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Value;
}
}
public class Money : ValueObject
{
public decimal Amount { get; private set; }
public string Currency { get; private set; }
public Money(decimal amount, string currency = "BRL")
{
if (amount < 0)
throw new ArgumentException("Amount cannot be negative");
Amount = amount;
Currency = currency;
}
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Amount;
yield return Currency;
}
}
3. Aggregates (Agregados)
Definição: Cluster de objetos de domínio tratados como uma única unidade para mudanças de dados.
Características:
- Possui um Aggregate Root (raiz do agregado)
- Define limites de consistência
- Acesso externo apenas pela raiz
- Transações limitadas ao agregado
Exemplo:
public class User : AggregateRoot
{
public Guid Id { get; private set; }
public Name Name { get; private set; }
private readonly List<UserAddress> _addresses = new();
public IReadOnlyCollection<UserAddress> Addresses => _addresses.AsReadOnly();
public void AddAddress(UserAddress address)
{
if (_addresses.Count >= 5)
throw new DomainException("User cannot have more than 5 addresses");
if (_addresses.Count == 0)
address.SetAsDefault();
_addresses.Add(address);
AddDomainEvent(new UserAddressAddedEvent(Id, address.Id));
}
}
4. Domain Services (Serviços de Domínio)
Definição: Operações do domínio que não pertencem naturalmente a uma entidade ou value object.
Quando usar:
- Operação envolve múltiplos agregados
- Lógica de negócio não pertence a nenhuma entidade específica
- Cálculos complexos ou algoritmos de domínio
Exemplo:
public interface IJobPricingService
{
Money CalculatePrice(Job job, JobTask task);
}
public class JobPricingService : IJobPricingService
{
public Money CalculatePrice(Job job, JobTask task)
{
var basePrice = task.BasePrice;
// Lógica de cálculo com multiplicadores
return basePrice;
}
}
5. Domain Events (Eventos de Domínio)
Definição: Algo significativo que aconteceu no domínio.
Características:
- Representam fatos passados (UserCreated, OrderPlaced)
- Imutáveis
- Usados para comunicação entre agregados
Exemplo:
public class UserCreatedEvent : DomainEvent
{
public Guid UserId { get; }
public string Email { get; }
public DateTime OccurredOn { get; }
public UserCreatedEvent(Guid userId, string email)
{
UserId = userId;
Email = email;
OccurredOn = DateTime.UtcNow;
}
}
Nota: Para detalhes sobre como eventos são publicados e consumidos, veja EDA Pattern e Outbox Pattern.
6. Repositories (Repositórios)
Definição: Abstração para persistência de agregados.
Características:
- Um repositório por aggregate root
- Encapsula acesso a dados
- Trabalha com agregados completos
- Interface definida no domínio, implementação na infraestrutura
Exemplo:
public interface IUserRepository
{
Task<User> GetByIdAsync(Guid id);
Task<User> GetByEmailAsync(string email);
Task AddAsync(User user);
Task UpdateAsync(User user);
}
Padrões Táticos
1. Aggregate Pattern
Regras:
- Referência externa via ID, não objeto
- Um repositório por agregado
- Transações não devem cruzar agregados
- Invariantes apenas dentro do agregado
2. Factory Pattern
Quando usar: Criação complexa de agregados com validações extensas
public static User CreateFromRegistration(string firstName, string lastName, string email)
{
// Lógica de criação e validação
return User.Create(firstName, lastName, email);
}
3. Specification Pattern
Quando usar: Regras de negócio complexas e validações reutilizáveis
public class UserIsActiveSpecification : ISpecification<User>
{
public bool IsSatisfiedBy(User user)
{
return user.Status == Status.Active;
}
}
Camadas da Arquitetura
Estrutura em Camadas

Dependências
- Presentation → Application → Domain
- Application → Domain
- Infrastructure → Application
- Domain → Nada (núcleo independente)
Boas Práticas no Santa Mão
1. Sempre Valide no Domínio
// ✅ Bom
public class User
{
public void UpdateEmail(string email)
{
if (string.IsNullOrWhiteSpace(email))
throw new DomainException("Email cannot be empty");
Email = new Email(email);
}
}
// ❌ Ruim - validação só na aplicação
public class UpdateUserCommandHandler
{
public async Task Handle(UpdateUserCommand request)
{
if (string.IsNullOrWhiteSpace(request.Email))
return; // Validação fora do domínio!
user.Email = request.Email;
}
}
2. Encapsule Coleções
// ✅ Bom
private readonly List<UserAddress> _addresses = new();
public IReadOnlyCollection<UserAddress> Addresses => _addresses.AsReadOnly();
// ❌ Ruim
public List<UserAddress> Addresses { get; set; }
3. Use Factory Methods
// ✅ Bom
public static User Create(string firstName, string lastName)
{
var user = new User();
// Lógica de inicialização
user.AddDomainEvent(new UserCreatedEvent(user.Id));
return user;
}
// ❌ Ruim
var user = new User { FirstName = "John", LastName = "Doe" };
4. Mantenha Invariantes
public void AddAddress(UserAddress address)
{
// Invariante: máximo 5 endereços
if (_addresses.Count >= 5)
throw new DomainException("Maximum addresses exceeded");
_addresses.Add(address);
}
Anti-Patterns a Evitar
1. Anemic Domain Model
❌ Evitar: Entidades apenas com getters/setters
// Anêmico - apenas dados
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
✅ Correto: Modelo rico com comportamento
public class User
{
public Name Name { get; private set; }
public Email Email { get; private set; }
public void UpdateName(string firstName, string lastName)
{
Name = new Name(firstName, lastName);
AddDomainEvent(new UserNameUpdatedEvent(Id));
}
}
2. Domain Logic Leakage
❌ Evitar: Lógica de domínio fora do domínio
// Na Application Layer
if (user.Status == Status.Active && !user.IsDeleted)
{
// Lógica de negócio no handler!
}
✅ Correto: Lógica no domínio
// No Domain
public bool CanPerformAction()
{
return Status == Status.Active && !IsDeleted;
}
3. Aggregate Boundaries Errados
❌ Evitar: Agregado muito grande
public class User
{
public List<Order> Orders { get; set; } // Order deveria ser agregado separado!
public List<Request> Requests { get; set; } // Request deveria ser agregado separado!
}
✅ Correto: Agregados independentes
public class User
{
// User é um agregado
}
public class Order
{
public Guid UserId { get; set; } // Referência via ID
}
Benefícios do DDD
✅ Código reflete fielmente o negócio
✅ Regras de negócio centralizadas e protegidas no domínio
✅ Comunicação melhorada entre desenvolvedores e especialistas do negócio
✅ Código expressivo e de fácil manutenção
✅ Mudanças nos requisitos incorporadas de forma natural
Quando Usar e Quando NÃO Usar
✅ Usar DDD Quando:
- Domínio complexo com muitas regras de negócio
- Projeto de longo prazo que evoluirá
- Equipe tem acesso a especialistas do domínio
- Múltiplos contextos bounded precisam interagir
- Valor do negócio justifica o investimento inicial
❌ NÃO Usar DDD Quando:
- CRUD simples sem lógica de negócio
- Projeto pequeno ou temporário
- Sem acesso a especialistas do domínio
- Equipe sem experiência em DDD
- Deadline muito curto
Relacionamento com Outros Padrões
DDD trabalha em conjunto com:
- CQRS - Aggregates executam Commands e geram eventos, Queries leem sem afetar o domínio
- EDA - Domain Events são publicados quando estado do Aggregate muda
- Outbox Pattern - Domain Events são persistidos de forma confiável
Fluxo Integrado:
Aggregate Root → Domain Event → Outbox → Redpanda → Workers
Conclusão
DDD no Santa Mão é mais que padrões técnicos - é uma filosofia de desenvolvimento que coloca o negócio em primeiro lugar.
Resultados Alcançados:
✅ Modelagem fiel do negócio no código
✅ Regras de negócio centralizadas no domínio
✅ Código expressivo e manutenível
✅ Comunicação efetiva entre técnicos e especialistas do negócio
A implementação consistente de DDD em todo o projeto garante que o código reflita o negócio e que mudanças nos requisitos possam ser incorporadas de forma natural e sustentável.
Última atualização: Novembro 2025
Maintainers: Equipe de Arquitetura Santa Mão