Linguagem Ubíqua
Definição
Seção intitulada “Definição”Cunhada por Eric Evans, a Linguagem Ubíqua (Ubiquitous Language) é a espinha dorsal do Design Estratégico. A ideia é eliminar a “tradução” entre a linguagem do negócio e a linguagem técnica — tradução que sempre perde informação e introduz bugs conceituais.
Não existe uma linguagem ubíqua global do sistema. Ela é contextual: cada Bounded Context tem a sua. O termo “Cliente” no contexto de Vendas pode significar algo diferente de “Cliente” no contexto de Faturamento. Forçar um único significado gera um modelo confuso e ambíguo.
O problema resolvido
Seção intitulada “O problema resolvido”- Ambiguidade de termos: sem acordo, “pedido”, “ordem” e “solicitação” viram sinônimos flutuantes.
- Perda na tradução: o analista descreve uma regra, o dev a implementa com outro nome, e o código deixa de “falar” o negócio.
- Documentação que mente: modelos que não usam a linguagem do especialista envelhecem mal.
Regras de design
Seção intitulada “Regras de design”- O código é a documentação viva. Se o especialista fala “aprovar apólice”, deve existir
apolice.aprovar(), nãoapolice.setStatus(2). - Refine a linguagem continuamente. Descobriu um termo melhor com o especialista? Refatore o modelo — inclusive nomes de classes.
- Um termo, um significado — por contexto. Homônimos entre contextos são normais; homônimos dentro do mesmo contexto são bug.
- Testes falam a linguagem. Cenários BDD/Gherkin são um ótimo espelho da linguagem ubíqua.
Trade-offs e quando NÃO forçar
Seção intitulada “Trade-offs e quando NÃO forçar”Em subdomínios genéricos (envio de e-mail, autenticação) ou CRUDs triviais, investir pesado na linguagem ubíqua tem baixo retorno. O esforço se justifica no Core Domain, onde está a vantagem competitiva.
Exemplo em Java + Spring
Seção intitulada “Exemplo em Java + Spring”Modelo que fala a linguagem do negócio de seguros. Note os nomes derivados diretamente do vocabulário do especialista.
package com.seguradora.apolice.domain;
import java.math.BigDecimal;import java.time.LocalDate;import java.util.UUID;
public class Apolice {
private final ApoliceId id; private final Segurado segurado; private final BigDecimal premio; private LocalDate vigenciaInicio; private LocalDate vigenciaFim; private StatusApolice status;
public Apolice(Segurado segurado, BigDecimal premio, LocalDate vigenciaInicio, LocalDate vigenciaFim) { if (premio == null || premio.signum() <= 0) { throw new IllegalArgumentException("Premio deve ser positivo"); } if (vigenciaFim.isBefore(vigenciaInicio)) { throw new IllegalArgumentException("Vigencia final anterior ao inicio"); } this.id = new ApoliceId(UUID.randomUUID()); this.segurado = segurado; this.premio = premio; this.vigenciaInicio = vigenciaInicio; this.vigenciaFim = vigenciaFim; this.status = StatusApolice.PROPOSTA; }
public void aprovar() { if (status != StatusApolice.PROPOSTA) { throw new IllegalStateException("Apenas propostas podem ser aprovadas"); } this.status = StatusApolice.VIGENTE; }
public void cancelar() { if (status != StatusApolice.VIGENTE) { throw new IllegalStateException("Apenas apolices vigentes podem ser canceladas"); } this.status = StatusApolice.CANCELADA; }
public boolean estaVigenteEm(LocalDate data) { return status == StatusApolice.VIGENTE && !data.isBefore(vigenciaInicio) && !data.isAfter(vigenciaFim); }
public ApoliceId id() { return id; }
public StatusApolice status() { return status; }}package com.seguradora.apolice.domain;
public enum StatusApolice { PROPOSTA, VIGENTE, CANCELADA}Anti-padrões e erros comuns
Seção intitulada “Anti-padrões e erros comuns”- Traduzir na fronteira: manter um glossário paralelo em vez de nomear o código com os termos reais.
- Linguagem global forçada: um único “Cliente” para todo o sistema, gerando um modelo genérico e anêmico.
- Termos técnicos vazando:
dto,manager,helpercomo se fossem conceitos de negócio. - Congelar a linguagem: não refatorar nomes quando o entendimento do domínio evolui.
Relações
Seção intitulada “Relações”- Vive dentro de um Bounded Context
- Base do Design Estratégico e Tático
- Materializa-se nos blocos táticos: Entidades, Value Objects, Domain Events
- Parte de Domain-Driven Design
- Voltar para Home
Perguntas de revisão
Seção intitulada “Perguntas de revisão”1. A Linguagem Ubíqua é global ou contextual?
Resposta
Contextual. Cada Bounded Context tem a sua. O mesmo termo pode significar coisas diferentes em contextos distintos, e isso é esperado — não um defeito.
2. Onde a Linguagem Ubíqua deve aparecer?
Resposta
Literalmente no código: nomes de classes, métodos, Domain Events e testes. O código é documentação viva do vocabulário do negócio.
3. Por que apolice.setStatus(2) viola a Linguagem Ubíqua?
Resposta
Porque não expressa a intenção do negócio. O especialista fala “aprovar”, “cancelar” — logo devem existir métodos aprovar()/cancelar() que carregam a regra, e não um setter genérico com códigos mágicos.
4. Quando NÃO vale a pena investir pesado na Linguagem Ubíqua?
Resposta
Em subdomínios genéricos (e-mail, auth) e CRUDs triviais. O retorno é maior no Core Domain, onde reside a complexidade e a vantagem competitiva.