En pocas palabras
Conjunto de patrones estratégicos (subdominios, bounded contexts, context mapping) y tácticos (agregados, entidades, eventos de dominio) para modelar dominios complejos.
Qué problema resuelve
Modelos únicos y gigantes donde «cliente» o «crédito» significan cosas distintas para cada área, con acoplamiento entre equipos y servicios.
Cuándo utilizarlo
Dominios con reglas de negocio ricas y varios equipos. Ejemplo: separar originación, cobranza y contabilidad de una plataforma de crédito.
De la idea a la práctica
Funcionamiento, ejemplos y decisiones para pasar al siguiente nivel.
Diseño estratégico
Subdominios. Clasifica las áreas del negocio para decidir dónde invertir:
| Tipo | Descripción | Estrategia típica |
|---|---|---|
| Core | Lo que diferencia a la empresa (p. ej. scoring) | Construir con el mejor equipo |
| Soporte | Necesario y específico, pero no diferencial | Construir sencillo o externalizar |
| Genérico | Resuelto en el mercado (identidad, pagos, correo) | Comprar o usar SaaS |
Lenguaje ubicuo. Cada término tiene un significado preciso dentro de un contexto y aparece igual en conversaciones, código, tablas y eventos. Si negocio dice «desembolso» y el código transfer, hay una traducción oculta que producirá errores.
Bounded context. Límite explícito dentro del cual un modelo es consistente. «Cliente» en Originación (solicitante con ingresos y documentos) no es el mismo «Cliente» que en Cobranza (deudor con saldo y canal de contacto). Forzar un único modelo crea una entidad enorme que nadie puede cambiar.
Context mapping
Describe cómo se relacionan los contextos y, de paso, los equipos:
| Patrón | Cuándo usarlo |
|---|---|
| Customer / Supplier | El proveedor (upstream) prioriza necesidades del consumidor (downstream) |
| Conformist | El downstream adopta el modelo del upstream tal cual (p. ej. un SaaS) |
| Anti-Corruption Layer | El downstream traduce el modelo ajeno para proteger el propio |
| Open Host / Published Language | Upstream ofrece una API o esquema estable y documentado para muchos |
| Shared Kernel | Dos equipos comparten una parte pequeña del modelo; exige coordinación alta |
| Separate Ways | Integrarse no compensa; se duplica deliberadamente |
Al integrar con un buró de crédito o un core bancario heredado, una ACL evita que sus códigos y estructuras se filtren por todo tu dominio.
Diseño táctico
- Entidad: identidad que persiste en el tiempo (
Solicitud#123). - Value object: definido por sus atributos, inmutable (
Dinero(1500, COP)). - Agregado: grupo de objetos con una raíz que garantiza invariantes; es la unidad de consistencia transaccional. Referencia a otros agregados por id, no por objeto.
- Evento de dominio: hecho pasado relevante para el negocio (
SolicitudAprobada). - Repositorio y servicio de dominio: acceso a agregados y lógica que no pertenece a una entidad.
public final class Solicitud { // raíz del agregado
private final SolicitudId id;
private Estado estado;
private final Dinero montoSolicitado;
private final List<Object> eventos = new ArrayList<>();
public void aprobar(Dinero montoAprobado, Politica politica) {
if (estado != Estado.EN_EVALUACION)
throw new IllegalStateException("Solo se aprueba en evaluación");
if (montoAprobado.mayorQue(politica.montoMaximo()))
throw new ReglaDeNegocioVioladaException("Excede el máximo");
estado = Estado.APROBADA;
eventos.add(new SolicitudAprobada(id, montoAprobado, Instant.now()));
}
}
La invariante vive en el agregado, no en un controlador ni en un if repartido en tres servicios.
Cómo descubrir los límites
Combina talleres colaborativos: domain storytelling para entender procesos, Event Storming para ordenar eventos de dominio en el tiempo y detectar agregados y contextos, y el Bounded Context Canvas (DDD Crew) para documentar cada contexto: propósito, lenguaje, entradas, salidas y decisiones de negocio.
Antipatrones frecuentes
- Modelo anémico: entidades con getters y setters y toda la lógica en servicios.
- Agregados enormes: cargar el cliente con todos sus créditos y pagos para cambiar un teléfono. Mantenlos pequeños y usa consistencia eventual entre ellos.
- DDD táctico sin estratégico: usar repositorios y value objects en un monolito sin límites no resuelve el acoplamiento.
- Un contexto por tabla: fragmentar en exceso produce microservicios distribuidos acoplados.
Event Storming en tres niveles
| Nivel | Objetivo | Participantes |
|---|---|---|
| Big picture | Visión de todo el dominio y sus puntos de dolor | Negocio, operaciones, tecnología (10–25 personas) |
| Proceso | Detallar un flujo con reglas y actores | Expertos del proceso y equipo |
| Diseño | Agregados, comandos e invariantes para construir | Equipo de desarrollo y experto |
Notación habitual con notas adhesivas: eventos en pasado (naranja: «Solicitud enviada»), comandos (azul: «Aprobar solicitud»), actores (amarillo), políticas («cuando X, entonces Y»), sistemas externos, modelos de lectura y puntos calientes (dudas y conflictos, en rosa).
Ejemplo de context map para una plataforma de crédito
┌──────────────┐ Published Language ┌──────────────┐
│ Originación │ ───── eventos ─────► │ Riesgos │
│ (core) │ ◄── Customer/Supplier│ (core) │
└──────┬───────┘ └──────────────┘
│ eventos
┌──────────▼───────┐ ACL ┌────────────────────┐
│ Cartera │ ◄─────────────── │ Core bancario │
│ (soporte) │ │ heredado (externo) │
└──────┬───────────┘ └────────────────────┘
│ Open Host Service
┌───────────▼──────┐ Conformist ┌───────────────┐
│ Cobranza │ ──────────────────────► │ Proveedor SMS │
└──────────────────┘ └───────────────┘
El mapa muestra, además de dependencias técnicas, relaciones de poder entre equipos: quién se adapta a quién.
Reglas para diseñar agregados
- Modela invariantes reales dentro del límite de consistencia: solo lo que debe ser consistente en la misma transacción.
- Diseña agregados pequeños: una raíz y pocos objetos.
- Referencia otros agregados por identidad, no por objeto.
- Usa consistencia eventual fuera del límite, mediante eventos de dominio.
Ejemplo: «el total pagado no puede superar el saldo» es una invariante del agregado Credito; «al aprobar una solicitud se crea un crédito» se resuelve con un evento entre dos agregados, no en una transacción gigante.
Estructura de código por contexto
originacion/
├── dominio/ # Solicitud, Dinero, Politica, eventos; sin dependencias de frameworks
├── aplicacion/ # casos de uso: EnviarSolicitud, AprobarSolicitud; puertos (interfaces)
├── infraestructura/ # adaptadores: JPA, Kafka, cliente del buró (ACL)
└── web/ # controladores REST, DTOs
Esta organización (arquitectura hexagonal o de puertos y adaptadores) protege el modelo de dominio de los cambios técnicos y se puede vigilar con fitness functions.
Criterios de implementación
Aplica DDD completo en el subdominio core; en los genéricos basta un CRUD o un producto. Alinea los contextos con equipos (Team Topologies) y usa eventos con el transactional outbox para integrarlos sin transacciones distribuidas.
Continúa en las fuentes
Documentación oficial para verificar detalles y explorar más.