1035. Identidad de la lección
1036. Objetivo de aprendizaje
Al terminar esta lección, podrás justificar una dependencia directa o un evento para tres interacciones de juego, identificando responsabilidad, acoplamiento, necesidad de completar la operación, momento del despacho y comportamiento ante fallos.
1037. Por qué importa
Los eventos pueden reducir las referencias directas, pero también pueden ocultar el flujo de control. Si cada interacción se convierte en un evento, una acción pequeña puede activar una cadena de consumidores difícil de seguir. Si todas las interacciones son directas, sistemas que deberían permanecer independientes pueden quedar estrechamente acoplados. El objetivo no es preferir siempre un mecanismo, sino elegir el que haga claras las responsabilidades, las dependencias y las consecuencias.
Este criterio también importa al dirigir a una IA. Un asistente puede generar rápidamente un event bus, una señal, un callback o una llamada a un servicio. Aun así, debes decidir si esa comunicación facilita el razonamiento sobre el sistema.
1038. Conocimientos previos
Ya deberías poder:
- Describir el contrato de evento S-R-P-T-F de Un mensaje es un contrato.
- Identificar sender, receiver, payload, timing y failure behavior.
- Separar la responsabilidad de un sistema de los efectos que otros sistemas pueden presentar.
1039. Concepto principal
Usa una dependencia directa cuando un componente necesita que un colaborador específico complete una operación conocida y esa relación forma parte del flujo principal de la funcionalidad. Usa un evento cuando ha ocurrido un hecho significativo y varios sistemas independientes pueden reaccionar sin que el publicador tenga que conocerlos.
Un evento no es automáticamente mejor por eliminar una referencia directa. Publicadores y suscriptores siguen compartiendo dependencias en el nombre del evento, el contrato del payload, la semántica del despacho, las garantías de orden y la política ante fallos. El publicador no necesita conocer a cada suscriptor, pero el sistema de comunicación sí necesita un contrato explícito.
La pregunta central es:
¿Esta comunicación es una solicitud dirigida a un responsable conocido o un hecho ante el que pueden reaccionar observadores independientes?
Una solicitud para que un responsable conocido ejecute una operación suele favorecer una dependencia directa. Un hecho ya ocurrido con consumidores independientes suele favorecer un evento.
1040. Modelo mental
La prueba de visibilidad y distribución a consumidores
Evalúa cada interacción con estas preguntas:
| Pregunta | Favorece una dependencia directa | Favorece un evento |
|---|---|---|
| ¿Quién posee la operación? | Un colaborador específico es responsable | Ningún consumidor único posee todas las reacciones |
| ¿Qué se comunica? | Una solicitud o comando | Un hecho ya ocurrido |
| ¿Cuántos consumidores se esperan? | Un colaborador conocido | Varios consumidores independientes u opcionales |
| ¿El iniciador necesita que la operación termine o devuelva un valor? | Sí; el flujo principal necesita un resultado o fallo explícito | No; el publicador puede comunicar el hecho sin recopilar el resultado de cada consumidor |
| ¿Qué contrato temporal se necesita? | El contrato de la llamada define cuándo se devuelve el resultado o el fallo | El despacho puede ser síncrono, diferido o mediante una cola, pero debe indicarse de forma explícita |
No supongas que un evento se ejecuta más tarde. Un dispatcher puede invocar a los consumidores inmediatamente en la misma pila de llamadas, aplazar la ejecución hasta una actualización posterior o colocar el mensaje en una cola. El contrato debe especificar el comportamiento aplicable, junto con las garantías de orden y de gestión de fallos.
Después aplica la prueba de trazabilidad:
- ¿Puede un desarrollador seguir el resultado principal desde el iniciador hasta el responsable de la operación mediante pocas referencias explícitas?
- Si se usa un evento, ¿puede localizar su contrato y sus consumidores importantes?
- ¿El nombre del evento representa un hecho estable del dominio o encubre una solicitud como
OpenDoorRequested? - ¿Qué componente debe conocer al colaborador o el contrato del mensaje, y es apropiado que tenga ese conocimiento?
Elige la opción que mantenga visible el flujo principal y conserve la independencia que la interacción realmente necesita.
Dependencia directa frente a evento
Solicitud directa:
PlayerInteraction -> Door.open()
Hecho publicado:
Door -> publica DoorOpened
DoorOpened -> [QuestTracker, AudioSystem, TutorialSystem]
La primera línea nombra al objeto responsable de intentar abrir la puerta. El emisor puede recibir un resultado de éxito o fallo de ese responsable. La segunda comunica que la puerta se abrió; cada consumidor independiente decide si el hecho le importa.
El contrato de DoorOpened debe definir el comportamiento del despacho. Los consumidores podrían ejecutarse de forma síncrona, durante una actualización posterior o a través de una cola. Esa decisión pertenece al contrato de la arquitectura; no se deduce de que la comunicación sea un evento.
1041. Ejemplo concreto
Considera la interacción con un cofre:
- El jugador pulsa el botón de interactuar.
- El controlador de interacción pide al cofre seleccionado que intente abrirse.
- El cofre comprueba su bloqueo y el estado de su inventario.
- El controlador recibe el resultado necesario para la interacción inmediata.
- Si el cofre se abre, otros sistemas pueden reaccionar ante ese hecho.
Un diseño razonable sería:
InteractionController -> Chest.try_open(player_context)
Chest.try_open -> devuelve éxito o fallo
Chest -> publica ChestOpened(chest_id, contents_summary)
ChestOpened -> QuestTracker actualiza objetivos
ChestOpened -> AudioPresentation reproduce el sonido de apertura
ChestOpened -> UI presenta la recompensa
try_open es una dependencia directa porque el controlador necesita que un cofre específico ejecute una operación y devuelva un resultado. Es apropiado que el controlador conozca el cofre seleccionado y el contrato de esa operación.
ChestOpened es un evento porque comunica un hecho con varios consumidores independientes. El cofre conoce el contrato del evento, pero no necesita saber qué consumidores están registrados. Cada consumidor conoce ese mismo contrato y la semántica de despacho que afecta a su reacción.
Un diseño basado solo en eventos, como OpenChestRequested, puede ser válido en una arquitectura con enrutamiento explícito de comandos, pero no es automáticamente una mejora. Si un controlador se dirige a un cofre conocido y necesita el resultado, convertir la solicitud en un evento puede ocultar quién posee la operación y dificultar el seguimiento de la finalización y los fallos.
1042. Errores comunes
Confundir desacoplamiento con calidad
Sustituir cada llamada de método por un evento puede eliminar un import y, al mismo tiempo, añadir acoplamiento indirecto a nombres de mensajes, interpretación del payload, comportamiento del despacho, orden y política ante fallos. El publicador no necesita conocer suscriptores concretos, pero todos los participantes siguen dependiendo del contrato compartido.
Suponer que los eventos son asíncronos
Los eventos pueden despacharse de forma síncrona, diferida o mediante una cola. Si importan el momento, el orden o el aislamiento de fallos, registra esas propiedades en el contrato en lugar de deducirlas de la palabra “evento”.
Publicar llamadas de método disfrazadas
InventoryAddItemRequestedByChestAnimation describe una ruta de implementación, no un hecho estable. Usa una llamada directa para una solicitud dirigida a un responsable conocido, o publica un hecho conciso como ChestOpened cuando lo ocurrido tenga significado independiente.
1043. Práctica guiada
Para cada interacción, elige dependencia directa, evento o una combinación deliberada de ambos. Justifica la elección mediante la responsabilidad, el significado de solicitud o hecho, la distribución a consumidores, la necesidad de completar la operación o devolver un valor, el momento del despacho, los fallos y el conocimiento introducido.
Interacción A — Operación de una puerta
El controlador de interacción del jugador necesita que una puerta bloqueada intente abrirse. El controlador debe mostrar si el intento tuvo éxito o falló. Solo la puerta seleccionada posee las reglas del bloqueo.
Interacción B — Consecuencia de una misión
Una puerta se ha abierto correctamente. El sistema de misiones, la presentación de audio y el sistema de tutorial pueden reaccionar. La puerta no debería saber cuáles de estos sistemas están presentes. El contrato del evento debe indicar si las reacciones son síncronas, diferidas o encoladas.
Interacción C — Solicitud de guardado
El menú de pausa necesita solicitar un guardado y mostrar un resultado o error claro. Un único servicio de guardado posee la serialización y las políticas de almacenamiento.
Usa esta tabla:
| Interacción | Mecanismo | Responsable | ¿Solicitud o hecho? | Consumidores | Finalización, momento y fallos | Conocimiento necesario del colaborador o contrato |
|---|---|---|---|---|---|---|
| A | ||||||
| B | ||||||
| C |
Una respuesta sólida normalmente elegirá una dependencia directa para A, un evento para B y una dependencia directa para C. Una combinación también puede ser válida si conserva el resultado directo que necesita el emisor y publica un hecho separado para observadores independientes. Lo importante es la justificación, no coincidir con un patrón único.
1044. Validación / evidencia
Tu evidencia consiste en una tabla de decisión completa con tres filas y tres explicaciones breves, una por interacción. Cada explicación debe:
- Nombrar el componente responsable de la operación o del hecho.
- Indicar si la comunicación es una solicitud o un hecho ya ocurrido.
- Identificar los consumidores esperados.
- Indicar si el iniciador necesita que la operación termine o devuelva un valor.
- Describir el momento, el orden y el comportamiento ante fallos sin suponer que los eventos se ejecutan más tarde.
- Identificar qué componente debe conocer al colaborador o el contrato del mensaje y explicar si ese conocimiento es apropiado.
- Explicar una consecuencia de escoger el mecanismo alternativo.
Antes de continuar, aplica la prueba de trazabilidad a tus decisiones. Debes poder seguir una solicitud desde su iniciador hasta el responsable de la operación, o seguir un hecho publicado desde su contrato de evento hasta sus consumidores importantes, sin depender de un listener global sin explicar.
1045. Ideas clave
- Una dependencia directa es adecuada para una solicitud dirigida a un responsable conocido cuando el iniciador necesita la finalización o un resultado.
- Un evento es adecuado para un hecho significativo ya ocurrido con consumidores independientes.
- Los eventos pueden ser síncronos, diferidos o encolados; el momento debe formar parte del contrato.
- Los eventos eliminan algunas referencias directas, pero mantienen dependencias compartidas en los contratos y la semántica del despacho.
- Un buen diseño mantiene trazable el flujo principal y sitúa el conocimiento en componentes cuya responsabilidad lo justifica.
1046. Siguiente lección
Continúa con 3.4 — Datos declarativos: Los datos no son comportamiento, donde partirás de estos límites explícitos de comunicación para distinguir entre los datos que recibe un sistema, el comportamiento que los interpreta y el estado que cambia con el tiempo.
1047. Comprobación
Responde estas preguntas por tu cuenta antes de leer las respuestas.
¿Qué situación favorece más claramente una dependencia directa?
Mostrar respuesta y explicación
Respuesta: Un emisor conocido necesita un resultado de un componente que posee la operación.
Por qué: Una dependencia directa es adecuada cuando un emisor conocido necesita que un colaborador específico ejecute una operación y devuelva un resultado. Las demás opciones describen características que favorecen un evento.
¿Por qué sustituir cada llamada de método por un evento puede crear acoplamiento oculto?
Mostrar respuesta y explicación
Respuesta: Publicadores y suscriptores siguen compartiendo dependencias en el contrato del evento y la semántica del despacho, incluidos el momento, el orden y la política ante fallos.
Por qué: Un evento puede eliminar una referencia directa sin eliminar todas las dependencias. Los participantes siguen dependiendo del contrato del mensaje y de cómo se definan el despacho, el momento, el orden y los fallos. Un publicador bien diseñado no necesita conocer los registros de suscriptores concretos.
Una puerta se abre correctamente y los sistemas de misiones, audio y tutorial pueden reaccionar de forma independiente. ¿Qué diseño comunica mejor la situación?
Mostrar respuesta y explicación
Respuesta: La puerta publica el hecho conciso DoorOpened mediante un contrato de despacho explícito.
Por qué: DoorOpened es un hecho ya ocurrido con consumidores independientes. Publicarlo evita que la puerta tenga que conocer a cada consumidor, mientras que el contrato explícito define si el despacho es síncrono, diferido o mediante una cola.
¿Qué debe incluir una justificación sólida del mecanismo de comunicación?
Mostrar respuesta y explicación
Respuesta: Responsabilidad, significado de solicitud frente a hecho, consumidores, necesidad de finalización, semántica de despacho y fallos, y quién debe conocer al colaborador o el contrato.
Por qué: El mecanismo debe justificarse mediante la responsabilidad, las necesidades de información, el conocimiento del contrato y el comportamiento observable de la comunicación. El volumen de código, las reglas universales y la sintaxis del framework no demuestran si el límite es adecuado.