# Uber DOMA: Como Camadas de Domínio Domaram a Explosão de Microsserviços

Com mais de 2.200 microsserviços e dependências cruzadas incontroláveis, a Uber enfrentava um problema clássico de escala organizacional disfarçado de problema técnico. A resposta foi DOMA — Domain-Oriented Microservice Architecture — uma abordagem que agrupa serviços em domínios, expõe interfaces bem definidas e introduz camadas de abstração para recuperar a coesão perdida. Este teardown reconstrói a arquitetura, analisa as decisões e aponta o que eu faria diferente.

- URL: https://fernando.moretes.com/studies/uber-domain-oriented-microservices

- Markdown: https://fernando.moretes.com/studies/uber-domain-oriented-microservices/study.md?lang=pt

- Type: Teardown

- Company: Uber

- Domain: Microsserviços

- Date: 2020-07-23

- Tags: microservices, domain-driven-design, uber, platform-engineering, architecture, scalability, organizational-design, api-gateway

- Reading time: 7 min

---

Microsserviços prometem autonomia e velocidade. Na prática, sem disciplina estrutural, entregam um grafo de dependências caótico que nenhum engenheiro consegue raciocinar completamente. A Uber chegou a 2.200+ serviços e precisou inventar uma nova camada de organização — não para os computadores, mas para os times.

## Ficha Técnica

- **Empresa:** Uber Technologies
- **Domínio:** Mobilidade urbana, entregas, logística
- **Escala de serviços (pré-DOMA):** ~2.200 microsserviços ativos
- **Publicação do artigo DOMA:** Setembro de 2020
- **Stack principal:** Go, Java, Python; gRPC; Kafka; Cadence (orquestração de workflows)
- **Rede de entrega:** Multi-região, presença global, data centers próprios + nuvem híbrida
- **Problema central:** Acoplamento cruzado incontrolável entre serviços sem fronteiras de domínio claras
- **Solução adotada:** DOMA — Domain-Oriented Microservice Architecture com camadas, gateways e extensões

## O Problema: Quando Microsserviços Viram um Monólito Distribuído

A Uber cresceu de um monólito Python para uma arquitetura de microsserviços ao longo de vários anos, impulsionada pela necessidade de escalar times independentes em múltiplos produtos — Rides, Eats, Freight, ATG. O resultado natural desse crescimento foi uma explosão de serviços: cada time criava o que precisava, quando precisava, sem uma visão global das dependências.

O sintoma mais visível era o que o time de engenharia chamou internamente de *dependency hell*: um serviço de pagamento chamando diretamente um serviço de mapeamento de rotas; um serviço de notificações acoplado a lógica de precificação; ciclos de dependência que tornavam deployments simples em eventos de coordenação complexos. Com 2.200+ serviços, nenhum engenheiro individual conseguia ter um mapa mental confiável do sistema.

O problema não era técnico na raiz — era organizacional. Conway's Law operando em escala máxima: a arquitetura do sistema espelhava a estrutura de comunicação dos times, que por sua vez era caótica porque cresceu organicamente sem uma taxonomia de responsabilidades. A solução precisava atacar os dois lados: estrutura técnica e estrutura organizacional simultaneamente.

Além do acoplamento, havia um problema de descoberta e reuso. Times criavam serviços duplicados porque não sabiam que a funcionalidade já existia em outro lugar. A ausência de um contrato explícito entre serviços significava que qualquer mudança interna podia — e frequentemente causava — quebras em cascata em consumidores que nunca deveriam ter acesso direto àquela implementação.

## Arquitetura DOMA Reconstruída

Visão em camadas da organização de domínios na Uber. Cada domínio expõe uma Layer Interface (gateway) e pode conter sub-domínios. Serviços internos são opacos para consumidores externos ao domínio. Extensões permitem customização sem modificar o núcleo.

### 🌐 Clients & Edge

- Mobile App iOS / Android (user)
- Partner API External Consumers (edge)

### 🚪 API Gateway Layer

- API Gateway Auth / Rate Limit / Routing (edge)

### 🏗️ Domain: Rides

- Rides Layer Interface (Domain Gateway) (frontend)
- Dispatch Service (internal) (compute)
- Driver Matching (internal) (compute)
- Rides Extension (customization hook) (compute)

### 💳 Domain: Payments

- Payments Layer Interface (Domain Gateway) (frontend)
- Billing Service (internal) (compute)
- Fraud Detection (internal) (compute)

### 🗺️ Domain: Maps & ETA

- Maps Layer Interface (Domain Gateway) (frontend)
- Routing Engine (internal) (compute)
- ETA Prediction (internal) (ai)

### 📦 Shared Platform Layer

- Observability Platform Metrics / Tracing / Logs (compute)
- Kafka Event Bus (messaging)
- Cadence Workflow Orchestration (compute)

### 🗄️ Storage Layer (per domain)

- Rides DB (Schemaless / MySQL) (data)
- Payments DB (isolated) (data)
- Maps Cache (Redis / in-memory) (storage)

### Fluxos

- mobile -> apigw: HTTPS
- partner -> apigw: HTTPS
- apigw -> rides_gw: gRPC
- apigw -> pay_gw: gRPC
- apigw -> maps_gw: gRPC
- rides_gw -> dispatch: interno
- rides_gw -> matching: interno
- rides_gw -> rides_ext: extensão
- rides_gw -> maps_gw: via interface
- rides_gw -> pay_gw: via interface
- pay_gw -> billing
- pay_gw -> fraud
- maps_gw -> routing
- maps_gw -> eta
- dispatch -> kafka: eventos
- billing -> kafka: eventos
- cadence -> rides_gw: orquestra
- dispatch -> rides_db
- billing -> pay_db
- routing -> maps_cache
- dispatch -> observability
- billing -> observability

## Como o DOMA Funciona: Domínios, Camadas e Contratos

O DOMA introduz quatro conceitos centrais que, em conjunto, reconstroem a ordem em um ecossistema de microsserviços caótico.

**1. Domínios (Domains):** Um domínio é uma coleção de microsserviços que representam uma área de negócio coesa — Rides, Payments, Maps, Driver, etc. A granularidade não é arbitrária: segue as linhas de responsabilidade dos times (Conway's Law deliberadamente aplicada, não acidental). Cada domínio tem um owner claro, um roadmap independente e uma fronteira de responsabilidade explícita.

**2. Camadas (Layers):** Domínios são organizados em camadas hierárquicas. Camadas inferiores (plataforma, infraestrutura) não podem depender de camadas superiores (produto, experiência). Essa restrição unidirecional é a chave para eliminar ciclos de dependência. Na prática, a Uber definiu camadas como: Infrastructure → Platform → Business Domain → Product → Experience. Um serviço de Maps não pode depender de lógica de Rides; um serviço de Rides pode depender de Maps.

**3. Layer Interface (Gateway de Domínio):** Cada domínio expõe exatamente uma interface pública — o Layer Interface. Serviços internos ao domínio são completamente opacos para o mundo externo. Consumidores externos só podem interagir com o domínio através dessa interface, que funciona como um API Gateway interno. Isso cria um contrato estável: o domínio pode refatorar sua implementação interna livremente, desde que mantenha a interface.

**4. Extensões (Extensions):** Extensões são o mecanismo de customização sem modificação. Em vez de um consumidor fazer fork de um serviço ou adicionar lógica condicional no núcleo ("se produto X, então..."), ele registra uma extensão que é invocada em pontos específicos do fluxo do domínio. É essencialmente o padrão Strategy/Plugin aplicado em escala de plataforma. Isso foi crítico para a Uber porque produtos diferentes (Rides vs. Eats vs. Freight) precisam de comportamentos ligeiramente diferentes nos mesmos domínios base.

A combinação desses quatro elementos cria o que o artigo da Uber chama de "structured modularity" — modularidade com regras de composição explícitas, não apenas decomposição arbitrária. O resultado prático é que o grafo de dependências, antes um espaguete, passa a ter uma topologia de DAG (Directed Acyclic Graph) com camadas bem definidas.

## A Dimensão Organizacional: Por Que Isso É Tanto um Problema de Times Quanto de Código

Um aspecto que o artigo da Uber trata com seriedade e que muitas análises superficiais ignoram: DOMA não é apenas uma reorganização de código. É uma reorganização de responsabilidades e poder de decisão.

Antes do DOMA, qualquer time podia criar dependências em qualquer serviço. Isso parece democrático, mas na prática significava que ninguém era responsável por nada de forma abrangente. O time de Payments não podia refatorar seu serviço de billing sem coordenar com 40 consumidores diretos que tinham acoplamento com detalhes de implementação interna.

Com DOMA, o Layer Interface cria uma fronteira de propriedade clara. O time dono do domínio é o único árbitro de quais funcionalidades são expostas publicamente. Isso tem consequências políticas reais: times de produto que antes podiam "pular a fila" acessando serviços internos diretamente agora precisam negociar adições à interface pública com o time dono. Isso é atrito intencional — o tipo de atrito que força conversas sobre design em vez de gambiarra.

O mecanismo de extensões é particularmente inteligente do ponto de vista organizacional. Ele resolve o problema clássico de plataformas: como um serviço central atende às necessidades divergentes de múltiplos produtos sem se tornar um gargalo ou um acumulador de lógica condicional? A resposta do DOMA é inverter o controle — o domínio define os pontos de extensão, os produtos registram seus comportamentos específicos. O time de plataforma não precisa conhecer todos os casos de uso; os times de produto não precisam de acesso ao núcleo.

Isso também tem implicações para hiring e onboarding. Um engenheiro novo no time de Payments precisa entender apenas o domínio de Payments e suas interfaces com domínios adjacentes — não o sistema inteiro. A complexidade cognitiva é delimitada pela fronteira do domínio. Em um sistema com 2.200 serviços sem essa estrutura, o onboarding efetivo levava meses; com DOMA, o escopo de aprendizado inicial é drasticamente reduzido.

## Matriz de Decisões: Alternativas Consideradas

### DOMA (abordagem adotada)

**Pros**
- Preserva autonomia dos times dentro do domínio
- Contratos explícitos via Layer Interface reduzem acoplamento acidental
- Extensões permitem customização sem modificar núcleo
- Compatível com migração incremental — não exige big bang

**Cons**
- Overhead de governança: quem decide as fronteiras dos domínios?
- Layer Interface pode virar gargalo de latência se mal implementado
- Extensões mal gerenciadas recriam o problema de acoplamento em outro nível

**Verdict:** Melhor equilíbrio para a escala e maturidade organizacional da Uber

### Consolidação em Monólito Modular

**Pros**
- Elimina latência de rede entre serviços do mesmo domínio
- Transações ACID dentro do módulo sem coordenação distribuída

**Cons**
- Inviável para a escala de times da Uber — conflitos de merge, deploys acoplados
- Perde os benefícios de isolamento de falha já conquistados
- Migração de 2.200 serviços para monólito é risco inaceitável

**Verdict:** Rejeitado — retrogredir não resolve o problema organizacional

### Service Mesh Puro (Istio/Envoy) sem reorganização de domínios

**Pros**
- Melhora observabilidade e controle de tráfego sem mudança de código
- Aplica políticas de segurança (mTLS) de forma transparente

**Cons**
- Não resolve o problema de acoplamento lógico — apenas adiciona visibilidade a ele
- Não endereça a questão de ownership e responsabilidade de times

**Verdict:** Complementar, não substituto — necessário mas insuficiente sozinho

### API Management Centralizado (estilo ESB)

**Pros**
- Controle centralizado de contratos e versioning

**Cons**
- Recria o gargalo do ESB — ponto único de falha e bottleneck de deploy
- Vai contra a filosofia de autonomia de times que a Uber já havia conquistado
- Não escala com 2.200 serviços sem fragmentação do próprio ESB

**Verdict:** Rejeitado — antipadrão conhecido para essa escala

## Leitura pelos Pilares Well-Architected

- **security**: **Positivo:** A Layer Interface como único ponto de entrada do domínio cria um perímetro natural para aplicar autenticação, autorização e auditoria. Serviços internos ficam inacessíveis diretamente, reduzindo a superfície de ataque. **Gap identificado:** O artigo não detalha o modelo de autorização entre domínios — em sistemas financeiros, precisaria de controle explícito de quais domínios podem chamar quais interfaces, com auditoria de cada chamada cross-domain. A Uber provavelmente resolve isso via seu service mesh (Envoy + mTLS + RBAC), mas a integração com DOMA não é documentada publicamen
- **reliability**: **Positivo:** O isolamento por domínio limita o blast radius de falhas. Uma degradação no domínio de Maps não propaga diretamente para Payments. As extensões, se implementadas com circuit breakers, permitem que o fluxo principal continue mesmo quando uma customização falha. **Gap:** O Layer Interface introduz um hop adicional em cada chamada cross-domain. Se não for implementado com caching adequado e circuit breakers, pode virar um ponto de falha concentrado. A Uber usa Cadence para workflows de longa duração, o que mitiga falhas transientes, mas a resiliência do próprio gateway de domínio pr
- **performance**: **Trade-off explícito:** DOMA adiciona latência em chamadas cross-domain ao forçar o roteamento pelo Layer Interface em vez de chamadas diretas ponto-a-ponto. Para a Uber, onde latência de matching de motoristas é crítica (centenas de milissegundos fazem diferença na experiência), isso é um custo real. O artigo não quantifica esse overhead. Minha estimativa conservadora é 1-5ms por hop adicional em uma infraestrutura bem otimizada — aceitável para a maioria dos fluxos, mas potencialmente significativo em caminhos críticos com múltiplos saltos de domínio.
- **cost**: **Positivo:** Melhor reuso de serviços reduz duplicação — times param de recriar funcionalidades que já existem em outros domínios. **Negativo:** O Layer Interface de cada domínio precisa ser um serviço de alta disponibilidade, o que significa redundância, monitoramento e manutenção adicionais. Com dezenas de domínios, isso é um custo operacional não trivial. A Uber tem escala para absorver isso; empresas menores precisariam avaliar se o overhead de infraestrutura compensa os ganhos de organização.
- **sustainability**: O reuso de serviços via Layer Interface reduz a proliferação de instâncias redundantes, o que tem impacto positivo em consumo de recursos computacionais. Menos duplicação de código significa menos superfície de manutenção e menor probabilidade de manter serviços zumbi ativos desnecessariamente. Não há dados públicos sobre o impacto de DOMA em eficiência de recursos na Uber.

> **O Que Eu Faria Diferente:** DOMA é uma das contribuições mais honestas e práticas que já vi publicadas sobre arquitetura de microsserviços em escala. Não é teoria — é uma solução que emergiu de dor real. Mas há três pontos onde eu divergiria ou complementaria.

**1. Contratos como artefatos de primeira classe, não como convenção.** O Layer Interface é uma ideia poderosa, mas o artigo da Uber não detalha como os contratos são versionados, testados e evoluídos. Em sistemas financeiros onde trabalhei, a ausência de contract testing explícito (Pact, Protolock para gRPC) significa que "a interface não mudou" é uma promessa baseada em disciplina humana, não em enforcement automatizado. Eu adicionaria contract testing como gate obrigatório no CI/CD de qualquer mudança em um Layer Interface.

**2. O modelo de extensões precisa de um registro centralizado com visibilidade.** Extensões resolvem o problema de customização, mas criam um novo problema de descoberta: quais extensões estão registradas em qual domínio? Quem as possui? Em um sistema com dezenas de domínios e centenas de extensões, isso vira um grafo de dependências de segundo nível. Eu implementaria um registry de extensões com ownership explícito, SLOs e alertas de extensões órfãs.

**3. A dimensão de segurança precisa ser cidadã de primeira classe no modelo.** DOMA define fronteiras organizacionais e técnicas, mas não define fronteiras de segurança explicitamente. Em sistemas com dados sensíveis — e a Uber lida com localização em tempo real, dados de pagamento e informações pessoais — eu mapearia cada Layer Interface com uma classificação de sensibi

## Lições Transferíveis: O Que Qualquer Organização Pode Aprender

DOMA é frequentemente descartado como "coisa de Uber" — uma solução para uma escala que a maioria das empresas nunca atingirá. Essa leitura é equivocada. Os princípios são aplicáveis muito antes de você ter 2.200 serviços.

**A explosão de microsserviços começa cedo.** Na minha experiência, times de 30-50 engenheiros já sofrem com os sintomas que o DOMA resolve: dependências cruzadas não documentadas, duplicação de funcionalidades, onboarding lento. Você não precisa esperar 2.000 serviços para introduzir fronteiras de domínio.

**Comece com o mapa de dependências, não com a reorganização.** Antes de qualquer mudança estrutural, torne visível o que existe. Ferramentas como Backstage (CNCF) ou até um grafo simples gerado a partir dos logs do service mesh revelam os padrões de acoplamento. O mapa é o diagnóstico; DOMA é um tratamento possível.

**O Layer Interface é aplicável mesmo sem microsserviços.** Em monólitos modulares, o mesmo princípio se aplica: módulos expõem interfaces públicas explícitas, implementações internas são privadas. A diferença é que a fronteira é de pacote/módulo em vez de rede. O padrão é agnóstico ao estilo de deployment.

**Extensões são o padrão correto para plataformas internas.** Qualquer time que constrói uma plataforma interna enfrenta o dilema: ser genérico demais (inútil) ou específico demais (não reutilizável). O modelo de extensões do DOMA — define os pontos de variação, deixa os consumidores injetarem o comportamento — é a resposta correta para esse dilema e se aplica independentemente da escala.

## Veredicto

DOMA é uma das contribuições arquiteturais mais substanciais publicadas por uma empresa de tecnologia na última década — não porque seja revolucionária em teoria, mas porque é uma solução honesta e documentada para um problema que a maioria das organizações enfrenta e poucos resolvem de forma sistemática. A combinação de domínios, camadas, Layer Interface e extensões não é apenas uma reorganização técnica: é um framework de governança que alinha estrutura de código, estrutura de times e estrutura de responsabilidades.

Os pontos fracos são reais: overhead de latência nos gateways de domínio, risco de que extensões mal gerenciadas recriem o problema original em outro nível, e ausência de um modelo de segurança explícito integrado ao framework. Mas esses são problemas de implementação, não falhas de design.

O que mais me impressiona no DOMA é o reconhecimento explícito de que arquitetura de software é inseparável de design organizacional. Não há solução técnica para um problema de Conway's Law que não passe também por uma mudança na estrutura de ownership e comunicação dos times. A Uber entendeu isso e construiu uma solução que ataca os dois lados.

Para qualquer engenheiro construi

## Referências

- [Uber Engineering — Microservice Architecture (DOMA)](https://www.uber.com/blog/microservice-architecture/)
- [Martin Fowler — Conway's Law](https://martinfowler.com/bliki/ConwaysLaw.html)
- [CNCF Backstage — Service Catalog](https://backstage.io/)
- [Uber — Cadence Workflow Orchestration](https://cadenceworkflow.io/)
- [AWS Well-Architected Framework](https://aws.amazon.com/architecture/well-architected/)
- [Sam Newman — Building Microservices (2nd ed.)](https://www.oreilly.com/library/view/building-microservices-2nd/9781492034018/)
- [Pact — Consumer-Driven Contract Testing](https://docs.pact.io/)

## Fontes do caso

- [Uber — Microservice Architecture (DOMA)](https://www.uber.com/blog/microservice-architecture/)
