strategic · temario
2.2tema 2 de 5

Lenguaje ubicuo por contexto

El lenguaje ubicuo no es global: cada bounded context tiene el suyo propio y los términos se traducen explícitamente en la frontera.

El lenguaje ubicuo es la columna vertebral de DDD: el mismo vocabulario usado por el equipo técnico y el equipo de negocio debe aparecer literalmente en el código. Sin embargo, un error conceptual común es asumir que ese lenguaje es global para todo el sistema. En realidad, el lenguaje ubicuo es local a cada bounded context.

El mismo término puede tener significados distintos —y completamente válidos— en contextos diferentes. Un 'Producto' en el contexto de catálogo puede tener atributos como descripción, imágenes y categorías; en el contexto de inventario, el mismo 'Producto' importa su stock y ubicación física; en el contexto de facturación, lo relevante es su precio y condición fiscal. Forzar un modelo único para los tres crea una clase con demasiadas responsabilidades y acoplamientos.

Dentro de un bounded context, el lenguaje ubicuo se materializa en los nombres de clases, métodos, eventos y repositorios. El código debe leer como prosa del negocio dentro de ese límite. Cada término del glosario del contexto tiene exactamente una definición, sin ambigüedad.

Cuando dos contextos necesitan comunicarse, sus lenguajes se traducen en la frontera. Esa traducción puede ser una Anti-Corruption Layer (ACL) que convierte el modelo externo al idioma propio, o un contrato publicado (Published Language / Open Host Service) que fija el vocabulario de intercambio entre contextos.

Un glosario de contexto es un artefacto vivo: debe estar accesible para todos los miembros del equipo y actualizarse cuando el entendimiento del negocio evoluciona. El código y el glosario deben mantenerse sincronizados; una discrepancia entre ambos es una señal de deuda técnica en el modelo.

La disciplina de mantener lenguajes separados por contexto protege a los equipos de la 'trampa del sustantivo compartido': la ilusión de que porque dos cosas se llaman igual, son la misma cosa. Nombrar explícitamente las diferencias es la primera acción para evitar el big ball of mud.

structure.txt
# Each bounded context defines its own vocabulary in code

# contexts/<catalog>/domain/model/product.py
from dataclasses import dataclass, field
from typing import list

@dataclass(frozen=True)
class ProductName:
    value: str

@dataclass
class Product:  # Catalog context: name, description, images, category
    id: ProductId
    name: ProductName
    description: str
    category: Category


# contexts/<inventory>/domain/model/stock_item.py
@dataclass
class StockItem:  # Inventory context: same 'product' = stock unit
    product_id: ProductId  # reference by id only — not the Catalog Product
    quantity: Quantity
    warehouse_location: WarehouseLocation


# contexts/<billing>/domain/model/billable_product.py
@dataclass
class BillableProduct:  # Billing context: price + tax conditions
    product_id: ProductId
    unit_price: Money
    tax_code: TaxCode

# Translation happens at the boundary (ACL or integration event mapper):
# catalog.Product ──▶ ACL ──▶ billing.BillableProduct

Debugging lab

Detecta y corrige el error o la violación de diseño.

0/5 tests passing0%
  1. 2.2.5.1

    # A single 'universal' User model is imported by both contexts: # contexts/auth/domain/model/user.py is imported in contexts/billing/domain/model/invoice.py from src.project.contexts.auth.domain.model.user import User class Invoice: def __init__(self, user: User, amount: Money): ...

  2. 2.2.5.2

    # A method name uses infrastructure jargon instead of domain language: class <aggregate_root>: def upsert_record(self, data: dict) -> None: ...

  3. 2.2.5.3

    # Domain event uses a generic name that no domain expert would recognize: class DataUpdated: # emitted by the <aggregate> aggregate_id: str new_data: dict

  4. 2.2.5.4

    # The same Customer class is reused across three bounded contexts by importing it: from src.project.contexts.crm.domain.model.customer import Customer # Used in: shipping, billing, crm

  5. 2.2.5.5

    # Glossary and code are out of sync: # GLOSSARY.md says: 'Order' = confirmed purchase with payment # But in code: class Order has a 'pending' status and no payment info