Arquitectura DDD — Entrevista
Fuente: Guía de estudio Laravel+Vue (proyecto Supermercado DDD)
dddhexagonalarquitectura
Tarjetas
¿Por qué el dominio no usa Eloquent?
Para mantenerlo puro y portable. Si el dominio depende de Eloquent, no se puede testear sin DB ni cambiar de ORM.
¿Por qué Dinero usa centavos (int)?
Float tiene error de precisión (0.1 + 0.2 != 0.3). Con enteros en centavos, los cálculos siempre son exactos.
¿Qué son ports y adapters?
Ports = interfaces del dominio. Adapters = implementaciones concretas. Permite cambiar la infraestructura sin tocar el dominio.
¿Qué es un aggregate root?
La entrada única a un cluster de objetos. Protege invariantes. En el proyecto Supermercado, `Venta` es el aggregate root de `LineaDeVenta`.
¿Cuáles son las capas en DDD?
Domain (reglas, PHP puro), Application (casos de uso), Infrastructure (DB, adaptadores), Presentation (controllers).
¿Cuál es la regla de dependencias?
Siempre hacia adentro. Domain no depende de nadie. Infrastructure depende de Domain (implementa interfaces).
¿Cómo testeo el dominio sin DB?
Las clases de dominio son PHP puro. En los tests Unit, instancias los objetos directamente (`new Venta(...)`) sin necesidad de base de datos.
¿Qué es un evento de dominio?
Algo que pasó en el dominio (ej: CompraRealizada). El aggregate lo graba; los listeners reaccionan. Desacopla.
¿Qué es el context mapping?
El mapa de relaciones entre bounded contexts: quién es upstream o downstream de quién, y qué patrón gobierna cada frontera (ACL, shared kernel, customer/supplier, conformist).
¿Qué es el lenguaje ubicuo (ubiquitous language)?
El vocabulario compartido entre expertos y código: los mismos términos en la conversación, las clases y los tests. En Supermercado: "carrito" y `Carrito`, nunca "order".
¿Qué es un Shared Kernel y cuál es su riesgo?
Una porción de modelo compartida por dos contexts, típicamente value objects (`Dinero` usado por Catálogo y Ventas). El riesgo: modificarla obliga a coordinar a ambos equipos.
¿Qué pasa si una regla de negocio cruza dos agregados?
No se fuerza en una transacción: un agregado es dueño de la regla y el resto se actualiza por eventos de dominio con consistencia eventual (`Venta` emite `VentaRegistrada` y Stock descuenta aparte).
¿Cuándo un repository es sobreingeniería?
Cuando el caso de uso es CRUD puro sin reglas que proteger ni proyecciones raras: usar el ORM directo desde el application service hace el mismo trabajo con menos archivos.
¿Repository o DAO?
El repository habla del dominio: una colección de agregados (`$ventas->add($venta)`, `ofCliente()`); el DAO habla de la base: métodos centrados en tablas y columnas, del lado de infraestructura.
¿Cuándo modelás como Entity y cuándo como Value Object?
Value Object si el valor lo define todo y no cambia (`Dinero(150, "ARS")`); Entity si necesita una identidad que persiste aunque cambien sus datos (la venta #42 sigue siendo esa venta con otras líneas).
¿Qué es una capa anticorrupción (ACL)?
Un traductor en la frontera que convierte el modelo externo al tuyo: `OrderDTO` del ERP entra y sale tu `Venta`, y las rarezas del sistema viejo mueren ahí.
¿Devolvés un DTO o el aggregate desde el controller?
Un DTO plano con contrato explícito. El aggregate no cruza la frontera de presentación: exponerlo permite mutarlo por fuera de sus métodos y acopla la API a su estructura interna.
¿Puerto primario o secundario?
Primario: por donde el mundo entra a tu app (la interfaz del caso de uso que el controller invoca). Secundario: lo que tu app consume hacia afuera (`RepositorioDeVentas`, `PasarelaDePago`), implementado por infraestructura.
¿Qué es CQRS y cuándo NO conviene?
Separar la escritura (commands sobre agregados) de la lectura (queries a proyecciones). No conviene si no hay asimetría real entre leer y escribir: pagás dos modelos más sincronización por nada.
¿Qué es event sourcing y qué precio tiene?
Guardar la secuencia de eventos (`VentaRegistrada`, `DescuentoAplicado`) como fuente de verdad y reconstruir el estado replayeándolos, en lugar de persistir el estado final.
¿Qué es una saga (process manager)?
Un coordinador de una transacción distribuida: cada paso local emite un evento, la saga escucha y dispara el siguiente, con acciones de compensación si algo falla (pago rechazado → liberar stock reservado).
¿Qué resuelve un command bus?
Desacoplar el disparador del ejecutor: el controller hace `bus->dispatch(new RegistrarVentaCommand(...))` y un handler lo procesa sin que ninguno conozca al otro.
¿Modular monolith o microservicios?
Modular monolith: un solo deploy con módulos por bounded context y fronteras duras (sin compartir modelo ni tablas). Microservicios, cuando los contexts escalan o despliegan a ritmos genuinamente distintos.
¿Cómo detectás un distributed monolith?
Servicios separados que se deployan y se rompen juntos: un cambio en Producto exige actualizar Stock, Ventas y frontend en orden, y nada funciona sin el resto levantado.
¿Qué es vertical slice architecture?
Cortar el código por feature de punta a punta (`AgregarAlCarrito`: controller, use case y query viven juntos) en vez de por capas técnicas globales, con el dominio compartido en el centro.
¿Qué es un Bounded Context?
Un límite explícito donde un modelo y su lenguaje son consistentes. En Supermercado: `Producto` de Catálogo (precio, descripción) es distinto de `Producto` de Stock (cantidad por depósito).
¿Un módulo interno equivale a un Bounded Context?
No. El módulo es una división de código dentro de un mismo modelo (`App\Domain\Stock`); el Bounded Context implica modelo y lenguaje propios, y a veces su propia base de datos y deploy.
¿Domain service o Application service?
El domain service contiene una regla de negocio que no cabe en una entity (`CalculadorDeDescuentos`, PHP puro); el application service solo orquesta: transacción, repos, eventos, sin decidir nada del negocio.
¿Qué es DDD?
Domain-Driven Design. Organiza el código alrededor del dominio (reglas de negocio), separándolo del framework.
¿Qué es un value object?
Objeto inmutable identificado por sus valores. `Dinero(150, "ARS")`. No tiene ID. Auto-validante.