Algunos consejos que todo desarrollador de Node.js debería saber en sus inicios

Algunos consejos que todo desarrollador de Node.js debería saber en sus inicios

Me encuentro desarrollando en Javascript por un buen tiempo ya y en mi experiencia me he dado cuenta que todo lenguaje de programación tiene esos pequeños trucos y practicas que todo el mundo debería tener en cuenta.

Muchas veces, nosotros los programadores, tendemos a hacer algunas cosas un poco más complicadas que terminan en algún grado de confusion y caos dentro de un ambiente de desarrollo.

Bill Gates dijo en algún momento que contrataría más vagos, dado que si le das una tarea difícil a un vago, buscara la manera de hacerla mas sencilla. A veces, inmersos en nuestro backlog de requerimientos, deberíamos poder tomarnos un tiempo para adoptar algunos trucos que nos permitan facilitarnos la vida y mejorar nuestra performance.

Sin mas, he aquí algunas de las lecciones aprendidas que podrían mejorar nuestra vida si estamos ingresando en el mundo de desarrollo en Javascript con NodeJS.

Utiliza el shell de node.js

Si lo que estas buscando es probar una función a fin de ver cómo se comporta, usar el shell de Node.js puede ser la forma mas rapida. Con solo teclear nodeen la consola. Se puede escribir el código en un editor de texto de preferencia, sin embargo cuando uno esta realizando una prueba sencilla pero al finalizar la ejecución de la misma, el shell de Node.js, no cuenta con una función de salida como ser exit o quit como tienen otras herramientas CLI. Se tiene que escribir una sentencia valida que finalice el proceso. Este es el comando que vas a necesitar para eso:

$process.exit(0)

La primera vez que utilice Node.js no tenia idea de cómo salir del shell y tuve que buscar en google la manera de hacerlo.

Se puede salir del shell utilizando la combinación Ctrl/Cmd + D pero no va a matar el proceso, simplemente nos sacara del shell.

Evitar utilizar “*” en las dependencias en producción

Dentro del archivo package.json, se pueden especificar las versiones de las dependencias de nuestra aplicación o dejar simplemente el wildcard “*” para que utilice siempre la ultima version, esto es bueno para mantener actualizada nuestra solución con las ultimas versiones de los módulos que pueden incluir mejoras, correcciones de errores, nuevos features. Pero todo esto hace sentido siempre y cuando nos encontremos dentro de nuestro entorno de desarrollo. Si surge algún incidente de incompatibilidad es mas fácil solucionarlo y no vamos a tener que gestionar un incidente de manera reactiva en producción.

//En vez de utilizar esto:
“dependencies”: {
    “clustered-node”: “*”
}
//utilice esto:
“dependencies”: {
    “clustered-node”: “~0.0.10”
}

Mantener esta notación en un entorno productivo para las dependencias conlleva a un riesgo muy grande. Nunca vamos a saber a priori qué paquetes pueden dejar de funcionar como lo hacían y hacer que nuestra solución termine en una caída.

Utilizar nodemon en desarrollo, pm2 en producción

Cuando uno comienza en el mundo de desarrollo de aplicaciones en Node.js una de las cosas mas frustrantes es la utilización del comando Cmd + C para detener la ejecución de una instancia y luego ejecutarla nuevamente.

En su momento y recurriendo nuevamente a Google, me encontré un paquete infaltable en todos mis desarrollos: nodemom

GitHub - remy/nodemon: Monitor for any changes in your node.js application and automatically restart the server - perfect for development
Monitor for any changes in your node.js application and automatically restart the server - perfect for development - GitHub - remy/nodemon: Monitor for any changes in your node.js application and a...

Se puede instalar mediante la utilización del siguiente comando:

npm install -g nodemon

en este caso -g implica la instalación de manera global dentro de nuestro sistema (asumiendo que contamos con npm). Cabe aclarar que, si utilizamos algún gestor de versiones de node.js como nvm, y cambiamos de version puede que tengamos que volver a ejecutar el comando para volver a instalar como dependencia global el paquete, esta vez en el nuevo contexto. Una vez instalado podemos ejecutar un programa de la siguiente manera:

nodemon <miprograma.js>

De esta manera vamos a estar diciendo a nodemon que monitoree cambios en todos los scripts dentro de nuestro proyecto así como también aquellas dependencias del mismo. Ante la detección de un cambio, la aplicación se reiniciará automáticamente impactando el cambio detectado.

Pero qué pasa en producción?

Al menos que se este utilizando un hosting dedicado para Node.js como heroku o nodejitsu o cualquier otro proveedor, existen grandes chances que termines con tu aplicación en una instancia EC2 u otro tipo de proveedor cloud. Como asegurarse de que nuestra aplicación se encuentra funcionando correctamente y siempre arriba?

La respuesta a esta pregunta es otra gran herramienta denominada PM2

GitHub - Unitech/pm2: Node.js Production Process Manager with a built-in Load Balancer.
Node.js Production Process Manager with a built-in Load Balancer. - GitHub - Unitech/pm2: Node.js Production Process Manager with a built-in Load Balancer.

Al igual que nodemon, va existir un monitoreo activo sobre los cambios y re-deployments automáticos. Pero a diferencia de nodemon, ante una falla fatal, la aplicación se va a reiniciar de manera inmediata.

Si bien la cantidad de features que tiene PM2 excede esta breve lista de consejos, donde realmente se destaca es en el escenario donde necesitas escalar tu aplicación en un ambiente de multiples cores. PM2 tiene incluida la capacidad de balanceo de carga que permite de manera sencilla especificar cuantas instancias de nuestra aplicación queremos ejecutar:

pm2 start mi-aplicacion.js -i max

El parámetro -i permite especificar cuántas instancias ejecutar. En el caso en particular del ejemplo, pm2 cuenta con una constante reservada denominada max que auto-escala la aplicación a la cantidad de cores disponibles en la infraestructura donde ejecuta. Recordemos que node.js solo corre en un core.

Utilización de la funcionalidad async/await

A medida que ganamos experiencia en el desarrollo de aplicaciones en node.js, eventualmente caeremos en el infierno de los callbacks. Si no se encontró nunca en esta situación solo vea un pequeño preview del infierno a través del siguiente código

function register(name, password, cb){
  checkIfNameExists(name, function(err, result){
   if(err){
    return cb(“error”);
   }
   checkIfPasswordGood(password, function(err, result){
    if(err){
     return cb(“error”);
    }
    
    createAccount(name,password, function(err,result){
     if(err){
      return cb(“error”);
     }
     createBlog(name, function(err, result){
      sendEmail(name, function(err, result){
       callback(result);
      });
     });
    });
   });
  });
 }

Cómo evitar esto?

En las versiones mas recientes Node.js incorporo dentro de su sintaxis las funcionalidad de async y await a fin de trabajar de manera mas sencillas con Promesas si la utilización de la librería Async.js común en las versiones anteriores.

En el caso de Node.js las funciones asincrónica toman una relevancia mayor dado que la naturaleza de javascript es de ejecutarse en un solo sub-proceso.

const miFuncion = async () => {
  const url = "https://jsonplaceholder.typicode.com/todos/1";
  const res = await fetch(url);
  const datos = await res.json();
  console.log(datos);
};
miFuncion();

Una función declarada con el prefijo async devuelve por defecto una promesa (vuelve a la misma función declarada asincrónica).

Una función declarada como asincrónica sabe que dentro de su código puede esperar la palabra await que permite la ejecución de una función asincrónica.

Dado que es un tema bastante mas extenso y require un posteo aparte, en el mientras tanto les dejo un link interesante para entretenerse

Async/await

Nunca hagas check-in de la carpeta node_modules

Dado que ya hemos mencionado temas como módulos y npm no es raro ver de vez en cuando algún miembro de un equipo o desarrollador que termina realizando el check-in de la carpeta node_modules dentro de un versionador de código fuente. El principal motivo para no hacer esto es simplemente que no existe razón para hacerlo. Mientras se cuente con la declaración de dependencias dentro de la aplicación basta con ejecutar el comando npm install para descargar todos los módulos necesarios para la aplicación.

Uno puede pensar que esto no es tan grave pero qué pasa si la persona que realiza el check-in se encuentra trabajando en un sistema operativo totalmente distinto a la persona que hace el check-out del código? Los módulos utilizados por tu aplicación son compilados en el momento que son instalados

Por ejemplo, la librería bcrypt se compilan en el sistema donde es instalada, a raíz de que contiene ciertas librerías escritas en C, el modulo compilado puede no ejecutarse en otro entorno.

La mejor manera de evitar hacer check-in de los módulos de una aplicación es mediante la adición de la excepción dentro del archivo .gitignore

.gitignore node_modules/

Para finalizar, a medida que la memoria me lo permite, voy a estar actualizando la nota para poder compartir mas experiencias vividas y lecciones aprendidas con Node.js