Para quem pratica DDD (Domain-Driven Design), pode se referir ao conjunto de entidades, agregados, value objects e serviços de domínio que expressam a linguagem ubíqua. Para quem segue Clean Architecture, pode ser tanto as entidades quanto os casos de uso. E para um DBA que trabalha com PostgreSQL, “domínio” pode simplesmente designar um tipo de dado customizado com restrições de validação.
Essa polissemia, quando não reconhecida, gera um ruído semântico que se manifesta como ruído técnico: decisões de arquitetura equivocadas, responsabilidades mal alocadas, fronteiras borradas e conversas que parecem concordar, mas descrevem coisas completamente diferentes. O problema não é apenas terminológico, é estrutural. Quando dois arquitetos discutem sobre “onde deve ficar a lógica de domínio”, eles podem estar falando de conceitos fundamentalmente distintos sem perceber. Um acredita que casos de uso pertencem ao domínio; o outro defende que domínio é apenas regras de negócio puras, sem orquestração. Ambos usam a mesma palavra, mas não compartilham o mesmo conceito.
O filósofo Ludwig Wittgenstein dizia, nas Investigações Filosóficas, que “o significado de uma palavra é o seu uso na linguagem”. A engenharia de software é, antes de tudo, uma linguagem técnica e social, e o termo domínio muda de significado conforme o jogo de linguagem em que é empregado. Não compreender esse jogo é o ponto de partida de muitos conflitos entre times de arquitetura, design e implementação. É também a origem de sistemas mal estruturados, onde a intenção arquitetural original se perde em traduções sucessivas e mal compreendidas.
Há algo de irônico nessa confusão. O DDD surgiu justamente para resolver o problema da comunicação entre desenvolvedores e especialistas de negócio, propondo uma linguagem ubíqua que unificasse ambos os mundos. No entanto, mesmo dentro da comunidade técnica, a palavra central dessa prática domínio não conseguiu escapar da ambiguidade. Talvez porque o conceito seja genuinamente complexo. Ou talvez porque, como acontece frequentemente em nossa disciplina, importamos termos de diferentes tradições sem nos preocupar em alinhar seus significados.
Este artigo não propõe eliminar a polissemia do termo domínio, isso seria impossível e até indesejável. O que propomos é torná-la explícita. Reconhecer que domínio não é uma palavra unívoca, mas um conceito com múltiplas facetas, cada uma útil em seu contexto. Compreender essas facetas é essencial para arquitetos, desenvolvedores e qualquer profissional que precise navegar entre diferentes estilos arquiteturais. A clareza semântica é uma competência de arquitetura tanto quanto o design de APIs ou o particionamento de microsserviços. É o que distingue o arquiteto que apenas codifica de quem constrói linguagem e entendimento compartilhado.
Modelos, abstrações e o gesto de representar
Todo software nasce de um gesto fundamental: o de abstrair. Antes que haja código, há uma tentativa de compreender o mundo e traduzi-lo em forma manipulável. Modelar é criar uma ponte entre a realidade observada e uma realidade construída, um espelho imperfeito, porém útil, que nos permite raciocinar, simular e controlar aspectos do real. Esse movimento de tradução não é trivial: toda abstração carrega uma intenção, uma ênfase, um recorte sobre o que se considera essencial. Quando um engenheiro modela um sistema de e-commerce, ele não busca reproduzir a complexidade total de uma transação comercial como os gestos, as negociações, as emoções, os contextos sociais. Ele constrói uma representação operável, voltada a um propósito específico: processar pedidos, calcular preços, controlar estoque.
“Toda a história da engenharia de software é a ascensão dos níveis de abstração.” — Grady Booch
A frase de Booch sintetiza uma das tendências mais marcantes da engenharia de software: afastar-se do concreto e aproximar-se de camadas conceituais mais expressivas. Da linguagem de máquina aos assemblies, das linguagens estruturadas aos paradigmas orientados a objetos, das arquiteturas monolíticas às orientadas a domínio. O avanço técnico é também um avanço semântico, o esforço contínuo de tornar o pensamento humano dialogável com a máquina. Cada novo nível de abstração é, ao mesmo tempo, um ganho de expressividade e uma nova forma de simplificação. Ganhamos poder de expressão, mas perdemos controle sobre os detalhes de baixo nível. Ganhamos produtividade, mas assumimos mais camadas de indireção.
A abstração é, portanto, uma escolha deliberada: o que manter e o que omitir. Modelar implica decidir quais aspectos do mundo serão preservados e quais serão deixados de fora. Um modelo é tanto uma revelação quanto uma omissão. Quando um engenheiro de software modela um sistema de vendas, ele revela o que considera relevante: clientes, produtos, pedidos, pagamentos e omite o que julga irrelevante, a cor da embalagem, o humor do vendedor, o clima do dia. Essa redução é o que torna o software possível, mas também o que define seus limites de compreensão. Um sistema pode ser extraordinariamente eficiente em processar pedidos, mas completamente cego aos aspectos humanos da venda.
“Um modelo é uma forma de conhecimento simplificada seletivamente e estruturada de modo consciente.” — Eric Evans
A citação de Evans destaca que o ato de modelar não é apenas técnico, mas cognitivo. Um modelo organiza conhecimento, ele é um artefato de entendimento coletivo, não apenas de programação. Por isso, modelar bem é também pensar bem sobre o domínio. O modelo de software não é neutro: ele traduz valores, hipóteses e visões de mundo sobre o que importa representar e como isso deve funcionar. Um modelo de domínio financeiro construído por economistas neoclássicos será diferente de um construído por economistas comportamentais, mesmo que ambos descrevam o mesmo sistema. As premissas sobre racionalidade, risco e comportamento humano moldam a estrutura do modelo.
Ao longo da evolução da disciplina, essa prática se consolidou sob a noção de modelo de domínio: uma representação conceitual do espaço de problemas que o sistema busca resolver. O domínio é, nesse sentido, o universo de significados e regras que antecede o código. É a camada de realidade que o software tenta compreender e automatizar. Essa ideia de que o modelo é uma tradução do real encontra ressonância em uma tradição filosófica muito mais antiga, que remonta a Platão e Aristóteles.
“Tudo o que vemos é apenas uma sombra daquilo que não vemos.” — Platão
Platão via o mundo sensível como uma sombra do mundo das ideias, uma representação imperfeita, mas significativa, da realidade essencial. De certo modo, o engenheiro de software atua como o artesão platônico: cria modelos que são sombras operáveis do real, recortes que capturam o essencial de um fenômeno complexo. A arte da modelagem é, portanto, uma busca pela forma que permanece sob a multiplicidade das aparências. Mas se Platão nos lembra que o modelo é uma sombra, Aristóteles nos ensina que compreender algo exige olhar para suas causas e princípios, isto é, para sua estrutura interna e finalidade.
“Conhecer algo é conhecer suas causas e seus princípios.” — Aristóteles
Modelar o domínio, portanto, é mais do que projetar uma imagem ideal do negócio; é compreender as forças e relações que o tornam inteligível. É buscar o porquê das coisas, suas regras, dependências, propósitos e consequências. A boa modelagem combina a intuição platônica, que busca a essência, com o rigor aristotélico, que busca a explicação. Quando um time de desenvolvimento partilha essa dupla compreensão, ele constrói um domínio verdadeiramente compartilhado: uma linguagem comum que reflete tanto a forma quanto a causa das coisas. O “domínio” não é, portanto, o software em si, mas o contexto que dá sentido ao software. Ele é o ponto de contato entre duas racionalidades: a do mundo real e a da máquina.
A origem conceitual: o domínio como realidade de negócio
Historicamente, domínio surge na engenharia de software como a tradução de problem domain — o espaço conceitual que o software busca modelar. Trata-se do mundo real, com suas entidades, regras e processos, que o sistema tenta representar. Quando um analista descreve um fluxo de pedido em uma pizzaria, ele está mergulhando no domínio do problema, antes de pensar em qualquer camada de código, antes de escolher uma linguagem de programação ou framework. Esse é o domínio pré-técnico, a realidade que precede qualquer decisão de implementação.
“O coração do software está em sua capacidade de resolver problemas relacionados ao domínio para o usuário.” — Eric Evans
Evans nos lembra que o software não existe para si mesmo, ele existe para resolver problemas reais de pessoas reais. O domínio é o espaço onde esses problemas vivem. É o contexto do cliente que encomenda a pizza, do cozinheiro que precisa organizar os pedidos, do entregador que precisa otimizar rotas. Cada um desses atores tem seu próprio modelo mental do domínio, sua própria linguagem, suas próprias prioridades. O trabalho do engenheiro de software é compreender esses modelos mentais diversos e traduzi-los em uma representação computacional coerente. Isso não é trivial. Exige observação, diálogo, empatia e a capacidade de abstrair sem perder a essência.
Essa raiz conceitual é essencial e frequentemente esquecida. O domínio é o mundo que existe antes do software, e o papel do engenheiro é compreender e abstrair essa realidade. Quando o domínio é reduzido a uma camada de código, quando “domínio” se torna apenas um nome de pasta em um projeto, perde-se a ponte entre a abstração e o real. É aqui que nasce a primeira distorção: confundir “domínio” com “código”, esquecendo que, originalmente, ele é uma linguagem compartilhada sobre o negócio. Um desenvolvedor pode criar classes elegantes, seguir todos os princípios SOLID, aplicar padrões de design sofisticados e ainda assim falhar completamente em representar o domínio se não compreender o negócio.
Essa confusão tem consequências práticas graves. Em um projeto que acompanhei, uma equipe de desenvolvedores criou um sistema de gestão de estoque baseado em suas próprias suposições sobre como estoques funcionam. Eles nunca conversaram com os operadores de armazém, nunca foram até o depósito, nunca observaram como os produtos eram movimentados fisicamente. O resultado foi um sistema tecnicamente impecável, mas praticamente inútil. As abstrações não correspondiam à realidade. O “domínio” que eles modelaram era uma ficção, uma fantasia de como achavam que as coisas deveriam funcionar. Quando o sistema foi implantado, os operadores simplesmente o ignoraram e voltaram às planilhas. O problema não era técnico, era de compreensão do domínio.
“Relacionar intimamente o código a um modelo subjacente dá significado ao código e torna o modelo relevante.” — Eric Evans
Quando o código reflete fielmente o domínio, algo mágico acontece: o software se torna compreensível não apenas para desenvolvedores, mas para especialistas de negócio. A lógica do código espelha a lógica do negócio. Os nomes das classes correspondem aos conceitos do domínio. As relações entre objetos refletem as relações do mundo real. Isso não é apenas uma questão estética, é uma questão de sustentabilidade. Um sistema que reflete bem seu domínio é mais fácil de manter, mais fácil de evoluir, mais fácil de explicar para novos membros da equipe.
O domínio, portanto, não é um detalhe de implementação, é o fundamento conceitual sobre o qual toda a arquitetura repousa. Negligenciar a compreensão do domínio é construir sobre areia. E muitos projetos de software fracassam não porque a tecnologia é inadequada, não porque os desenvolvedores são incompetentes, mas porque o domínio nunca foi verdadeiramente compreendido. O código pode compilar, os testes podem passar, o sistema pode até entrar em produção, mas se ele não resolve os problemas reais do domínio, ele falhou em sua missão essencial.
O domínio na engenharia de negócios e a fragmentação organizacional
Em arquitetura corporativa, o termo ganha outro contorno: business domain. Ele passa a designar uma área de responsabilidade organizacional: finanças, vendas, logística, RH, marketing e não um módulo de software. Essa separação conceitual é produtiva e reflete a maneira como organizações complexas se estruturam. Empresas de grande porte naturalmente se dividem em domínios de negócio para distribuir responsabilidades, estabelecer métricas de performance e facilitar a governança. Cada domínio tem seus próprios objetivos, seus próprios indicadores de sucesso, sua própria linguagem e cultura.
A empresa pode ter um “domínio financeiro” com contadores, analistas financeiros e controladores; um “domínio de vendas” com representantes comerciais, gerentes de conta e equipes de prospecção; um “domínio de logística” com planejadores de transporte, gestores de armazém e analistas de supply chain. Mas o software que modela esses domínios possui uma estrutura diferente: “módulos de domínio” com entidades, regras de negócio e serviços. São níveis distintos de abstração, mas frequentemente confundidos em reuniões entre analistas de negócio e desenvolvedores. O ruído aqui é institucional: o vocabulário do negócio e o vocabulário técnico colidem, e cada lado acredita estar falando sobre a mesma coisa.
Presenciei uma reunião memorável em uma grande corporação financeira onde esse ruído se manifestou de forma dramática. O diretor de negócios falava sobre a necessidade de “integrar o domínio de crédito com o domínio de cobrança”. Os arquitetos de software entenderam que era preciso criar uma interface entre dois módulos de código. Semanas de trabalho depois, quando apresentaram a solução técnica, o diretor ficou perplexo: ele não queria integração de sistemas, queria integração de processos de negócio, alinhamento de KPIs, compartilhamento de informações entre equipes. O problema não era técnico, era organizacional. Mas porque ambos os lados usaram a palavra “domínio”, assumiram que estavam falando da mesma coisa. O custo desse mal-entendido foi significativo: retrabalho, frustração e desconfiança mútua.
Essa ambiguidade não é acidental, ela reflete uma tensão fundamental na engenharia de software empresarial. Como Conway observou em sua famosa lei, “organizações que projetam sistemas estão limitadas a produzir designs que copiam as estruturas de comunicação dessas organizações”. Os domínios de negócio influenciam a arquitetura de software, mas não de forma direta ou óbvia. A tradução entre domínio organizacional e domínio técnico é complexa e mediada por dezenas de fatores: política interna, restrições tecnológicas, legados históricos, competências das equipes.
“Informação dispersa não pode ser centralizada; por isso, sistemas econômicos dependem de mecanismos de coordenação descentralizados.” — Friedrich Hayek
Embora Hayek falasse de mercados econômicos, sua observação sobre informação dispersa aplica-se perfeitamente a grandes organizações. O conhecimento sobre o domínio de negócio está distribuído por dezenas ou centenas de pessoas, especialistas que entendem profundamente seus nichos, mas têm visão limitada do todo. Quando tentamos centralizar esse conhecimento em um modelo de software único e coerente, enfrentamos um desafio epistemológico: como capturar conhecimento que não existe em forma explícita, que está incorporado em práticas, intuições e experiências?
A fragmentação organizacional, portanto, não é apenas um problema de gestão, é um problema de modelagem de domínio. Cada departamento tem sua própria visão do que constitui o “domínio financeiro” ou o “domínio de vendas”. Essas visões são parciais, às vezes conflitantes, frequentemente implícitas. O papel do arquiteto de software é navegar essa fragmentação, identificar sobreposições e contradições, e construir modelos que sejam coerentes sem serem reducionistas. É um trabalho que exige tanto habilidade técnica quanto sensibilidade política.
O domínio em DDD: o coração semântico do software
Eric Evans, em Domain-Driven Design: Tackling Complexity in the Heart of Software (2003), propõe o domínio como o centro do design. Ele não é apenas uma camada técnica, mas o núcleo de significado do sistema. As entidades, value objects, agregados e serviços de domínio são expressões codificadas da linguagem ubíqua (Ubiquitous Language) compartilhada com o negócio. O DDD é, antes de tudo, uma filosofia de design que coloca o domínio e a compreensão profunda do domínio como a prioridade máxima do desenvolvimento de software.
“Ouça a linguagem que os especialistas do domínio usam. Existem termos que expressam de forma sucinta algo complicado? Eles estão corrigindo suas escolhas de palavras (talvez de maneira diplomática)? As expressões de confusão nos rostos deles desaparecem quando você usa uma determinada frase? Esses são indícios de um conceito que pode ser útil para o modelo.” — Eric Evans
Evans não está falando apenas de nomenclatura de classes ou variáveis. Ele está descrevendo um processo de descoberta conceitual. A linguagem que os especialistas de domínio usam carrega anos de experiência destilada, convenções estabelecidas, distinções sutis que importam. Quando um especialista financeiro diz “provisão” em vez de “reserva”, ou quando um médico diz “sintoma” em vez de “sinal”, essas diferenças têm significado. Ignorá-las é perder nuances importantes do domínio. Capturá-las no modelo é aproximar o software da realidade que ele pretende representar.
O DDD transforma o domínio em uma ontologia prática, onde cada termo reflete um conceito do negócio. Aqui, o domínio é semântico e social antes de ser técnico. Não é suficiente que o código funcione, ele precisa fazer sentido. Precisa ser legível para alguém que conheça o domínio. Um especialista de negócio deveria conseguir olhar para o código de domínio (mesmo sem conhecer a sintaxe da linguagem de programação) e reconhecer os conceitos, as regras, as relações. Isso é ambicioso, talvez utópico, mas é o ideal que o DDD persegue.

Quando equipes reduzem o “domínio” à pasta /domain do projeto, o espírito do DDD se perde e a promessa de alinhar código e negócio vira apenas uma convenção de diretórios. Vi isso acontecer repetidas vezes: equipes que adotam a estrutura superficial do DDD sem abraçar sua filosofia. Criam entidades, agregados, repositórios, toda a parafernália tática do DDD, mas sem linguagem ubíqua, sem modelagem colaborativa, sem iteração constante com especialistas de domínio. O resultado é um simulacro de DDD, uma casca vazia que parece sofisticada mas não entrega os benefícios prometidos.
O verdadeiro poder do DDD não está em suas ferramentas táticas: agregados, especificações, eventos de domínio. Está no mindset de colocar o domínio no centro de todas as decisões. Quando surge uma dúvida arquitetural, a pergunta não é “qual padrão devo usar?” mas “o que o domínio exige?”. Quando surge um conflito entre performance e clareza de modelo, a primeira pergunta é “estamos modelando corretamente?”, não “como otimizamos essa query?”. Isso não significa ignorar restrições técnicas, significa priorizá-las corretamente.
“O coração do software está em sua capacidade de resolver problemas relacionados ao domínio para o seu usuário.” — Eric Evans
Evans repete esse mantra porque ele vai contra a tendência natural dos desenvolvedores: focar em desafios técnicos interessantes em vez de problemas de negócio importantes. É mais divertido otimizar um algoritmo, experimentar um novo framework, debater padrões de concorrência, do que sentar com um especialista de domínio e entender como funciona o processo de aprovação de crédito. Mas é na compreensão profunda do domínio que reside o valor real do software. Um sistema tecnicamente medíocre que resolve bem os problemas do domínio é mais valioso que um sistema tecnicamente brilhante que erra o alvo.
Arquitetura Hexagonal: o domínio como núcleo isolado
A Arquitetura Hexagonal, também conhecida como Ports and Adapters, foi proposta por Alistair Cockburn no início dos anos 2000 como uma resposta a um problema comum: sistemas onde a lógica de negócio estava tão emaranhada com frameworks, bancos de dados e interfaces de usuário que se tornava impossível testá-la isoladamente ou mudá-la sem refatorações massivas. A arquitetura hexagonal propõe uma separação radical: o núcleo da aplicação, o domínio, deve ser completamente independente de qualquer detalhe técnico externo.
“Permita que uma aplicação seja igualmente controlada por usuários, programas, testes automatizados ou scripts em lote, e que possa ser desenvolvida e testada de forma isolada de seus dispositivos e bancos de dados de execução finais.” — Alistair Cockburn

Essa citação captura a essência da proposta: o domínio deve ser agnóstico quanto a como ele é acionado ou onde ele persiste dados. Se você pode testar sua lógica de negócio sem levantar um banco de dados, sem iniciar um servidor web, sem frameworks pesados, você alcançou o ideal hexagonal. O domínio comunica-se com o mundo externo através de “portas” (interfaces abstratas) e “adaptadores” (implementações concretas dessas interfaces). Isso inverte a dependência: não é o domínio que depende da infraestrutura, é a infraestrutura que se adapta ao domínio.
Na prática, isso significa que o “domínio” na arquitetura hexagonal é o código que contém entidades de negócio, regras de negócio e, dependendo da interpretação, também casos de uso ou serviços de aplicação. Aqui começa uma das ambiguidades: diferentes praticantes da arquitetura hexagonal posicionam os casos de uso de formas diferentes. Alguns os colocam dentro do núcleo hexagonal, outros os colocam em uma camada intermediária entre o núcleo e os adaptadores. Essa ambiguidade não é acidental, reflete tensões reais sobre o que constitui “lógica de domínio pura” versus “lógica de aplicação”.
Trabalhei em um projeto onde essa tensão se manifestou claramente. Tínhamos um caso de uso “ProcessarPedido” que orquestrava várias entidades de domínio, fazia chamadas a serviços externos de pagamento e enviava notificações por email. A pergunta surgiu: isso pertence ao domínio? Alguns argumentaram que sim, porque é lógica essencial do negócio. Outros argumentaram que não, porque orquestração e integração com serviços externos é responsabilidade de aplicação, não de domínio. Ambos os lados tinham razão dependendo de como você define “domínio” na arquitetura hexagonal.
A força da arquitetura hexagonal está em sua clareza sobre dependências: o domínio não pode depender de nada externo. Mas ela deixa em aberto questões importantes sobre granularidade e responsabilidades. O que exatamente vai dentro do hexágono? Apenas entidades e regras de negócio puras? Ou também a coordenação entre essas entidades? E os serviços de domínio que implementam regras que não cabem naturalmente em uma única entidade? E os eventos de domínio? Cockburn fornece princípios, mas não prescrições detalhadas, o que é tanto uma força (flexibilidade) quanto uma fraqueza (ambiguidade).
O grande insight da arquitetura hexagonal é tratar todas as interfaces externas: UI, banco de dados, mensageria, APIs de terceiros como adaptadores equivalentes. Não há privilégio especial para o banco de dados. Ele é apenas mais um detalhe técnico, substituível, secundário. Essa é uma inversão mental poderosa que liberta o desenvolvedor para pensar primeiro no domínio, e só depois em como persistir, exibir ou comunicar os resultados. O domínio hexagonal é soberano: ele define interfaces que o mundo externo deve implementar, não o contrário.
Onion Architecture: o domínio como centro absoluto
A Onion Architecture, proposta por Jeffrey Palermo em 2008, é uma evolução da arquitetura hexagonal com ênfase ainda maior na pureza do domínio. A metáfora da cebola é deliberada: camadas concêntricas onde o domínio fica no centro mais interno, completamente protegido, e cada camada externa adiciona responsabilidades progressivamente mais técnicas e menos conceituais. A regra fundamental é simples e inflexível: dependências sempre apontam para dentro, nunca para fora.

O domínio na Onion é o miolo da cebola, contendo exclusivamente entidades de negócio, value objects e regras de domínio puras. Ao redor dele vem a camada de serviços de domínio, depois a camada de aplicação (que contém casos de uso e orquestração), e finalmente a camada de infraestrutura (persistência, UI, APIs externas). Essa hierarquia é mais prescritiva que a arquitetura hexagonal. Não há ambiguidade sobre onde os casos de uso ficam: eles estão fora do domínio, na camada de aplicação.
Essa separação rígida tem implicações filosóficas. O domínio em Onion representa a essência platônica do negócio, as verdades imutáveis, as regras fundamentais que permaneceriam verdadeiras mesmo se mudássemos completamente a tecnologia, o banco de dados, a interface. Uma regra como “um pedido não pode ser finalizado se tiver itens com estoque insuficiente” é uma verdade do domínio, independente de como implementamos o sistema. Já uma regra como “ao finalizar um pedido, enviar email de confirmação e atualizar o cache distribuído” é lógica de aplicação, importante, mas não essencial ao domínio.
Essa distinção parece elegante na teoria, mas é desafiadora na prática. Poucos domínios têm regras verdadeiramente platônicas, independentes de contexto. A maioria das regras de negócio é contingente, contextual, cheia de exceções e casos especiais. Considere uma regra aparentemente simples: “desconto máximo permitido é 20%”. Isso parece uma regra de domínio pura. Mas então surgem exceções: gerentes podem aprovar até 30%, diretores até 50%, e para clientes VIP não há limite. A regra pura se dissolve em política organizacional e hierarquia. O que era domínio se torna aplicação.
Apesar dessas dificuldades, a Onion Architecture oferece um ideal regulador valioso. Ela nos força a perguntar constantemente: “isso é realmente parte do domínio, ou é apenas lógica de aplicação disfarçada?”. Essa pergunta disciplina o pensamento arquitetural. Evita que o domínio se torne um cesto de lixo onde jogamos toda lógica que não sabemos onde colocar. Mantém o núcleo enxuto, focado, compreensível.
Trabalhei em um sistema financeiro onde levamos a Onion Architecture ao extremo. O núcleo de domínio tinha zero dependências externas, nem mesmo de bibliotecas de terceiros para manipulação de datas ou decimais. Usávamos apenas tipos primitivos e construções da linguagem. Isso tornou o domínio trivialmente testável e portável. Mas o custo foi alto: muito código boilerplate, reinvenção de estruturas básicas, complexidade para converter entre tipos de domínio e tipos de infraestrutura. A pureza tinha um preço.
A lição que aprendi é que a Onion Architecture funciona melhor como filosofia do que como dogma. O espírito proteger o domínio de dependências técnicas, manter regras de negócio isoladas e testáveis é mais importante que a estrutura literal de camadas concêntricas. Às vezes, pragmatismo exige comprometer a pureza. A chave é fazer isso conscientemente, sabendo que está assumindo dívida arquitetural, e documentando as razões.
Clean Architecture: o domínio dividido em dois
Robert C. Martin, conhecido como Uncle Bob, sintetizou várias ideias arquiteturais em sua proposta de Clean Architecture, apresentada no livro homônimo. A Clean Architecture não inventa conceitos radicalmente novos, mas organiza-os de forma pedagógica e prescreve regras claras. Seu diagrama de círculos concêntricos tornou-se icônico, representando visualmente a hierarquia de dependências: camadas externas (frameworks, bancos de dados, UI) dependem de camadas internas (casos de uso, entidades), nunca o contrário.

O que distingue a Clean Architecture é sua divisão explícita do “domínio” em duas camadas:
- Entities (Enterprise Business Rules) — Regras de negócio de nível mais alto, geralmente genéricas e reutilizáveis por múltiplas aplicações. São as regras fundamentais da organização.
- Use Cases (Application Business Rules) — Regras específicas de uma aplicação particular, que orquestram as entidades para realizar tarefas concretas.
“As entidades encapsulam as regras de negócio de toda a empresa. Uma entidade pode ser um objeto com métodos ou um conjunto de estruturas de dados e funções. Isso não importa, desde que as entidades possam ser usadas por muitas aplicações diferentes dentro da organização.” — Robert C. Martin
Essa citação esclarece que entidades não são simplesmente classes de domínio, elas encapsulam regras de negócio que transcendem aplicações individuais. Se sua empresa tem múltiplos sistemas que lidam com “Cliente” ou “Produto”, a definição de Cliente ou Produto como entidade deveria ser compartilhável entre esses sistemas. Isso é ambicioso e raramente alcançado na prática, mas revela a intenção de Martin: distinguir entre conhecimento de negócio duradouro (entidades) e lógica de aplicação transitória (casos de uso).
A subdivisão do domínio em entidades + casos de uso é tanto um esclarecimento quanto uma fonte de confusão. Esclarece porque explicita que nem toda lógica importante é “lógica de domínio pura”, há lógica de aplicação que é igualmente importante mas tem natureza diferente. Confunde porque agora “domínio” pode significar ambas as camadas (entidades + casos de uso) ou apenas a camada de entidades, dependendo de quem você pergunta.
Quando alguém diz “estou trabalhando na camada de domínio” em um projeto que segue Clean Architecture, é ambíguo: está trabalhando em entidades? Em casos de uso? Em ambas? Essa ambiguidade só é resolvida por convenção explícita da equipe. Algumas equipes chamam a camada de entidades de “domínio” e a camada de casos de uso de “aplicação”. Outras chamam ambas coletivamente de “domínio”, distinguindo entre “domínio core” e “domínio aplicacional”. Outras ainda evitam o termo “domínio” completamente, usando apenas “entidades” e “casos de uso”.
“Nada em um círculo interno pode saber qualquer coisa sobre algo em um círculo externo. Em particular, o nome de algo declarado em um círculo externo não deve ser mencionado pelo código em um círculo interno. Isso inclui funções, classes, variáveis ou qualquer outra entidade de software nomeada.” — Robert C. Martin
A Regra de Dependência é absoluta e não negociável em Clean Architecture. Ela garante que mudanças em camadas externas (escolher um novo framework web, mudar de banco de dados relacional para NoSQL) não afetem camadas internas. As entidades não sabem nada sobre persistência. Os casos de uso não sabem nada sobre HTTP. Isso é inversão de dependência aplicada sistematicamente a toda a arquitetura.
A força da Clean Architecture está em sua clareza didática. É relativamente fácil explicar seus princípios para desenvolvedores júniors e mantê-los alinhados. O diagrama dos círculos concêntricos se torna uma linguagem visual compartilhada. A fraqueza está em sua rigidez: às vezes as fronteiras são forçadas, gerando muito código de tradução entre camadas. Mas como toda arquitetura principled, a Clean Architecture prioriza evolvabilidade de longo prazo sobre conveniência de curto prazo.
DDD, Hexagonal, Onion, Clean: variações de um tema
Chegamos ao ponto onde precisamos confrontar uma pergunta incômoda: essas arquiteturas são realmente diferentes, ou apenas usam terminologia diferente para descrever essas ideias? A resposta é: ambas as coisas. Elas compartilham uma filosofia fundamental, isolar a lógica de negócio de detalhes técnicos, mas divergem em prescrições, fronteiras e ênfases. E essas divergências importam quando times precisam decidir concretamente onde colocar código.

Considere um serviço que processa pagamentos. Ele precisa:
- Validar o pedido
- Verificar disponibilidade de estoque
- Calcular impostos e descontos
- Chamar gateway de pagamento externo
- Persistir transação no banco de dados
- Enviar email de confirmação
- Publicar evento para atualizar analytics
Agora pergunte a praticantes de cada arquitetura: “onde vai cada pedaço desse fluxo?”. Você receberá respostas diferentes:
DDD puro diria: validação, cálculo de impostos e regras de negócio ficam em entidades e serviços de domínio. Chamada ao gateway e envio de email são serviços de aplicação que usam o domínio. Persistência é implementada por repositórios (cuja interface é definida no domínio, mas implementada na infraestrutura).
Hexagonal diria: tudo que é lógica de negócio vai no hexágono central. Chamada a gateway externo e persistência são adaptadores. Email pode ser adapter ou parte do hexágono dependendo se consideramos “notificar cliente” uma regra de negócio ou detalhe técnico.
Onion seria mais rígida: validação e cálculos ficam no núcleo de domínio. Orquestração do fluxo completo fica na camada de aplicação. Gateway, persistência e email são todos infraestrutura, na camada mais externa.
Clean seria similar a Onion, mas explicitaria: validação de regras de negócio nas entidades, orquestração no caso de uso “ProcessarPagamento”, gateway e email como implementações de interfaces definidas na camada de casos de uso.
Essas não são diferenças triviais. Elas afetam como organizamos código, como testamos, como distribuímos responsabilidades na equipe. Um desenvolvedor vindo de um projeto Hexagonal vai estranhar um projeto Onion porque o que ele chamava de “domínio” foi subdividido em “domínio core” e “aplicação”. Um desenvolvedor acostumado com Clean Architecture vai sentir falta da distinção explícita entre entidades e casos de uso em um projeto Hexagonal.
O que essas arquiteturas têm em comum é mais fundamental que suas diferenças: todas reconhecem que dependências devem apontar para dentro, que lógica de negócio deve ser isolada de detalhes técnicos, que testabilidade requer independência de infraestrutura. Esses são princípios universais. As diferenças estão em como materializar esses princípios: quantas camadas? Onde traçar as fronteiras? Quão rígidas devem ser as regras?
A tragédia é quando times brigam sobre essas diferenças sem reconhecer o acordo fundamental. Vi discussões acaloradas sobre se casos de uso “pertencem ao domínio” que consumiram horas de reunião. No fim, era uma disputa semântica. Ambos os lados concordavam que lógica de negócio deve ser isolada e testável. Discordavam apenas sobre rótulos. Se tivessem reconhecido isso, poderiam ter estabelecido uma convenção e seguido em frente.
“O mapa não é o território.” — Alfred Korzybski
Essa frase do engenheiro e filósofo Alfred Korzybski nos lembra que arquiteturas são mapas, não territórios. São modelos, não realidades. O valor de um mapa está em sua utilidade, não em sua verdade absoluta. Diferentes mapas servem propósitos diferentes. Um mapa rodoviário é diferente de um mapa topográfico, que é diferente de um mapa político. Todos representam o mesmo território, mas enfatizam aspectos diferentes. Da mesma forma, DDD, Hexagonal, Onion e Clean são mapas diferentes do mesmo território: a organização de código para proteger lógica de negócio. Escolha o mapa que melhor serve seu propósito, mas não confunda o mapa com o território.
O domínio técnico: quando o banco de dados entra na conversa
Até agora discutimos domínio em contextos de arquitetura de software e modelagem de negócio. Mas há outro uso do termo, completamente distinto e frequentemente esquecido: domínio em bancos de dados relacionais. Em SQL, especialmente em PostgreSQL, Oracle e outros sistemas robustos, você pode criar um DOMAIN, um tipo de dado customizado com restrições específicas.
CREATE DOMAIN email AS VARCHAR(255)
CHECK (VALUE ~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\\.[A-Za-z]{2,}$');
CREATE TABLE usuarios (
id SERIAL PRIMARY KEY,
email_contato email NOT NULL
);
Neste exemplo, email é um domínio, não no sentido de DDD ou arquitetura, mas no sentido de SQL: um tipo de dado com regras de validação embutidas. Isso nada tem a ver com modelar o negócio ou isolar lógica. É puramente uma construção de esquema de banco de dados, uma forma de reutilizar definições de tipos e garantir consistência de dados.
Esse uso técnico do termo “domínio” é completamente ortogonal aos outros. Quando um DBA fala de “criar domínios no banco”, ele está falando de tipos de dados. Quando um arquiteto de software fala de “modelar o domínio”, está falando de lógica de negócio. Mesma palavra, universos semânticos distintos. E essa colisão terminológica gera confusões reais.
Participei de uma reunião onde um arquiteto de software sugeriu “modelar o domínio no banco de dados”. Ele queria dizer: criar um schema rico que refletisse as entidades e relações do domínio de negócio. O DBA entendeu: criar DOMAINs SQL para tipos customizados. Levou meia hora de conversa cruzada até que alguém percebesse que estavam usando a mesma palavra com significados completamente diferentes. Ambos saíram frustrados, achando que o outro não entendia o básico.
Essa colisão terminológica não é acidente. Reflete uma tensão histórica na engenharia de software entre duas escolas de pensamento: a que vê o banco de dados como centro do sistema (data-centric design) e a que vê a lógica de aplicação como centro (domain-centric design). Na abordagem data-centric, que dominou a indústria nos anos 80 e 90, o schema do banco é o modelo. As regras de negócio são expressas em constraints, triggers e stored procedures. O “domínio” (no sentido de lógica de negócio) vive no banco de dados.
Na abordagem domain-centric, que ganhou força com a ascensão do DDD e das arquiteturas modernas, o banco de dados é apenas um detalhe de persistência. O domínio vive no código da aplicação, em objetos ricos com comportamento. O banco de dados é burro, um armazenamento glorificado de bytes. As regras de negócio são expressas em código, não em SQL.
Essas duas filosofias são fundamentalmente incompatíveis, e a palavra “domínio” é usada por ambas. Um defensor do domain-centric dirá: “o domínio deve ser independente do banco de dados”. Um defensor do data-centric dirá: “o domínio está no banco de dados, é onde as regras são enforçadas”. Ambos usam “domínio”, mas significam coisas opostas.
“A assimetria de informação impede uma coordenação ideal.” — George Akerlof
Akerlof ganhou o Nobel de Economia em parte por seu trabalho sobre mercados com informação assimétrica. Quando vendedores sabem mais que compradores (ou vice-versa), mercados funcionam mal. A mesma dinâmica ocorre em times de desenvolvimento com assimetria semântica. Quando arquitetos e DBAs usam o mesmo termo com significados diferentes, “trocas” de comunicação geram valor sub-ótimo. Decisões são tomadas baseadas em entendimentos equivocados. Códigos refletem compromissos que ninguém realmente queria.
A solução não é padronizar o vocabulário, é impossível forçar DBAs a parar de usar “domínio” no sentido SQL. A solução é consciência semântica: reconhecer que a palavra é sobrecarregada e sempre esclarecer o contexto. Quando digo “domínio”, estou falando de tipo SQL ou de lógica de negócio? Essa pequena clarificação previne horas de confusão.
O domínio como construção linguística e social
“Os limites da minha linguagem significam os limites do meu mundo.” — Ludwig Wittgenstein
Wittgenstein, nas Investigações Filosóficas, propõe que significado não é algo intrínseco às palavras, mas emerge de seu uso em contextos sociais, “jogos de linguagem”, como ele os chama. A engenharia de software é um jogo de linguagem complexo, com múltiplos sub-jogos (DDD, arquitetura de sistemas, administração de bancos de dados, engenharia de negócios). O termo “domínio” participa de vários desses sub-jogos, assumindo significados ligeiramente diferentes em cada um.
Quando um praticante de DDD usa “domínio”, ele está jogando o jogo de linguagem do design orientado a domínio, onde termos como “entidade”, “agregado”, “bounded context” têm significados específicos estabelecidos por convenção comunitária. Quando um arquiteto empresarial usa “domínio de negócio”, está jogando o jogo de linguagem da arquitetura corporativa, onde termos como “capacidade”, “processo ponta-a-ponta”, “matriz de responsabilidades” são relevantes. Esses jogos se sobrepõem, mas não são idênticos.
A linguagem ubíqua do DDD é uma tentativa de criar um jogo de linguagem compartilhado entre desenvolvedores e especialistas de negócio. É um esforço consciente de alinhar semântica, estabelecer um vocabulário comum onde “pedido”, “cliente”, “pagamento” significam precisamente a mesma coisa para todos os participantes. Isso é difícil. Desenvolvedores têm vícios de linguagem técnica; especialistas de negócio usam termos de forma coloquial e ambígua. A linguagem ubíqua exige disciplina de ambos os lados.
“A ação comunicativa busca entendimento mútuo, não apenas sucesso estratégico.” — Jürgen Habermas
Habermas, filósofo da Escola de Frankfurt, distingue entre comunicação orientada a entendimento e comunicação orientada a manipulação. No contexto de times de desenvolvimento, isso se traduz em: estamos realmente tentando nos entender, ou apenas tentando vencer argumentos? Quando um arquiteto e um desenvolvedor debatem sobre onde colocar certa lógica, estão tentando chegar a um entendimento compartilhado sobre a melhor estrutura arquitetural? Ou cada um está tentando impor sua visão?
A polissemia de “domínio” se torna problemática quando a comunicação não é orientada a entendimento. Se as pessoas assumem que suas definições são óbvias e universais, se não fazem esforço para esclarecer contexto, se interpretam discordância como incompetência em vez de diferença semântica, então o termo se torna fonte de conflito em vez de clareza.
Trabalhei em um time onde essa dinâmica chegou a um ponto crítico. Tínhamos desenvolvedores de backgrounds diferentes: alguns vinham de projetos hexagonais, outros de projetos DDD puros, outros de sistemas legados sem arquitetura clara. Quando discutíamos arquitetura, usávamos “domínio” constantemente, mas cada pessoa tinha uma imagem mental diferente. As discussões eram frustradas e improdutivas até que fizemos um workshop explícito: passamos quatro horas desenhando diagramas, comparando definições, estabelecendo glossário compartilhado. Foi tedioso, mas transformador. Depois disso, nossas discussões arquiteturais se tornaram substantivas, não semânticas.
A lição é que linguagem compartilhada não emerge espontaneamente, ela precisa ser construída intencionalmente. Times de alto desempenho investem tempo em alinhar semântica. Criam glossários. Desenham diagramas juntos. Revisam nomenclaturas. Questionam termos ambíguos. Isso pode parecer overhead, mas é investimento. Cada hora gasta alinhando linguagem economiza dezenas de horas de confusão posterior.
O “domínio” no sentido mais profundo não é código, não é documentação, não é UML, é o entendimento compartilhado que existe na mente coletiva do time. Quando esse entendimento é forte e alinhado, o código reflete-o naturalmente. Quando é fraco e fragmentado, nenhuma arquitetura sofisticada salva o projeto. A arquitetura de software é, fundamentalmente, a arquitetura de entendimento.
A falácia do domínio genérico e o anti-DDD
Uma das distorções mais comuns no uso do termo “domínio” é o que podemos chamar de domínio genérico ou domínio anêmico: uma camada rotulada como “domínio” que contém pouco mais que POJOs (Plain Old Java Objects), DTOs (Data Transfer Objects) ou entidades sem comportamento. Essas classes geralmente têm apenas getters e setters, sem lógica de negócio. Toda a lógica real vive em “serviços” que manipulam essas estruturas de dados passivas.
Essa prática nasce da importação acrítica de termos, usar a palavra “domínio” porque parece arquiteturalmente correta, porque é o que frameworks populares esperam, porque todo mundo está fazendo. Mas sem entender o que o termo implica conceitualmente. O resultado é um simulacro de modelagem de domínio: a aparência de arquitetura sofisticada sem a substância.
“O modelo de domínio anêmico é um design de estilo procedural, exatamente o tipo de coisa contra a qual fanáticos por orientação a objetos como eu (e Eric Evans) vêm lutando desde os nossos primeiros dias em Smalltalk.” — Martin Fowler
Martin Fowler cunhou o termo “Anemic Domain Model” e argumentou fortemente contra ele. O modelo anêmico viola princípios fundamentais de orientação a objetos: encapsulamento, coesão entre dados e comportamento. Mais importante, viola o espírito do DDD, que vê entidades como objetos ricos com comportamento, não como estruturas de dados passivas.
Por que o domínio anêmico é tão comum? Várias razões. Primeiro, é mais fácil. Não exige pensar profundamente sobre onde vai a lógica, tudo vai em serviços. Segundo, muitos frameworks (especialmente ORMs como Hibernate ou Entity Framework) incentivam esse design, tratando entidades como meros mapeamentos de tabelas. Terceiro, muitos desenvolvedores aprenderam programação procedural primeiro e apenas superficialmente adotaram orientação a objetos. Para eles, objetos são estruturas de dados glorificadas, e toda lógica naturalmente vive em funções/métodos separados.
Mas o custo do domínio anêmico é alto. Quando lógica está dispersa em serviços desconectados, é difícil entender o comportamento do sistema. Você precisa ler múltiplos arquivos, seguir múltiplas chamadas, manter contexto mental complexo. Regras de negócio que deveriam estar localizadas, “um pedido só pode ser cancelado se não foi enviado”, ficam espalhadas. Talvez o serviço de pedidos cheque isso em um lugar, o serviço de cancelamento em outro, a API pública em um terceiro. Duplicação, inconsistência e bugs são inevitáveis.
Além disso, domínio anêmico torna refatoração arriscada. Se uma entidade é apenas dados, mudá-la afeta todos os serviços que a manipulam. Não há encapsulamento protegendo invariantes. Qualquer serviço pode colocar a entidade em estado inválido. Testes se tornam complexos porque você precisa mockar muitos serviços interagindo de formas complexas.
Essa confusão é análoga ao que Karl Popper chamava de nominalismo vazio: usar palavras com prestígio teórico sem compromisso com sua substância empírica. Chamar algo de “domínio” não faz dele um domínio bem modelado, assim como chamar algo de “ciência” não faz dele científico. O nome é fácil; a substância é difícil.
“A diferença entre a palavra quase certa e a palavra certa é realmente algo muito importante, é a diferença entre o vagalume e o relâmpago.” — Mark Twain
Twain estava falando de escrita literária, mas o princípio aplica-se perfeitamente a arquitetura de software. Usar “domínio” para rotular uma pasta de POJOs anêmicos é usar “almost the right word”. Parece certo, mas perde a essência. A diferença entre domínio rico (entidades com comportamento, regras encapsuladas, linguagem ubíqua) e domínio anêmico (DTOs glorificados) é a diferença entre lightning e lightning-bug.
A solução não é simplesmente adicionar métodos às entidades. É repensar fundamentalmente o que são entidades. Elas não são tabelas de banco de dados refletidas em código. São conceitos do negócio com identidade, comportamento e responsabilidade. Uma entidade “Pedido” deveria saber como se calcular, como se validar, como mudar de estado. Não deveria ser manipulada passivamente por serviços externos.
O ruído organizacional e o custo da ambiguidade
A falta de clareza sobre o termo domínio é um tipo de ruído semântico organizacional. Em times ágeis, onde o fluxo de comunicação é contínuo e decisões são descentralizadas, pequenas divergências conceituais se amplificam com o tempo. É como uma deriva genética em biologia: pequenas mutações aleatórias que, isoladamente, são irrelevantes, mas acumuladas ao longo de gerações produzem divergência significativa.
Um desenvolvedor acredita que “casos de uso pertencem ao domínio”. Ele estrutura seu código colocando orquestração de fluxo dentro do módulo de domínio. Outro desenvolvedor, com background diferente, acredita que “domínio é só entidade e regra pura”. Ele coloca casos de uso em uma camada separada. Ambos contribuem para a mesma codebase. O resultado? Código inconsistente. Alguns casos de uso dentro do domínio, outros fora. Alguns serviços que misturam responsabilidades, outros que as separam rigorosamente.
Essa inconsistência não é apenas estética. Ela tem custos reais:
Custo cognitivo: Novos desenvolvedores (e até veteranos) não conseguem prever onde encontrar certa funcionalidade. “Onde está a lógica de aprovação de pedido?” Deveria estar no domínio? Na aplicação? No serviço? É preciso buscar, adivinhar, ou pior, perguntar repetidamente.
Custo de manutenção: Mudanças exigem entender múltiplas organizações de código. Adicionar nova regra de negócio exige entender onde ela deve ir — e a resposta é inconsistente com o precedente do próprio projeto.
Custo de teste: Estratégias de teste se tornam heterogêneas. Alguns módulos são facilmente testáveis porque separam domínio de infraestrutura. Outros são emaranhados e exigem testes de integração pesados. A cobertura de teste vira uma colcha de retalhos.
Custo político: Discussões sobre arquitetura se tornam disputas territoriais. “Minha parte do código está certa, a sua está errada.” Sem critério objetivo para julgar, essas disputas não se resolvem, apenas se perpetuam.
“Em um mercado de limões, a qualidade média dos bens negociados diminui por causa da assimetria de informação.” — George Akerlof
Akerlof estudou mercados onde vendedores sabem mais sobre a qualidade de produtos que compradores (exemplo: carros usados). Nesses mercados, produtos ruins (“lemons”) expulsam produtos bons porque compradores não conseguem distingui-los. O preço cai para refletir qualidade média, então vendedores de produtos bons saem do mercado, baixando ainda mais a qualidade média. É um ciclo vicioso.
Em codebases onde a qualidade arquitetural é difícil de distinguir (devido a ruído semântico e inconsistência), ocorre dinâmica similar. Desenvolvedores que se preocupam com arquitetura ficam frustrados porque não conseguem estabelecer padrões. Desenvolvedores que não se preocupam contribuem código de baixa qualidade arquitetural porque “é assim que já está sendo feito”. A qualidade média cai. Desenvolvedores bons eventualmente saem, exacerbando o problema.
Essa não é apenas analogia, é observação empírica. Vi projetos onde o ruído semântico sobre “domínio” eventualmente levou à degradação completa da arquitetura. Camadas que deveriam ser isoladas se tornaram completamente entrelaçadas. Testes se tornaram impossíveis sem subir toda a infraestrutura. O tempo de build cresceu de segundos para minutos. Deployment se tornou arriscado porque ninguém entendia as dependências reais. O projeto eventualmente foi descartado e reescrito.
O custo da ambiguidade, portanto, não é apenas comunicação ineficiente, é degradação progressiva da arquitetura até o ponto onde o custo de manutenção excede o valor gerado. E tudo isso começa com algo aparentemente trivial: não alinhar o significado de uma única palavra.
Entre filosofia e pragmatismo: o domínio como prática
Há algo de filosófico na discussão sobre domínio. Estamos perguntando, em última análise: o que é essencial e o que é acidental? O que pertence à natureza do problema e o que é artefato da solução? Essas são questões aristotélicas, substância versus acidente, forma versus matéria.
A arquitetura de software, quando feita com seriedade, é um exercício filosófico aplicado. Não apenas “onde coloco esta classe?”, mas “qual é a natureza desta responsabilidade?”. Não apenas “como implemento esta funcionalidade?”, mas “como modelo este aspecto da realidade?”. Essas questões exigem tanto competência técnica quanto clareza conceitual.
“A ciência é aquilo que entendemos bem o suficiente para explicar a um computador. A arte é tudo o mais que fazemos.” — Donald Knuth
Knuth, um dos pais da ciência da computação, reconhece que nossa disciplina é tanto arte quanto ciência. Modelar domínio é arte: exige intuição, sensibilidade, interpretação. Duas pessoas competentes podem modelar o mesmo domínio de formas diferentes, ambas válidas. Não há algoritmo para encontrar o modelo correto.
Mas isso não significa que “vale tudo”, que todas as modelagens são equivalentes. Existem modelagens melhores e piores, mais ou menos fiéis ao domínio, mais ou menos expressivas, mais ou menos sustentáveis. O julgamento sobre qual é melhor requer experiência, contexto e, frequentemente, debate. É um julgamento hermenêutico, não algorítmico.
A tensão entre filosofia e pragmatismo é constante. Filosoficamente, queremos domínio puro, independente de toda contaminação técnica. Pragmaticamente, precisamos comprometer. Persistência, performance, restrições de framework, todas afetam como modelamos o domínio. O desenvolvedor purista que insiste em domínio absolutamente isolado frequentemente gera tanto boilerplate que a produtividade desaba. O desenvolvedor pragmático que ignora separação de conceitos gera código rápido de escrever, mas impossível de manter.
A sabedoria está em navegar essa tensão conscientemente. Saber quando é apropriado comprometer a pureza arquitetural (entregas urgentes, protótipos, sistemas triviais) e quando é essencial mantê-la (core business, sistemas críticos, produtos de longo prazo). Saber quando a refatoração arquitetural vale o custo e quando é gold-plating.
Trabalhei com um arquiteto brilhante que tinha um princípio: “Arquitetura é sobre decisões reversíveis versus irreversíveis. Invista em tornar irreversíveis as decisões corretas.” A escolha de isolar ou não o domínio é relativamente irreversível. Uma vez que código de negócio está misturado com código de infraestrutura, desembaraçar é custoso. Portanto, essa é uma decisão onde vale investir acertando desde o início. Já a escolha de qual biblioteca de logging usar é facilmente reversível. Não vale perder tempo debatendo exaustivamente.
O domínio é uma daquelas decisões estruturantes que define a trajetória do projeto. Errar o domínio não inviabiliza imediatamente o projeto, mas cria dívida técnica que cresce exponencialmente. Cada nova feature é um pouco mais difícil. Cada bug é um pouco mais obscuro. Cada refatoração é um pouco mais arriscada. Eventualmente, o projeto atinge um ponto onde qualquer mudança é perigosa e custosa. A única saída é reescrita.
Histórias do front: quando a teoria encontra a realidade
Deixe-me compartilhar algumas histórias reais (anonimizadas) que ilustram concretamente como a confusão sobre “domínio” se manifesta em projetos reais.
História 1: O domínio que era um banco de dados
Em um projeto financeiro para uma grande seguradora, a equipe tinha décadas de experiência em sistemas mainframe e Oracle. Para eles, “modelar o domínio” significava desenhar o modelo entidade-relacionamento, criar tabelas normalizadas, estabelecer constraints de chave estrangeira, escrever triggers para regras de negócio. Quando a empresa decidiu modernizar e contratar novos desenvolvedores com expertise em arquitetura moderna, surgiu conflito imediato.
Os novos desenvolvedores queriam criar camada de domínio com objetos ricos, isolada do banco de dados. Os veteranos achavam isso absurdo: “o domínio JÁ ESTÁ modelado, no banco de dados!”. Para eles, criar “outra representação do domínio” em código era duplicação desnecessária. As discussões eram frustrantes porque ambos os lados usavam “domínio” para significar coisas diferentes. Para os veteranos, domínio = schema do banco. Para os novos, domínio = objetos de negócio no código.
O projeto fracassou em integrar as duas visões. Terminaram com híbrido infeliz: parte da lógica em triggers e stored procedures, parte em serviços Java, sem clara separação de responsabilidades. O sistema funcionava, mas era nightmare para manter. Nenhum desenvolvedor entendia todo o fluxo. Bugs apareciam em lugares inesperados. Mudanças exigiam alterações sincronizadas em banco e código, frequentemente desincronizadas na prática.
História 2: O domínio que estava em tudo e em nada
Uma startup de e-commerce adotou DDD após o CTO ler o livro de Eric Evans. Todos ficaram entusiasmados. Criaram pasta /domain no projeto. Moveram código para lá. Celebraram que agora tinham “arquitetura moderna”.
Mas ninguém realmente entendeu DDD. O /domain virou lixão: entidades anêmicas, DTOs, utilities, helpers, validações diversas, até código de integração com API de pagamento. Não havia bounded contexts, não havia linguagem ubíqua, não havia agregados bem definidos. Era código procedural organizado em classes, com rótulo fancy de “domínio”.
Pior: porque tudo estava “no domínio”, nada estava isolado. Código de domínio dependia diretamente de bibliotecas de HTTP, de frameworks de serialização JSON, de clientes de banco de dados. Testes exigiam subir quase toda a aplicação. Não havia ganho arquitetural real, apenas ilusão criada pelo rótulo.
Quando um novo CTO entrou (o anterior saiu após rodada de investimento frustrante), ele primeiro ficou impressionado: “vocês usam DDD!”. Depois, ao examinar o código, ficou horrorizado: “isso não é DDD, é caos organizado em pastas”. A refatoração levou meses.
História 3: O domínio dividido e a guerra de arquitetos
Em uma grande consultoria, dois arquitetos seniores lideravam times diferentes no mesmo programa. Um seguia religiosamente Clean Architecture; outro preferia Hexagonal. Ambos os times implementavam microsserviços que precisavam integrar.
O time Clean tinha clara separação: /entities para regras de negócio puras, /usecases para orquestração. O time Hexagonal tinha /domain único contendo ambos. Quando começaram integrações, surgiu problema: contratos de API refletiam organizações internas diferentes. O que o time Clean chamava de “serviço de domínio”, o time Hexagonal chamava de “porta”. O que um via como “entidade”, outro via como “agregado”.
Tecnicamente, ambos os sistemas funcionavam bem individualmente. Mas a integração era nightmare conceitual. Documentação usava terminologias diferentes. Discussões de design eram confusas porque cada lado interpretava propostas através de seu framework arquitetural. Reuniões de alinhamento se tornaram debates filosóficos sobre arquitetura.
O programa atrasou. Stakeholders não entendiam por que “problemas de arquitetura” causavam tanto delay, afinal, ambos os sistemas funcionavam. A resolução veio apenas quando trouxeram arquiteto externo para estabelecer vocabulário comum e mediar traduções entre as duas abordagens. Mas o custo em tempo e moral foi significativo.
Domínio como disciplina: indo além do código
Se há uma lição que atravessa todas as discussões sobre domínio, é esta: domínio é mais que código. É disciplina de pensamento. É a prática de constantemente perguntar “o que realmente importa aqui?” e “como isso se relaciona com o negócio?”. É resistir à tentação de pular direto para implementação e primeiro investir em compreensão.
“Semanas de programação podem economizar horas de planejamento.”
Essa frase irônica captura uma verdade profunda: tempo investido em compreender o domínio e planejar a modelagem economiza múltiplo tempo de implementação. Mas há viés cognitivo forte para ação. Desenvolvedores querem escrever código. Gerentes querem ver progresso. Planejar parece improdutivo. Então pulamos para código e descobrimos problemas quando já temos milhares de linhas escritas.
DDD e as arquiteturas associadas são, fundamentalmente, disciplinas de contenção: contenção do impulso de codificar prematuramente, contenção do impulso de otimizar prematuramente, contenção do impulso de complicar prematuramente. Elas dizem: primeiro entenda o domínio, depois modele, depois escolha arquitetura, depois implemente. Essa ordem importa.
Mas disciplina é difícil. Exige maturidade individual e organizacional. Times sob pressão por entregas rápidas não têm paciência para “filosar sobre domínio”. Product owners não entendem por que “modelagem” demora tanto. A pressão é sempre para “code faster”, não “think deeper”. E então colhemos as consequências: sistemas que funcionam, mas não fazem sentido. Código que passa nos testes, mas não reflete o negócio. Arquiteturas que são tecnicamente corretas, mas conceitualmente vazias.
O domínio como disciplina também significa rejeitar soluções prontas sem pensamento crítico. Não adotar DDD “porque é o que se faz”, não aplicar Clean Architecture “porque Uncle Bob disse”, não usar microsserviços “porque é moderno”. Mas sim entender profundamente o que cada abordagem propõe, por que propõe, que problemas resolve e que problemas cria. E então escolher conscientemente, contextualmente.
Significa também aceitar que não há receita universal. O domínio de uma fintech é diferente do domínio de uma rede social, que é diferente do domínio de um sistema embarcado. As mesmas técnicas não se aplicam universalmente. DDD faz enorme sentido para sistemas com lógica de negócio complexa e mutável; faz pouco sentido para sistemas CRUD simples. Arquitetura Hexagonal é valiosa quando você prevê mudanças frequentes em infraestrutura; é overhead desnecessário em protótipos descartáveis.
A maturidade arquitetural está em saber adaptar princípios a contextos, não em aplicar padrões dogmaticamente.
Conclusão: o domínio da comunicação
No fim, o verdadeiro domínio que precisamos entender é o da comunicação. A engenharia de software é um exercício de tradução constante entre mundos: o do negócio, o do código, o da infraestrutura, o da equipe. Cada contexto usa “domínio” para falar de um pedaço dessa realidade. Ignorar o contexto é confundir os mundos e projetar mal a ponte entre eles.
Evans, Cockburn, Palermo e Martin não criaram conceitos incompatíveis, criaram vocabulários diferentes para problemas distintos. O ruído nasce quando esses vocabulários se misturam sem mediação. É nesse ponto que a filosofia se torna pragmática: compreender a linguagem é compreender o sistema. Wittgenstein já sabia: “o significado de uma palavra é o seu uso na linguagem”. Em engenharia de software, o uso de “domínio” varia dramaticamente. Reconhecer essa variação é o primeiro passo para comunicação eficaz.
A polissemia de “domínio” não é problema a ser eliminado, é realidade a ser navegada. Diferentes comunidades de prática (DDD, arquitetura corporativa, administração de bancos de dados) legitimamente usam o termo de formas diferentes. Forçar unificação seria impor empobrecimento semântico. O que precisamos não é vocabulário único, mas consciência semântica: saber que estamos usando termo polissêmico e sempre esclarecer contexto.
Falar de “domínio” sem compreender o contexto é como tentar tocar uma sinfonia onde cada músico lê uma partitura diferente. O resultado é ruído, não harmonia. E toda boa arquitetura, no fim das contas, é a arte de eliminar ruído, técnico, conceitual e humano. É construir sistemas que fazem sentido em múltiplos níveis: compilam corretamente, executam eficientemente, mas também comunicam claramente suas intenções.
“Programas devem ser escritos para que as pessoas os leiam, e apenas incidentalmente para que as máquinas os executem.” — Harold Abelson
Abelson, co-autor do clássico Structure and Interpretation of Computer Programs, nos lembra que código é, antes de tudo, comunicação humana. O compilador não se importa se você chama algo de “domínio” ou “núcleo” ou “negócio”. Mas humanos se importam. A escolha de termos molda entendimento. Termos bem escolhidos tornam sistema compreensível; termos mal escolhidos obscurecem intenções.
O “domínio”, em todos seus sentidos, é sobre construir pontes de entendimento. Entre o negócio e a tecnologia. Entre o problema e a solução. Entre especialistas e desenvolvedores. Entre a realidade e sua representação computacional. Essas pontes são frágeis e exigem manutenção constante. Exigem diálogo, esclarecimento, refinamento. Exigem humildade para reconhecer quando não estamos nos entendendo e paciência para alinhar vocabulários.
A melhor arquitetura de software não é a mais elegante tecnicamente ou a mais trendy conceitualmente. É a que melhor comunica suas intenções aos futuros mantenedores, que podem ser você mesmo daqui a seis meses. É a que estabelece fronteiras claras baseadas em entendimento profundo do domínio (em qualquer sentido que você esteja usando a palavra, desde que seja claro qual). É a que facilita evolução porque suas abstrações são robustas e bem fundamentadas.
Portanto, da próxima vez que você ou sua equipe usar a palavra “domínio”, pare por um momento. Pergunte-se: “o que realmente queremos dizer aqui?”. É domínio no sentido de DDD: entidades e regras de negócio? É domínio no sentido arquitetural, o núcleo isolado da aplicação? É domínio no sentido corporativo, uma área de responsabilidade organizacional? É domínio no sentido de banco de dados, um tipo de dado customizado? Esclareça. Alinhe. Compartilhe entendimento.
Essa pequena disciplina, precisão semântica, é o que distingue times medianos de times excelentes. Times medianos debatem termos indefinidamente. Times excelentes alinham vocabulários rapidamente e focam no trabalho substantivo. Times medianos assumem que “todo mundo sabe o que é domínio”. Times excelentes sabem que ninguém sabe até que seja explicitado.
No final, arquitetura de software é arquitetura de entendimento. E você não pode arquitetar entendimento sobre fundamentos semânticos instáveis. Clarifique seus termos. Entenda seus contextos. Construa suas pontes. O código agradece, a equipe agradece, e o negócio agradece.
Nota Final: Este artigo não prescreve qual definição de “domínio” é correta — porque não há definição única correta. O objetivo é tornar explícitas as múltiplas definições, para que times possam escolher conscientemente qual adotar e comunicá-la claramente. A clareza, não a uniformidade, é o objetivo.