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.

Avançado 40 min 25 pontos Leitura 0%

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

  1. 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.
  1. Definir entidade local no Java (customer-service)
package com.aprendi.customer.domain;

public record Customer(String id, String fullName, String email) {}
  1. Definir entidade local no Python (order-service)
from pydantic import BaseModel

class Order(BaseModel):
    id: str
    customer_id: str
    total_amount: float
    status: str
  1. 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

  1. Subir o ambiente:
docker compose -f infra/docker-compose.yml up --build -d
  1. 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
  1. 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.: PaymentStatus nã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-service atualizar 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.