Patrón Singleton en JavaScript ES6+

Microservicios con Node JS y React

El proyecto contiene un submódulo, clónalo con estos parámetros:

git clone –recursive https://github.com/josecho/MicroServicesNatsStreamingBlog.git

Después de clonar el repositorio, vamos a la rama donde se desarrolló el código del que vamos a hablar.

git checkout -b managinNatsClient

Singleton

Singleton es un patrón de diseño creacional que nos permite asegurarnos de que una clase tenga una única instancia, a la vez que proporciona un punto de acceso global a dicha instancia.

El patrón Singleton resuelve dos problemas al mismo tiempo, vulnerando el Principio de responsabilidad única

  • Garantizar que una clase tenga una única instancia.

  • Proporcionar un punto de acceso global a dicha instancia.

En internet puedes encontrar muchas páginas que explican su funcionamiento con mayor profundidad.

Gestión de un cliente NATS

En primer lugar indicar que en la aplicación de la que vamos a hablar, ya lo hicimos antes, hemos implementado un Bus de Eventos llamado NATS Streaming Server para manejar la comunicación entre servicios utilizando eventos.

Bus Event

Durante el proceso de desarrollo, hemos llegado a un punto en el que debemos comenzar a gestionar la comunicación entre los servicios, la publicación y recepción de eventos entre ellos. En otras palabras, debemos gestionar un cliente NATS. Por este motivo, se ha creado una rama llamada managinNatsClient. En ella podemos ver todos los ‘commits’ creados y así seguir todo el proceso de desarrollo llevado a cabo. En concreto, este proceso se ha iniciado en Tickets Service.

git checkout -b managinNatsClient

Veamos el primer paso dado. En este commit podemos ver que cuando se crea un ticket, Tickets Service publica un evento para comunicar esta acción al resto de servicios. Para ello se está utilizando un cliente que aún no está definido ni importado (en este momento falla la compilación).

Publish event

Ya tenemos la capacidad de poder publicar y ahora solo necesitamos una instancia de Nats Client para poder publicar cosas con éxito. Debemos decidir dónde ubicar al cliente en nuestro código.

Client initialized

En un principio el archivo index.ts (módulo de tickets) parece la mejor opción para situr al cliente. Dentro de este archivo podemos ver cómo Mongoose también realiza la conexión y la aplicación funciona correctamente.

Conexión del Singleton de Mongo

Vamos a intentar crear algo muy similar a Mongoose, donde vamos a tener algún tipo de objeto que internamente realiza un seguimiento de algún cliente y lo pone a disposición de todo lo demás que existe dentro de nuestra aplicación.

MongoDB

Cuando nos conectamos con Mongoose, Mongoose guarda internamente un registro de todas las diferentes conexiones que existen. Podemos abrir cualquier otro archivo dentro de nuestro proyecto e importar Mongoose para obtener una copia de Mongoose que ya está conectado a algún servidor. Así que podemos hacer uso libremente de Mongoose a través de los diferentes modelos que hemos creamo para poder alcanzar a MongoDB, hacer consultas y demás.

Después de ejecutar el código, que se muestra en la imagen de arriba, cualquier otro archivo dentro de nuestro proyecto puede importar Mongoose y también obtendrá una versión preconectada e inicializada de Mongoose.

MongoDB save

Usamos Mongoose, técnicamente, a través del Ticket Model, pero podríamos importar Mongoose y usarlo para llegar directamente a nuestra base de datos sin tener que preocuparnos por inicializar ninguna conexión ni nada por el estilo.

Esto es lo que sucede detrás de la escena dentro de Mongoose.

Singleton

Cliente NATS Singleton

Sin embargo, la biblioteca Node NATS Streaming que estamos usando para conectarnos a NATS establece la conexión de una manera muy diferente.

Así que dentro del archivo que realiza las publicaciones (nats-test module:  en este módulo hemos realizado pruebas para comprobar que el servidor NATS respondía correctamente a la publicación y recepción de eventos), cuando nos conectamos con NATS, no hay ninguna conexión interna u objeto interno que realice un seguimiento de esta conexión dentro de esta biblioteca NATS. En cambio, cuando llamamos al método connect de  NATS, nos es devuelto directamente el cliente.

Entonces, necesitamos compartir este cliente de alguna manera entre todos los diferentes archivos existentes dentro de nuestro proyecto.

NATS client

Como mencionamos anterirormente, el archivo index.ts (ticket module) parece ser la ubicación correcta para proceder con la inicialización, es el mismo lugar donde se realiza la conexión con mongo. Vamos a tener un objeto del cliente NATS y queremos compartirlo de alguna manera con un montón de otros archivos dentro de nuestro proyecto.

Pero empieza a surgir un gran problema, lo que se llama dependencia circular.

Algunos archivos se importan entre sí, mutuamente, tal y como se ve en la imagen de arriba y crean este problema. Eso es algo que técnicamente podemos hacer pero sería realmente fantástico si pudiéramos encontrar alguna forma de evitar crear esta dependencia cíclica.

Para evitar esto, como dijimos antes, vamos a intentar construir algo muy similar a Mongoose, donde vamos a tener algún tipo de objeto que internamente realiza un seguimiento del cliente y lo ponga a disposición de todo lo demás dentro de nuestra aplicación. Seguiremos el enfoque que se muestra en el siguiente diagrama.

Singleton NATS Client

Pasos dados en la implementación

Singleton Pattern in JavaScript ES6+

El patrón Singleton, en antiguas versiones de JavaScript está implementado tal y como podemos ver en la página web que mencioné en la parte superior. Concretamente en este enlace, Singleton in TypeScript.

Singleton Patter in Javascript ES6+

Aunque también se puede ver la misma implementación del patrón en diferentes lenguajes de programación en la misma página. Pero lo que tratamos de mostrar en esta publicación es cómo se implementa este patrón en ES6+.

0 comentarios

Dejar un comentario

¿Quieres unirte a la conversación?
Siéntete libre de contribuir!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *