Tabla de Contenidos

04.2 - Casos de uso y colaboración entre módulos

Un caso de uso coordina una operación completa de la aplicación: obtiene las entradas, invoca los servicios necesarios y organiza el resultado. Expresa un flujo de aplicación; no debe contener las reglas internas de los modelos ni sustituir a los servicios de dominio.

1. Responsabilidad del caso de uso

El caso de uso coordina servicios y dependencias necesarias para completar una operación. No invoca otro caso de uso: cada caso de uso representa un punto de entrada independiente al comportamiento de aplicación.

ControllerCancelOrderOrderServiceinvocacoordina

Invocar un caso de uso desde otro acopla flujos que deberían poder componerse y reutilizarse de forma independiente. Si varios flujos necesitan una misma regla, se comparte mediante un servicio de dominio, no encadenando casos de uso.

2. Servicio o caso de uso: ¿quién coordina?

Una colaboración pertenece a un servicio cuando forma parte de su comportamiento de dominio de manera consistente. Si depende del flujo concreto que se está ejecutando, la coordinación corresponde al caso de uso. Los servicios pueden colaborar con otros servicios; si necesitan otro módulo, usan su API pública.

Situación Responsable de coordinar
Cada cancelación debe liberar la reserva de stock El servicio de pedidos colabora con la API pública de stock en cada cancelación
Solo un flujo específico envía una notificación adicional al cancelar El caso de uso de ese flujo invoca la API pública correspondiente

El criterio de “siempre” ayuda a distinguir el comportamiento estable de un servicio de una decisión propia de un flujo, pero no es una regla mecánica: las invariantes del dominio deben quedar protegidas aunque un flujo sea su único consumidor. Toda colaboración entre módulos cruza el límite mediante la API pública del módulo requerido, no mediante sus servicios privados.

3. API pública y contratos entre módulos

Cuando un módulo necesita capacidades de otro, utiliza su API pública interna. No accede directamente a servicios privados ni a modelos internos del módulo proveedor.

Módulo de pedidosMódulo de stockCancelOrderUseCaseOrderServiceStockModuleApiStockServiceStockModelcoordinasiempre libera la reservaeste flujo solicita otra operacióndelega internamente

La API pública interna define un contrato entre módulos. Puede ser una interfaz Java y sus DTO; no implica una llamada HTTP ni convierte el monolito modular en una aplicación distribuida.

4. DTO y mapeo entre límites

Cuando se usan modelos de dominio enriquecidos, no conviene exponerlos directamente al cruzar límites entre capas o módulos. Se pueden intercambiar DTO que expresen los datos necesarios para cada contrato; dentro del módulo, los modelos conservan su comportamiento e invariantes. Es una decisión de diseño, no un requisito de todos los estilos de dominio.

MapStruct genera implementaciones de mapeadores entre DTO y modelos. El mapeo transforma datos; las decisiones de negocio siguen perteneciendo a servicios y modelos.

La construcción e inyección de los mapeadores generados se resuelve en la composición de la aplicación, sin añadir dependencias de Spring al dominio.

@Mapper
public interface StockMapper {
    StockRequestDto toDto(StockRequest request);
    StockResult toModel(StockResultDto dto);
}

La interfaz pública y sus DTO pertenecen al contrato que ofrece el módulo. Los tipos internos no deben filtrarse a través de ese contrato.

5. Pruebas de casos de uso

Probar el caso de uso como coordinador:

No invocar la implementación completa de otros módulos en cada prueba del caso de uso: se comprueba el contrato de colaboración, mientras que la API pública y sus implementaciones tienen sus propias pruebas.

@Test
void notifiesStockWhenThisFlowCancelsOrder() {
    when(orderService.cancel(42L)).thenReturn(cancelledOrder);

    cancelOrder.execute(42L);

    verify(stockModuleApi).releaseReservation(
            new ReleaseReservationRequest(42L));
}

Los casos de uso coordinan flujos y colaboran con servicios o APIs públicas de módulos. No deben invocar otros casos de uso; las reglas compartidas pertenecen a servicios o modelos de dominio.