Imagina que en una tienda de tu barrio preparan ese plato que te encanta, ¡tu preferido! Pero… Siempre que intentas comprarlo no hay stock, porque lo han vendido todo.
¿Qué pasaría si supieras cuando está disponible tu comida favorita para ir a comprar de inmediato? Podría existir una solución para este problema cotidiano.
Aplicación en tiempo real
Este tipo de plataformas nos permiten interactuar con la información de manera instantánea y reactiva. Para entender este concepto les hablaré de dos elementos importantes dentro de los principios de las aplicaciones reactivas:
Interactividad: la información fluye en base a interacciones. A medida que el usuario interactúa con la aplicación, la información va respondiendo según el flujo que el usuario siga.
Eventos: procesamiento en paralelo y mensajes asíncronos. Las interacciones del usuario van desencadenando eventos que pueden realizarse de manera asíncrona, sin necesidad de esperar que ciertas tareas terminen para continuar con las siguientes.
Entonces, ¿cómo funcionaría una aplicación en tiempo real y cuándo debo crearla? Imagina que te gustan mucho los videojuegos y hay una tienda física cerca de tu casa. Veremos dos casos donde se obtiene el mismo resultado, pero de maneras diferentes.
Caso 1: visitas la CleverStore regularmente para ver el catálogo nuevo de juegos. Cada cierto tiempo, debes acudir físicamente a revisar la nueva información sobre los videojuegos.
Caso 2: te suscribes a las noticias vía e-mail de CleverStore. Aquí habrá muchas otras personas suscritas a la lista y que serán notificadas cuando haya un nuevo juego disponible, sin necesidad de ir presencialmente a la tienda para enterarse.
Bajo este contexto, puedes crear una aplicación en tiempo real cuando necesites que la información fluya de manera instantánea (como en el caso 2), pero también es posible unir ambas situaciones en una sola aplicación.
Si tomamos como ejemplo una app financiera, sabemos que puedes consultar tus contactos del banco en la aplicación cada vez que la abres (solicitud API Rest – caso 1), porque son datos que cambian poco a lo largo del tiempo. Pero respecto a los abonos a tu cuenta, probablemente sea más útil para ti como usuario recibir una notificación en tiempo real (sockets – caso 2), así estarás al tanto de los movimientos en tu cuenta sin tener que revisar el saldo constantemente.
Sockets
Para entender el concepto de sockets, un protocolo de comunicación bidireccional (Full-Duplex), pensemos un momento en el patrón de diseño Observer. Este utiliza un mecanismo de suscripción para notificar a varios observadores (suscriptores) sobre cualquier evento que suceda con un objeto en particular.
Entendiendo el patrón Observer, veamos cómo funcionan los sockets con respecto a una API Rest:
En el caso de los sockets, estos establecen una comunicación abierta entre el cliente y el servidor de manera bidireccional hasta que uno de los dos se desconecte.
En el caso de una API Rest, el cliente realiza solicitudes al servidor abriendo y cerrando conexión cada vez que requiere información utilizando los verbos HTTP permitidos (GET, POST, PUT, PATCH, DELETE, etc.).
Cuando tenemos clara esta diferencia, podemos ver algunos casos de uso de los sockets en aplicaciones que usamos diariamente:
Redes sociales
Juegos multiplayer
Interacción en un streaming
Documentos colaborativos
Apps deportivas (noticias, resultados, etc.)
Apps financieras (abonos, crypto-monedas, etc.)
¿Cómo funcionan los sockets?
Para comprenderlo revisaremos la siguiente arquitectura, que se usará en nuestra aplicación de ejemplo.
Ojo: los mensajes de la aplicación solo existen en memoria mientras el servidor esté funcionando para efectos del ejemplo. Si eventualmente quieres persistir la información, te recomiendo Firebase o RethinkDB para persistencia de datos en tiempo real.
NodeJS en el Servidor
1) Configuración del Servidor - Eventos a escuchar (.on):
Al iniciar el servidor, se activará la escucha de los siguientes eventos:
2) Configuración de Sockets:
Se mantendrán los usuarios y los mensajes en memoria mientras el servidor esté en funcionamiento. para lo que usaremos variables locales. La variable numberUser se utilizará para asignar un nombre estándar a cada usuario conectado.
3) Al conectar un usuario:
Se asigna un nombre genérico al usuario conectado y se agrega a la lista de usuarios en memoria. Además, se emite a todos el evento active-users con la lista actualizada de usuarios conectados.
4) Evento disconnect:
Se elimina al usuario de la lista en memoria y se emite a todos el evento active-users con la lista actualizada de usuarios conectados.
5) Evento get-users:
Al recibir el evento, se emite al solicitante la lista de usuarios conectados enviando la lista de usuarios en memoria con el evento active-users.
6)Evento message:
Al recibir el evento, se emite a todos el mensaje con el evento new-message.
Angular en el Cliente
1) Configuración de Sockets - Servicio websocket.service:
Se mantendrá el estado de la conexión con el servidor de sockets para mostrarlo en la pantalla de inicio. Se escucharán los eventos de connect y disconnect para saber el estado en tiempo real con el servidor de sockets.
Además se configuran otras dos funcionalidades: una para escuchar eventos y otra para emitir eventos sobre la infraestructura de sockets.
2) Manejo de eventos de Sockets - Servicio chat.service:
Emitir usuarios: cuando el usuario entra en la app, se emite get-users para obtener la lista de usuarios conectados.
Emitir un mensaje: cuando el usuario escribe un mensaje, se emite a todos quienes están conectados al servidor de sockets.
Escuchar evento active-users: recibe la lista de usuarios conectados cuando el servidor la emite.
Escuchar evento new-message: recibe cada nuevo mensaje cuando el servidor lo emite.
En conclusión, la aplicación interactúa entre el cliente y el servidor mediante eventos. Escuchar y emitir estos eventos nos permite darle dinamismo a la comunicación, reaccionando a las acciones del usuario. Gracias a lo anterior, la información se mantiene en un flujo activo en ambas direcciones, tanto desde el cliente hacia el servidor como viceversa, dándonos una sensación de inmediatez.
Si tu aplicación requiere de información instantánea o reactiva en base a acciones de sus usuarios, podrías sacar partido del uso de los sockets. En el próximo artículo sobre este tema veremos cómo complementar los sockets con APIs REST para hacer un uso más eficiente de los recursos.