El patrón Observer en TypeScript: Cuándo no necesitas RxJS
El patrón Observer sigue siendo uno de los mecanismos fundamentales para construir sistemas reactivos, pero en el ecosistema TypeScript es fácil caer en la tentación de instalar una librería pesada cuando una solución nativa sería suficiente. La decisión no debería basarse en lo que está de moda, sino en la forma real del problema que tenemos delante. Cuando un equipo de desarrollo evalúa si incluir RxJS en un proyecto, lo que realmente está evaluando es el coste de mantenimiento futuro frente a la complejidad intrínseca de los flujos de datos que manejará la aplicación.
En la práctica, gran parte de los casos de uso reactivos en una aplicación corporativa son simples notificaciones de un solo canal con retardos o cancelaciones. Node.js ofrece desde hace tiempo un EventEmitter nativo que, correctamente tipado con genéricos sobre un mapa de eventos, proporciona toda la seguridad que TypeScript puede dar sin añadir ni una sola dependencia. El navegador, por su parte, expone EventTarget y AbortController, que combinados resuelven la gestión de ciclo de vida de los listeners sin necesidad de librerías externas. En Q2BSTUDIO, cuando desarrollamos aplicaciones a medida, siempre priorizamos que la pila técnica se ajuste exactamente al dominio del problema, evitando sobreingeniería que luego se convierte en deuda técnica.
La clave está en distinguir entre un problema de composición de streams y una simple notificación con debounce. Un buscador con autocompletado, por ejemplo, entra en la segunda categoría. Implementarlo con setTimeout y un AbortController tipado es directo y comprobable. Sin embargo, cuando el sistema requiere combinar tres o más fuentes asíncronas —como filtros, búsquedas y selecciones de ordenación— que además deben sincronizarse con el último valor de cada una y compartir resultados entre suscriptores tardíos, entonces sí estamos ante un escenario donde operadores como combineLatest, switchMap y shareReplay marcan la diferencia. En esos casos, RxJS deja de ser un lujo y se convierte en la herramienta que mantiene el código legible y libre de bugs de sincronización.
Más allá de la comparativa técnica, hay un factor estratégico que muchas empresas pasan por alto: cada dependencia que se añade a un proyecto tiene un coste de aprendizaje, actualización y posibles conflictos de versiones. Por eso, antes de incorporar una librería reactiva, merece la pena analizar si el equipo podría resolver el mismo problema con tipos discriminados y un bus de eventos tipado. En proyectos que integran ia para empresas o agentes IA, donde los flujos de datos suelen ser complejos pero no necesariamente multimodales, a menudo es mejor comenzar con una solución ligera y escalar solo cuando la complejidad lo exija.
También conviene considerar el contexto del runtime. En entornos que ya consumen servicios cloud aws y azure, la integración con servicios de mensajería como SQS, EventBridge o Service Bus ya proporciona buena parte de la semántica reactiva. En ese caso, el frontend o el backend ligero solo necesita un adaptador tipado, no toda la parafernalia de una librería de streams. Lo mismo ocurre cuando se trabaja con ciberseguridad y pentesting: los sistemas de auditoría y alertas suelen seguir patrones de eventos sencillos donde un EventTarget nativo es más que suficiente y, además, evita vectores de ataque asociados a dependencias innecesarias.
La madurez técnica de un equipo se nota en su capacidad para elegir el nivel de abstracción adecuado. No se trata de demonizar RxJS, sino de usarlo donde realmente aporta valor: composición declarativa de múltiples fuentes, manejo explícito de contrapresión y árboles de cancelación profundos. Si el problema cabe en seis líneas con EventEmitter o CustomEvent, meter una librería de cientos de kilobytes solo porque es más elegante es una decisión que lastrará el proyecto durante meses. En Q2BSTUDIO aplicamos este criterio tanto en desarrollos de software a medida como en proyectos de servicios inteligencia de negocio o power bi, donde la simplicidad del modelo de eventos permite mantener dashboards ligeros y fáciles de mantener.
En definitiva, leer la forma del problema antes de escribir la solución es la habilidad que separa un código resiliente de uno sobrecargado. TypeScript nos da las herramientas para tipar buses de eventos nativos de forma segura. Aprovechémoslas antes de buscar atajos con dependencias externas. Cuando el día llegue en que realmente necesites combinar tres streams con cancelación y repetición, sabrás que es el momento de importar la librería. Hasta entonces, el runtime que ya tienes es suficiente.
Comentarios