Saltar al contenido principal
BACK-701 • 32 Horas • Nivel Avanzado / Principal Domain Architect

Ingeniería de Requerimientos Asistida por IA, Domain-Driven Design (DDD), Contratos OpenAPI 3.1 y Pact

Destilación estratégica de Bounded Contexts, Context Mapping, EventStorming a código ejecutable, invariantes transaccionales en Aggregate Roots, contratos API-First con OpenAPI 3.1 / JSON Schema 2020-12 y Consumer-Driven Contract Testing.

Módulo 1: Módulo 1: Domain-Driven Design (DDD) Estratégico: Subdominios, Bounded Contexts y Context Mapping

Clasificación Estratégica de Subdominios (Core, Supporting, Generic) y Fronteras Lingüísticas de Bounded Contexts (55 min)

Clasificación Estratégica de Subdominios (Core, Supporting, Generic) y Fronteras Lingüísticas de Bounded Contexts

1. Por qué Fracasan los Modelos de Datos Corporativos "Canónicos" Únicos

Intentar construir una única clase o tabla global Customer o Product compartida por Ventas, Contabilidad, Logística de Bodega y Cobranza produce un Monolito de Dios (Big Ball of Mud) con $180$ columnas anulables donde cambiar una regla de empaque rompe el cierre contable.

En Domain-Driven Design (Eric Evans / Vaughn Vernon), dividimos el espacio del problema en Subdominios según su diferenciación competitiva y aislamos el espacio de la solución en Bounded Contexts donde cada término del Lenguaje Ubicuo tiene un significado matemático inequívoco:

| Tipo de Subdominio | Ventaja Competitiva | Volatilidad de Reglas | Estrategia de Inversión Arquitectónica | | :--- | :--- | :--- | :--- | | Core Domain | Máxima (El secreto comercial que genera ingresos/margen único) | Muy Alta | Ingeniería in-house de élite, DDD táctico completo, Arquitectura Hexagonal pura | | Supporting Subdomain | Baja (Necesario para operar el Core, pero específico de la empresa) | Media | CRUD modular limpio / Transaction Script bien testeado sin sobre-ingeniería | | Generic Subdomain | Cero (Problema resuelto universalmente: OAuth2, Pasarela de Pago, Envío de Email) | Baja | Comprar SaaS / Adoptar estándar Open-Source tras un Anti-Corruption Layer |

Topologías de Context Mapping: Anti-Corruption Layer (ACL), Open Host Service y Conformist (50 min)

Topologías de Context Mapping: Anti-Corruption Layer (ACL), Open Host Service y Conformist

1. Protección del Dominio Core frente a Sistemas Legacy (Anti-Corruption Layer)

Cuando tu nuevo microservicio de originación crediticia debe integrarse con un Core Bancario AS/400 o SAP de hace $25$ años que devuelve códigos crípticos (COD_EST_04 = "R", fechas en formato juliano), jamás debes permitir que esos tipos de datos ni nombres entren a tu modelo de dominio.

flowchart LR
    LEG["Legacy Core ERP (Modelo Hostil / Acoplado)"] --> ACL["Anti-Corruption Layer (Translator + Facade + Adapter)"]
    ACL --> CORE["Nuevo Bounded Context (Modelo de Dominio Puro e Incorrupto)"]

El Anti-Corruption Layer (ACL) traduce en la frontera el dialecto externo hacia Value Objects y Entidades propias de tu lenguaje ubicuo.'

De Entrevistas Ambiguas a Especificaciones Ejecutables: EventStorming y Criterios Gherkin BDD sin Ambigüedad (50 min)

De Entrevistas Ambiguas a Especificaciones Ejecutables: EventStorming y Criterios Gherkin BDD sin Ambigüedad

1. La Gramática Causal de EventStorming (Alberto Brandolini)

Toda especificación funcional se modela como una cadena causal determinista de 5 elementos:

$\text{Actor} \longrightarrow \text{Command (Imperativo)} \longrightarrow \text{Aggregate (Invariantes)} \longrightarrow \text{Domain Event (Pasado Inmutable)} \longrightarrow \text{Policy / Read Model}$

Un requerimiento está sub-especificado (y debe rechazarse antes de escribir código) si carece de: 1. Precondiciones cuantificadas del estado del Agregado. 2. Qué invariantes exactos impiden ejecutar el Comando. 3. Qué Evento de Dominio se emite en caso de éxito y qué compensación ocurre en caso de fallo.

Módulo 2: Módulo 2: DDD Táctico: Diseño de Aggregate Roots, Invariantes Transaccionales y Value Objects

Las 4 Reglas de Oro de Diseño de Agregados (Vaughn Vernon): Fronteras de Consistencia ACID vs Eventual (55 min)

Las 4 Reglas de Oro de Diseño de Agregados (Vaughn Vernon): Fronteras de Consistencia ACID vs Eventual

1. Definición Formal de un Aggregate Root

Un Agregado no es un simple grafo de clases con relaciones @OneToMany en un ORM; es un límite de consistencia transaccional atómica.

Las 4 Reglas Inmutables para Diseñar Agregados Escalables

1. Proteger Invariantes de Negocio Reales dentro de la Frontera del Agregado: Un invariante es una regla algebraica que debe cumplirse al finalizar cualquier transacción (ej. $\sum \text{ Asientos Deudores} = \sum \text{ Asientos Acreedores}$). 2. Diseñar Agregados Pequeños: Si un agregado Customer carga en memoria una colección de $50,000$ Orders históricas cada vez que el cliente cambia su dirección, el sistema colapsa por memoria y contención de bloqueos. 3. Referenciar Otros Agregados ÚNICAMENTE por su Identidad (Value Object ID): Prohibido tener referencias de objeto directas a otros Aggregate Roots; almacena readonly customerId: CustomerId en lugar de customer: Customer. 4. Una Sola Instancia de Agregado Modificada por Transacción de Base de Datos: La coordinación entre distintos agregados se realiza mediante Eventos de Dominio y Consistencia Eventual.'

Implementación en Producción de un Aggregate Root con Eventos de Dominio y Concurrencia Optimista (55 min)

Implementación en Producción de un Aggregate Root con Eventos de Dominio y Concurrencia Optimista

export interface DomainEvent {
  readonly eventId: string;
  readonly aggregateId: string;
  readonly occurredAtIso: string;
  readonly eventName: string;
}

export class CreditLineAggregate { private readonly uncommittedEvents: DomainEvent[] = [];

private constructor( public readonly id: string, private limitCents: bigint, private utilizedCents: bigint, private version: number ) {}

public static reconstitute( id: string, limitCents: bigint, utilizedCents: bigint, version: number ): CreditLineAggregate { return new CreditLineAggregate(id, limitCents, utilizedCents, version); }

/ * Invariante de Dominio: El saldo utilizado jamás puede superar el cupo autorizado, * y toda disposición válida incrementa la versión de concurrencia optimista. */ public drawFunds(amountCents: bigint, eventId: string, nowIso: string): void { if (amountCents <= 0n) { throw new Error('DRAW_AMOUNT_MUST_BE_POSITIVE'); } if (this.utilizedCents + amountCents > this.limitCents) { throw new Error('INVARIANT_VIOLATION_CREDIT_LIMIT_EXCEEDED'); }

this.utilizedCents += amountCents; this.version += 1;

this.uncommittedEvents.push({ eventId, aggregateId: this.id, occurredAtIso: nowIso, eventName: 'CreditLineFundsDrawn.v1' }); }

public pullDomainEvents(): DomainEvent[] { const copy = [...this.uncommittedEvents]; this.uncommittedEvents.length = 0; return copy; }

public get currentVersion(): number { return this.version; } }

Erradicación del Anti-Patrón de Modelo de Dominio Anémico (Martin Fowler) mediante Value Objects Inmutables (50 min)

Erradicación del Anti-Patrón de Modelo de Dominio Anémico (Martin Fowler) mediante Value Objects Inmutables

1. Anatomía de un Modelo Anémico vs Modelo de Dominio Rico

En un Modelo Anémico, las "Entidades" son simples bolsas de datos con getters y setters públicos sin validación, y miles de líneas de reglas de negocio están duplicadas en servicios procedimentales (OrderService, BillingHelper, OrderUtils). En un Modelo Rico, los constructores validan invariantes desde el nacimiento (Parse, Don't Validate) y las mutaciones solo ocurren mediante métodos de negocio con significado semántico.

Módulo 3: Módulo 3: Arquitectura Contract-First con OpenAPI 3.1, JSON Schema 2020-12 y RFC 9457

Arquitectura API-First con OpenAPI 3.1.0: Compatibilidad 100% con JSON Schema Draft 2020-12 y Tipos Polimórficos (55 min)

Arquitectura API-First con OpenAPI 3.1.0: Compatibilidad 100% con JSON Schema Draft 2020-12 y Tipos Polimórficos

1. Diferencias Críticas entre OpenAPI 3.0 y OpenAPI 3.1.0

En OpenAPI 3.0 existía un dialecto incompatible con JSON Schema estándar (usaba nullable: true propietario y no soportaba prefixItems ni $dynamicRef). OpenAPI 3.1.0 es un superconjunto exacto de JSON Schema Draft 2020-12: 1. Reemplaza nullable: true por arreglos de tipos estándar: type: ["string", "null"]. 2. Soporta webhooks como ciudadano de primera clase al mismo nivel que paths. 3. Permite validación estricta de uniones discriminadas con oneOf + discriminator.mapping y cierre contra inyección de propiedades con additionalProperties: false.

Estandarización de Errores HTTP (RFC 9457 Problem Details) e Idempotencia Transaccional (Idempotency-Key) (55 min)

Estandarización de Errores HTTP (RFC 9457 Problem Details) e Idempotencia Transaccional (Idempotency-Key)

1. Estructura Canónica de Errores de API según IETF RFC 9457 (Reemplazo de RFC 7807)

Prohibido devolver respuestas de error arbitrarias como { "error": true, "msg": "falló" }. Toda API empresarial devuelve Content-Type: application/problem+json siguiendo RFC 9457:

{
  "type": "https://api.sentinel.internal.local/problems/credit-limit-exceeded",
  "title": "Límite de línea de crédito excedido",
  "status": 422,
  "detail": "La disposición solicitada de 500,000 CLP supera el cupo disponible de 120,000 CLP.",
  "instance": "/v1/credit-lines/CL-9941/draws/9b1deb4d",
  "traceId": "4bf92f3577b34da6a3ce929d0e0e4736"
}

2. Máquina de Estados del Header Idempotency-Key (IETF Draft)

Cuando un cliente envía POST /v1/payments con Idempotency-Key: : - Si la clave ya existe con un hash SHA-256 de payload distinto, el servidor responde inmediatamente HTTP 422 Unprocessable Content (uso indebido de clave idempotente con parámetros diferentes). - Si la primera petición aún está en vuelo (status = IN_PROGRESS), responde HTTP 409 Conflict con Retry-After: 1. - Si ya finalizó, devuelve exactamente el mismo código de estado y cuerpo JSON almacenados sin volver a cobrar.

Detección Automatizada de Breaking Changes en CI/CD: Ley de Postel, Evolución Aditiva y Headers Sunset (RFC 8594) (50 min)

Detección Automatizada de Breaking Changes en CI/CD: Ley de Postel, Evolución Aditiva y Headers Sunset (RFC 8594)

1. Álgebra de Varianza en Contratos API (Contravarianza en Request, Covarianza en Response)

Un cambio en una especificación OpenAPI 3.1 rompe la compatibilidad hacia atrás (Breaking Change) si y solo si: 1. En el Request (Contravariante): Hace más estricto lo que el servidor exige (ej. agregar una nueva propiedad a required, reducir maxLength, eliminar un valor de un enum de entrada). 2. En el Response (Covariante): Hace menos garantizado lo que el servidor devuelve (ej. eliminar una propiedad existente, cambiar un campo de obligatorio a opcional/nullable, o agregar un nuevo valor a un enum de respuesta cuando el cliente tiene validación cerrada).'

Módulo 4: Módulo 4: Consumer-Driven Contract Testing (Pact), Auditoría SQL de Contratos y Certificación

Consumer-Driven Contract Testing con Pact: Eliminación de Entornos E2E Frágiles y Matriz can-i-deploy (50 min)

Consumer-Driven Contract Testing con Pact: Eliminación de Entornos E2E Frágiles y Matriz can-i-deploy

1. Por qué los Tests de Integración E2E Compartidos No Escalan a 100 Microservicios

Mantener un entorno staging donde $80$ microservicios deben estar levantados simultáneamente para correr pruebas E2E produce fallos falsos constantes. Con Consumer-Driven Contracts (Pact): 1. Durante el test unitario del Consumidor (ej. BFF / Web), sus expectativas se graban contra un Mock Server local generando un archivo JSON de contrato (pact.json) que se publica en el Pact Broker. 2. Durante el pipeline CI del Proveedor (ej. Payments Service), el proveedor reproduce las peticiones del pact.json contra su propio controlador real en aislamiento y publica el resultado de verificación. 3. Antes de desplegar a producción, el comando pact-broker can-i-deploy consulta la matriz de versiones verificadas en $O(1)$.

Laboratorio Práctico SQL: Auditoría del Registro de Idempotencia Financiera y Detección de Colisiones de Payload (60 min)

Laboratorio Práctico SQL: Auditoría del Registro de Idempotencia Financiera y Detección de Colisiones de Payload

Contexto del Laboratorio

Operas la pasarela de pagos API-First de Sentinel Core. La tabla api_idempotency_attempts registra cada intento recibido en los endpoints POST /v1/transfers (attempt_id, tenant_id, idempotency_key, payload_sha256, amount_cents).

Reglas de Negocio a Consultar

Para cada combinación de tenant_id e idempotency_key, calcula: 1. total_attempts: número total de peticiones recibidas con esa misma idempotency_key (COUNT(*)::INT). 2. distinct_payloads: cantidad de hashes payload_sha256 distintos enviados bajo la misma clave (COUNT(DISTINCT payload_sha256)::INT). 3. effective_charged_cents: - Si distinct_payloads > 1, el cliente violó el protocolo enviando cuerpos distintos con la misma clave, pero el primer intento válido es el menor attempt_id; sin embargo, para este reporte queremos calcular el monto ahorrado de cobro duplicado (duplicate_saved_cents): (SUM(amount_cents) - MIN(amount_cents))::BIGINT. 4. rfc_resolution_status: - 'HTTP_422_PAYLOAD_MISMATCH_ATTACK' si distinct_payloads > 1. - 'HTTP_200_IDEMPOTENT_REPLAY_SAVED' si distinct_payloads = 1 y total_attempts > 1. - 'HTTP_201_SINGLE_EXECUTION' si total_attempts = 1. 5. Ordena el resultado por duplicate_saved_cents DESC, idempotency_key ASC.

Examen de Certificación: Principal DDD, Requirements & OpenAPI 3.1 Architect (BACK-701) (45 min)

Examen de Certificación: Principal DDD, Requirements & OpenAPI 3.1 Architect (BACK-701)

Valida tu dominio técnico sobre Domain-Driven Design estratégico y táctico, fronteras de Agregados, contratos OpenAPI 3.1.0, manejo de errores RFC 9457 y pruebas de contrato impulsadas por el consumidor (Pact).