Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

02 - Linguagem Ubíqua (Ubiquitous Language)

#ddd#documentacao-viva#linguagem-ubiqua#refatoracao
video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

Linguagem Ubíqua (Ubiquitous Language)

A linguagem ubíqua é o vocabulário compartilhado, preciso e obrigatório entre especialistas do
negócio, desenvolvedores, testadores e todos os envolvidos no produto. Ela define que um termo como
"reserva", "liquidação" ou "inadimplência" tem um significado único e acordado dentro de um
contexto, e que esse mesmo vocabulário aparece nas conversas, nos requisitos, no código, nos testes
e nos logs. O objetivo é eliminar a tradução permanente entre o jeito de falar do negócio e o jeito
de falar da tecnologia, porque cada tradução perde significado e abre espaço para defeitos. Em
produção, boa parte dos bugs sérios nasce de ambiguidade de termos e não de lógica mal escrita. Um
sistema onde o código fala a língua do negócio é auditável pelo próprio especialista, acelera o
onboarding e reduz o custo de cada mudança.

O problema que resolve

Em projetos sem vocabulário comum, cada camada fala um dialeto diferente. O analista escreve
"lançamento", o desenvolvedor cria uma classe chamada TransactionRecord, o QA chama de "movimento"
e o suporte abre ticket com o termo que o cliente usou. Quando um incidente acontece, o time gasta
horas apenas descobrindo se todos estão falando da mesma coisa. Esse custo de tradução aparece em
outros três pontos: na escrita de requisitos, que descrevem o comportamento com palavras que o
código não reconhece; na revisão de código, onde um nome ruim exige reunião para confirmar o
significado; e na manutenção por novos integrantes, que precisam construir mentalmente um dicionário
que ninguém documentou. A linguagem ubíqua ataca a raiz: um único dicionário, usado por todos e
refletido no próprio software.

Onde a linguagem vale e como ela se forma

A linguagem ubíqua só é consistente dentro de um bounded context, e tentar um dicionário único para
a empresa inteira costuma fracassar. "Apólice" significa algo diferente no seguro de vida e no
seguro de automóvel, e forçar um único significado produz um modelo vago. A formação do vocabulário
acontece nas conversas de levantamento e nas sessões de modelagem com especialistas, e deve ser
registrada em um glossário vivo no repositório do projeto. O critério de admissão de um termo é
objetivo: ele precisa ser usado naturalmente pelos especialistas, sem exigir tradução, e precisa ser
preciso o bastante para não gerar duas interpretações. Termos que não passam nesse critério ficam de
fora ou são refinados até passarem.

O código refletindo a linguagem

O teste prático da linguagem ubíqua é abrir o código e conseguir ler nomes de classes, métodos e
estados como frases do negócio. Se o especialista diz "reservar um assento" e o código tem
Assento.reservar(), a conversa e a implementação estão coladas. O exemplo a seguir compara dois
estilos para a mesma operação de pedido em TypeScript, um com vocabulário genérico de técnico e outro
com o vocabulário acordado do domínio.

// Estilo genérico: o leitor precisa traduzir o que "processar" significa
class PedidoProcessor {
  exec(p: PedidoDTO, repo: Repo): Res {
    if (p.itens.length === 0) throw new Error("inválido");
    p.status = "PRC";
    repo.save(p);
  }
}

// Estilo ubíquo: nomes vêm do vocabulário acordado com o negócio
class Pedido {
  // um pedido sem itens não é um pedido, é um carrinho abandonado
  static novoPara(cliente: ClienteId, itens: ItemDePedido[]): Pedido {
    if (itens.length === 0) throw new PedidoSemItens();
    return new Pedido(PedidoId.novo(), cliente, itens, StatusDoPedido.AGUARDANDO_PAGAMENTO);
  }

  // o negócio diz "confirmar pedido", então o método se chama confirmar
  confirmar(pagamento: PagamentoAprovado): void {
    if (this.status !== StatusDoPedido.AGUARDANDO_PAGAMENTO) {
      throw new PedidoNaoPodeSerConfirmado(this.id, this.status);
    }
    this.status = StatusDoPedido.CONFIRMADO;
    this.registrarEvento(new PedidoConfirmado(this.id, pagamento.id));
  }
}

A diferença não é estética. Na versão ubíqua, um incidente às 3 da manhã é diagnosticável lendo o
log, porque a mensagem PedidoNaoPodeSerConfirmado significa algo para o time de negócio também. Na
versão genérica, o erro "inválido" obriga a abrir código para descobrir qual regra falhou.

Renomeação como refatoração de verdade

Quando o negócio muda o nome de um conceito, o código deve mudar junto, e essa troca é refatoração
no mesmo sentido de extrair método ou remover duplicação. Manter o termo antigo "para não quebrar
nada" cria dois dicionários em paralelo, e em poucos meses ninguém sabe qual é o oficial. IDEs
modernas tornam a renomeação segura em linguagens estaticamente tipadas, então o custo da atualização
é baixo perto do custo do vocabulário dividido. Casos reais mostram o ganho: um time que trocou
"contrato" por "assinatura" após mudança regulatória atualizou classes, filas, tópicos e dashboards
em uma sprint, e a documentação parou de divergir do sistema. Nomes que atravessam fronteiras
externas, como campos de APIs públicas, exigem um plano de transição com deprecação, mas o modelo
interno deve seguir o negócio sem hesitar.

Glossário como documentação viva

O glossário é o artefato mínimo e mais barato para sustentar a linguagem: uma tabela de termo,
significado, exemplos e o que o termo não é. Ele vive junto do código, no repositório, e é atualizado
no mesmo pull request que introduz o conceito novo, exatamente como se atualiza um teste. Testes de
aceitação escritos em Gherkin reforçam o mesmo efeito, porque descrevem regras com o vocabulário
acordado e falham quando o código se descola da linguagem. A diferença para uma documentação comum é
a cobrança: glossário desatualizado é defeito, não detalhe. Times maduros revisam termos novos em
reunião curta, e a pergunta padrão é se o especialista do negócio reconheceria a frase escrita no
código.

Introduzindo a linguagem em um time que já existe

Em sistemas legados, o vocabulário do código raramente coincide com o vocabulário atual do negócio, e
forçar uma grande renomeação de uma vez é arriscado. O caminho incremental começa pelo glossário do
contexto mais ativo, seguido pela adoção dos termos em conversas, tickets e mensagens de commit.
Depois vêm os testes novos, que já nascem com a linguagem correta, e então os métodos tocados por
cada mudança de funcionalidade. Eventos publicados para outras equipes merecem cuidado redobrado,
porque renomear um payload quebra consumidores, então a troca segue com deprecação anunciada. Em
alguns meses o núcleo ativo do domínio fala a língua do negócio, e o vocabulário antigo sobrevive
apenas nas bordas congeladas.

Sinais de linguagem quebrada

Sintoma observado Causa provável Mitigação
Reuniões em que negócio e time técnico repetem coisas diferentes do mesmo termo Vocabulário sem significado único por contexto Construir glossário por bounded context e validar com especialistas
Nomes como Gerenciador, Handler e Dados no núcleo do domínio Código escrito só pelo vocabulário técnico Renomear com base no que o negócio chama a operação
Especialista não consegue ler um teste de aceitação Testes escritos no dialeto da tecnologia Reescrever cenários em Gherkin com termos do negócio
Requisito novo muda o código, mas não a documentação, ou o inverso Duas fontes de verdade sem sincronização Glossário e testes no mesmo pull request da mudança
Novos integrantes demoram semanas para entender termos básicos Conhecimento oral que nunca virou registro Onboarding começando pelo glossário e pelos testes

Erros comuns e boas práticas

  • Escolher termos que soam técnicos em vez dos que o especialista usa. Se o mercado chama de
    "sinistro", chamar de "evento de ocorrência" cria tradução desnecessária.
  • Manter termos ambíguos para agradar todos os interlocutores. Vagueza no vocabulário vira
    vagueza no modelo e depois nos dados.
  • Ignorar que a linguagem vale por contexto e tentar dicionário corporativo único. Termos
    compartilhados entre contextos precisam de mapeamento explícito, não de unificação.
  • Deixar o glossário em documento fora do repositório. Documentação longe do código envelhece
    sem que ninguém perceba.
  • Tratar renomeação como custo puro. O termo desatualizado no código é dívida que cobra juros em
    cada conversa, em cada incidente e em cada integração.
  • Registrar o termo sem exemplo de uso. Um termo sem exemplo admite duas leituras, e a ambiguidade
    volta exatamente onde o glossário deveria eliminá-la.