APIs REST e Bounded Contexts
DDD, Bounded Context e independência
Você delimita fronteiras de domínio entre os cinco serviços para garantir autonomia técnica e de negócio.
Nesta aula você vai
- Definir responsabilidade de negócio de cada serviço
- Evitar acoplamento por compartilhamento de modelo e banco
- Preparar APIs para integração por contratos
DDD, Bounded Context e independência
Objetivos
- Definir responsabilidade de negócio de cada serviço
- Evitar acoplamento por compartilhamento de modelo e banco
- Preparar APIs para integração por contratos
Pré-requisitos
- Monorepo da matéria 1 funcionando
- Cinco serviços respondendo
/health - Noções básicas de REST e JSON
Conceito
Bounded Context é uma fronteira linguística e técnica. Em vez de um modelo "global" de e-commerce, você define modelos locais: cliente pertence ao customer-service, pedido ao order-service, pagamento ao payment-service e assim por diante. Isso reduz o impacto de mudança e melhora autonomia de deploy.
O erro mais comum em times iniciantes é compartilhar entidade entre serviços para "evitar duplicação". Na prática, isso cria acoplamento oculto: uma mudança em Customer quebra Order e Payment. Em microsserviços, pequenas duplicações conscientes são melhores do que dependência estrutural entre contextos.
Nesta aula você formaliza essas fronteiras no código e na documentação. O objetivo é que qualquer desenvolvedor consiga responder rapidamente: "qual serviço é dono desta regra de negócio?".
Estrutura de arquivos
docs/
architecture/
bounded-contexts.md
services/
customer-service/src/main/java/com/aprendi/customer/domain/Customer.java
order-service/app/domain/order.py
payment-service/internal/domain/payment.go
notification-service/app/domain/notification.rb
analytics-service/src/domain/eventSnapshot.js
Passo a passo
- Criar
docs/architecture/bounded-contexts.md
# Bounded Contexts do E-commerce
- customer-service: cadastro e consulta de clientes.
- order-service: criação e acompanhamento de pedidos.
- payment-service: autorização/aprovação/recusa de pagamento.
- notification-service: envio de comunicação ao cliente.
- analytics-service: consolidação de eventos para métricas.
- Definir entidade local no Java (
customer-service)
package com.aprendi.customer.domain;
public record Customer(String id, String fullName, String email) {}
- Definir entidade local no Python (
order-service)
from pydantic import BaseModel
class Order(BaseModel):
id: str
customer_id: str
total_amount: float
status: str
- Definir entidade local em Go/Ruby/Node sem dependência cruzada
// services/payment-service/internal/domain/payment.go
package domain
type Payment struct {
ID string
OrderID string
Amount float64
Status string
}
# services/notification-service/app/domain/notification.rb
Notification = Struct.new(:id, :customer_id, :message, :channel, :status, keyword_init: true)
// services/analytics-service/src/domain/eventSnapshot.js
function eventSnapshot(type, payload) {
return { type, payload, capturedAt: new Date().toISOString() };
}
module.exports = { eventSnapshot };
Como testar
- Subir o ambiente:
docker compose -f infra/docker-compose.yml up --build -d
- Verificar se APIs seguem seus próprios contextos:
curl -s http://localhost:8081/health
curl -s http://localhost:8000/health
curl -s http://localhost:8080/health
- Conferir documentação dos contextos:
rg "customer-service|order-service|payment-service|notification-service|analytics-service" docs/architecture/bounded-contexts.md
Saída esperada: cada serviço aparece com responsabilidade específica, sem sobreposição.
Dicas de projeto
- Se outro serviço precisa de dado, exponha API/evento em vez de compartilhar tabela.
- Mantenha vocabulário de domínio por contexto (ex.:
PaymentStatusnão no Order). - Registre dono do contexto no README.
- Revise fronteiras antes de criar endpoint novo.
Erros comuns
- Criar um pacote "common-domain" com entidades compartilhadas.
- Fazer
order-serviceatualizar pagamento diretamente. - Reutilizar DTO HTTP de um serviço em outro.
- Tratar bounded context só como organização de pasta.
Resumo
Você definiu fronteiras reais de domínio e registrou responsabilidades no projeto. Essa base evita acoplamento estrutural e torna viável evoluir para eventos sem quebrar autonomia dos serviços.