Header Ads Widget

Ticker

6/recent/ticker-posts

Mejores prácticas de Node Js

Una breve introducción a NodeJS, su historia, uso y popularidad en el mundo web actual.

MEJORES PRÁCTICAS

  • Estructurar el proyecto 
    • Divida el proyecto en carpetas y archivos
    • Estructurar la aplicación de acuerdo con los puntos finales de la API
    • No hagas un archivo enorme
  • Usar formateadores de código
    • Usa más bonito o embellece
  • Evite funciones anónimas
    • Crea funciones reutilizables
  • Utilice camelCase
    • Siga una convención de nomenclatura para métodos, objetos y variables.
  • Evite las devoluciones de llamada:  use async-await
    • No corras al infierno de devolución de llamada
  • Manejar errores:  use try-catch
  • Usa un registrador
  • Utilice un monitor de proceso
  • Usar variables de entorno
  • Utilice siempre LTS
  • Prevenir ataques XSS
    • Escapa de los scripts HTML, JS y CSS para caracteres especiales.
    • Evite JS eval
  • Aprende a chocar:  esquiva los ataques de DOS
  • Utilice ESLint
    • Detecte antipatrones y siga los estándares

Introducción a Nodejs

NodeJS es un entorno de tiempo de ejecución de JavaScript multiplataforma de código abierto que ejecuta código JavaScript fuera de un navegador. Esa es la definición oficial de NodeJS. Pero en palabras más simples, NodeJS le permite escribir y ejecutar código JavaScript en un servidor o dentro de una aplicación que no tiene que funcionar dentro del navegador. NodeJS se utiliza principalmente para escribir utilidades del sistema y servidores web.
En los últimos años, NodeJS se ha vuelto tremendamente popular y es uno de los entornos de ejecución más populares para servidores web. Es un entorno de ejecución multiplataforma de código abierto para desarrollar aplicaciones del lado del servidor, o más precisamente, código que se ejecuta en un servidor.
NodeJS es una plataforma basada en el tiempo de ejecución de JavaScript de Chrome para crear fácilmente aplicaciones de red rápidas y escalables. Utiliza un modelo de E / S sin bloqueo controlado por eventos que lo hace liviano y eficiente, perfecto para aplicaciones en tiempo real con uso intensivo de datos que se ejecutan en dispositivos distribuidos.
En este artículo, veremos algunas de las mejores prácticas que los desarrolladores deben seguir para mantener sus grandes proyectos NodeJS en condiciones de mantenimiento.

MEJORES PRÁCTICAS

Estructurar el proyecto

Estructurar la base del código es muy importante para proyectos que escalan e involucran a equipos grandes. Esto asegura que el código sea manejable y que los desarrolladores de todos los equipos puedan comprender el código. Para esto, es necesario establecer algunas reglas básicas que serán seguidas por todos los desarrolladores e incluso probadores. A medida que el proyecto crece, el código debe desglosarse, tanto lógica como físicamente. Esto asegura que a medida que el proyecto se amplía, se mantiene manejable. Algunas pautas sobre cómo dividir una enorme base de código en fragmentos más pequeños y manejables son las siguientes.
El mayor obstáculo de los proyectos grandes es que tienden a crecer con cada nueva función o corrección de errores. Esto requiere que el proyecto se divida en diferentes archivos y luego estructura esos archivos en directorios. Ahora, esto puede variar de un proyecto a otro, pero el concepto es que el proyecto debe organizarse de tal manera que para hacer un pequeño cambio o agregar una pequeña característica a una parte del código base, el desarrollador solo necesita navegar a una rama del código. árbol de directorio.
Mala estructuraBuena estructura
  • src
  • user_login.js
  • cancel_order.hs
  • update_order.js
  • create_order.js
  • send_order_email.js
  • create_account.js
  • verify_account.js
  • user_login.js
  • src
  • pedidos
  • cancel_order.hs
  • update_order.js
  • create_order.js
  • correos electrónicos
  • send_order_email.js
  • cuentas
  • create_account.js
  • verify_account.js
  • auth
  • user_login.js
Con las bases de código grandes viene un gran conjunto de dependencias. Tener un gran software con muchas dependencias es difícil de razonar y esto a menudo conduce a un código espagueti que es táctil o casi imposible de administrar. La solución definitiva es dividir a la bestia en bestias más pequeñas y domesticables. Esto requiere dividir toda la pila en componentes autónomos que no comparten archivos con otros, cada uno constituye muy pocos archivos y por lo tanto se vuelve mucho más manejable. Además, los cambios en uno son completamente opacos a otro.
Esta opacidad asegura que los cambios en un módulo o componente en el proyecto no rompan los otros que de alguna manera están usando ese módulo o componente.

Usar formateadores de código

Este no es realmente específico de NodeJS, pero herramientas como Prettier y Beautify mejoran la estética visual del código base, que de otra manera puede verse muy desordenado y estresante. Estos le ayudan a encontrar y corregir rápidamente errores sintácticos comunes. Aunque se trata más de la estética visual del código, estas herramientas realmente ayudan ya que funcionan constantemente mientras codifica. Funcionan de acuerdo con el lenguaje en el que está codificando (JavaScript o TypeScript) y luego colorean ciertas palabras clave, formatean el código y muestran errores comunes como llaves faltantes o punto y coma.
La mayoría de los formateadores de código populares también admiten editores de código populares. Por ejemplo, tanto Prettier como Beautify admiten Visual Studio Code, que es mi favorito personal cuando se trata de NodeJS. Prettier tiene una extensión VSCode llamada prettier-vscode y unibeautify-vscode.
Las extensiones oficiales son totalmente configurables y auto-formatean el código cuando se guarda el archivo, lo que ahorra mucho tiempo y asegura que los desarrolladores no pierdan el foco.
No usar ninguno de estos formateadores de código no afectará la eficiencia de la codificación de ninguna manera, pero definitivamente afectará la eficiencia de los desarrolladores. Los desarrolladores se centrarán en las tediosas preocupaciones sobre el espaciado y el ancho de línea, y es posible que se pierda tiempo pensando demasiado en el estilo del código del proyecto.

Evite las funciones anónimas

De acuerdo con este principio, se recomienda tener funciones con nombre en lugar de funciones en línea anónimas. Le sugiere que siempre cree funciones con nombre, incluidos cierres y devoluciones de llamada, y que las nombre de forma lógica. Un ejemplo sería más apropiado para explicar esto. Echemos un vistazo a un ejemplo.
Función anónima en líneaFunción reutilizable nombrada
var woocommerce = apapi.createOrder (orderData). then ((order) => {
  // código para crear orden
  . .
  // código para enviar el correo electrónico del pedido
  . .
  // código para enviar respuesta al cliente
  . .
})
var woocommerce = apapi.createOrder (orderData). then ((order) => {
   postOrderTasks ();
})
Función postOrderTasks (orden) {
  // código para crear orden
  . .
  // código para enviar el correo electrónico del pedido
  . .
  // código para enviar respuesta al cliente
  . .
}
En el fragmento de código de la izquierda en el conjunto anterior, puede ver que una vez que se inicia el método createOrder, ejecuta ciertas operaciones en un orden determinado, pero todo sucede dentro de una función anónima. En el código de la derecha, en lugar de crear una función anónima, creamos una función con nombre llamada postOrderTasks () que solo realiza esas tareas en el mismo orden. La principal ventaja aquí es que esta función se puede reutilizar en un pedido nuevamente en otras partes del proyecto y esto reduce la redundancia de código.
Además, si encuentra un error en el código que crea un pedido, corrige ese error solo en un lugar, es decir, en el método postOrderTasks () y se reflejará en todos los lugares, lo que ahorra tiempo.
Otra ventaja de usar funciones con nombre es que cuando está perfilando una aplicación NodeJS, le permite comprender fácilmente lo que está mirando al verificar una instantánea de memoria en busca de fugas de memoria o código ineficiente. La depuración de problemas de producción mediante un volcado de memoria (instantánea de memoria) puede convertirse en un desafío si utiliza demasiadas funciones anónimas.

Utilice camelCase

En general, se considera una buena práctica seguir una convención de nomenclatura al nombrar todas las variables, objetos y clases, pero el caso de los nombres y los caracteres en los nombres también es muy importante, ya que las mayúsculas y minúsculas representan significados diferentes.
Se recomienda usar lowerCamelCase al nombrar constantes, variables y funciones y UpperCamelCase (también la primera letra mayúscula) al nombrar clases.
Se trata de convenciones aceptadas universalmente y los desarrolladores de todo el mundo pueden identificar y diferenciar fácilmente objetos y clases al utilizar esta convención de nomenclatura.
Artículo artículo = nuevo artículo ();
Artículo firstArticle = nuevo artículo ();

Evite las devoluciones de llamada: use async-await

NodeJS 8 y versiones posteriores deben completar el soporte de espera de Async en sus versiones LTS. A menudo, es una buena práctica tener operadores asíncronos en espera en lugar de utilizar varias devoluciones de llamada. Inspirado por los operadores asíncronos en espera de C #, NodeJS ofrece operadores asíncronos en espera que parecen bloquear las operaciones asíncronas esperando los resultados antes de continuar con la siguiente declaración donde la ejecución síncrona es un requisito.
Async-await en NodeJS es completamente sin bloqueo, aunque puede aparecer en el bloqueo. Es rápido y eficiente y funciona de manera muy similar a los operadores async-await de C #.
Echemos un vistazo a un ejemplo. Siguiendo el código que usa el patrón de devolución de llamada tradicional para ejecutar de forma asíncrona sincrónica.
En el bloque de código anterior, hay 3 funciones asíncronas que se ejecutan en orden y, por lo tanto, el código parece una escalera. Con más funciones, esto se ve terrible y la legibilidad del código se vuelve muy pobre. Async-await viene al rescate del infierno de devolución de llamada. Ahora, reescribamos el código usando los operadores async-await.
Como puede ver, el código es mucho más legible. La función foo () no bloquea el bucle de eventos de NodeJS, a pesar de su apariencia sincrónica. La ejecución dentro de la función se suspende durante cada una de sus tres operaciones asincrónicas, pero el bucle de eventos de NodeJS puede ejecutar otro código mientras se ejecutan esas operaciones.
El uso del operador de espera junto a una llamada de función asíncrona asegura que la siguiente línea de código solo se ejecutará cuando la función esperada se ejecute correctamente.
Se recomienda usar bloques try-catch cuando se usan operadores async-await que discutiremos a continuación.

Evite las devoluciones de llamada: use async-await

Esto es más un requisito que una recomendación. Cuando usamos operadores asíncronos en espera, ya no tenemos acceso a las devoluciones de llamadas exitosas y fallidas en las promesas, luego () y catch (). Entonces, ¿cómo manejamos los errores? Bueno, volvemos al antiguo método try-catch para manejar errores en el código.
Envuelva el código con las palabras clave await en un bloque try y, en consecuencia, escriba el código de manejo de errores en el bloque catch. Simple verdad? Reescribamos el bloque de código anterior que usa async-await usando try-catch.
Simple, elegante y el código se mantiene legible. Tenga en cuenta que si no recomienda las llamadas esperadas en los bloques de prueba, es posible que no pueda encontrar si la función se ejecutó correctamente o falló. En tal situación, no podrá manejar errores.

Usa un registrador

Tanto si el software funciona perfectamente como si no, los registros son una información que se puede evitar. Utilice siempre una herramienta de registro que registre información sobre accesos a bases de datos, bloqueos, patrones de acceso de usuarios y otra información que pueda ser útil para los equipos. Hay muchas herramientas sofisticadas disponibles para NodeJS. Algunos de los más populares son:
  • Nodo-Loggly
  • Bunyan
  • Winston
  • Morgan
He utilizado Winston en numerosos proyectos y es uno de los mejores, pero varía de un proyecto a otro y también de un desarrollador a otro.
Con Winston, puede:
  • Utiliza múltiples medios de transporte
  • Crea transportes personalizados
  • Realizar perfiles
  • Manejar excepciones
  • Utilice uno de una gama de niveles de error predefinidos
  • Crea niveles de error personalizados
Múltiples modos de transporte le permiten iniciar sesión en archivos, red o prácticamente cualquier cosa. Hay varios modos de transporte principales incluidos en Winston, que aprovechan la red incorporada y la E / S de archivos que ofrece el núcleo de Node.js. Además, hay transportes adicionales escritos por miembros de la comunidad.
Sin un registrador, hojear los registros de la consola o manualmente a través de un archivo de texto desordenado sin herramientas de consulta o un visor de registros decente puede ser una molestia cuando el software no funciona.

Utilice un monitor de proceso

Puede haber casos en los que el servidor se bloquee o tenga errores que no pueda manejar, ya que nosotros, como desarrolladores, no hemos considerado ciertos casos extremos. En estas situaciones, debemos asegurarnos de que el proceso finalice correctamente y se reinicie inmediatamente sin tiempo de inactividad mínimo o nulo. La información sobre el bloqueo también debe escribirse en los registros para que podamos manejar el bloqueo cuando ocurra en el futuro o eliminarlo por completo.
Los monitores de procesos o las herramientas de gestión de procesos como PM2 están disponibles para NodeJS que manejan todas estas cosas por nosotros. La utilidad PM2 también integra un equilibrador de carga. Puede mantener activos los procesos del servidor de aplicaciones y volver a cargarlos / reiniciarlos sin tiempo de inactividad.
PM2 también le permite administrar fácilmente los registros de su aplicación. Puede mostrar los registros procedentes de todas sus aplicaciones en tiempo real, eliminarlos y volver a cargarlos. También hay diferentes formas de configurar cómo PM2 manejará sus registros (separados en diferentes archivos, fusionados, con marca de tiempo…) sin modificar nada en su código.
Las características principales de PM2 son:
  • Gestión de procesos, incluido el reinicio automático de la aplicación en caso de fallo o reinicio del sistema
  • Monitoreo de aplicaciones
  • Configuración declarativa mediante archivo JSON
  • Gestión de registros
  • Modo de clúster integrado
  • Generación de scripts de inicio para sistemas * nix
  • Actualizaciones perfectas
  • Sistema de módulo integrado
También puede consultar para siempre o supervisor que ofrecen características similares para el monitoreo de procesos.

Usar variables de entorno

Las variables de entorno son una parte fundamental del desarrollo con NodeJS, lo que permite que su aplicación se comporte de manera diferente según el entorno en el que desea que se ejecuten. Esto es lo que implica el nombre, variables almacenadas en el entorno en el que se está ejecutando el código. Estas variables se pueden utilizar para almacenar información confidencial como claves API o cadenas secretas y también se pueden utilizar para almacenar otra información para indicar si la aplicación está en modo de prueba, desarrollo o producción. Con base en los valores de estas variables, se pueden ejecutar diferentes bloques de código para realizar diferentes operaciones o realizar operaciones de manera diferente.
Las variables de entorno se pueden utilizar para almacenar claves específicas de la aplicación, versión de software e información de compilación, rutas de archivos y rutas de carpetas, puertos e información de host, etc. Cuando la aplicación se implementa en otro servidor o en la nube, las variables de entorno garantizan que la aplicación todavía funciona, pero ahora, dado que el entorno es diferente, funcionará exactamente como se supone que debe funcionar. Se salva de la molestia de cambiar de variable antes de implementar la aplicación.
Existe un paquete específico llamado dotenv que es muy popular y se puede usar para leer archivos .env que puede usar para usar variables de entorno. Las variables de entorno garantizan que su código esté siempre al tanto del entorno en el que se ejecuta y pueda funcionar de la forma prevista.
Tenga en cuenta que estos archivos deben ignorarse cuando envíe el código al control de versiones como Github.

Utilice siempre LTS

Siempre se recomienda utilizar la versión LTS de la última versión disponible de NodeJS. LTS significa soporte a largo plazo, lo que significa que no importa lo que suceda, obtendrá soporte del equipo de NodeJS para esta versión en el futuro. Está preparado para el futuro y, por lo tanto, es adecuado para su uso en producción.
La otra variante, que se llama versión estable, recibe actualizaciones frecuentes, correcciones de errores y mejoras de rendimiento que pueden romperse en ocasiones. Si desea la versión más estable, use el último LTS disponible.
Según Rod Vagg del equipo NodeJS LTS, el objetivo de establecer un plan LTS para Node es construir sobre un ciclo de lanzamiento estable existente mediante la entrega de nuevas versiones en un calendario predecible que tenga un ciclo de vida de soporte extendido claramente definido. Si bien esto puede parecer contrario a la tradición de código abierto de "lanzamiento temprano, lanzamiento frecuente", es un requisito esencial para el desarrollo de aplicaciones empresariales y los equipos de operaciones.

Prevenir ataques XSS

Los ataques de Cross-Site Scripting (XSS) son un tipo de inyección, en el que se inyectan scripts maliciosos en sitios web que de otro modo serían benignos y confiables. Los ataques XSS ocurren cuando un atacante usa una aplicación web para enviar código malicioso, generalmente en forma de un script del lado del navegador, a un usuario final diferente.
En NodeJS, los ataques XSS se pueden prevenir mediante el uso de módulos dedicados. Hay muchos módulos disponibles para este mismo propósito. La aplicación debe utilizar encabezados seguros para evitar atacantes. Estos se pueden configurar fácilmente usando módulos como un casco. Hay otros paquetes como sanitizer y dompurify que garantizan que el contenido se envíe al cliente como contenido puro y no se pueda evaluar. Básicamente, esto se mitiga mediante el uso de bibliotecas dedicadas que marcan explícitamente los datos como contenido puro que nunca debería ejecutarse.
Otra causa común son los métodos eval (), setTimeout (), setInterval () de JavaScript. Estos métodos y la nueva función () son funciones globales, a menudo utilizadas en NodeJS, que aceptan un parámetro de cadena que representa una expresión de JavaScript, que se puede evaluar para realizar una operación en el cliente. El problema de seguridad del uso de estas funciones es la posibilidad de que la entrada de un usuario que no sea de confianza pueda llegar a la ejecución del código y comprometer el servidor, ya que evaluar el código del usuario esencialmente permite que un atacante realice cualquier acción que pueda. Por lo tanto, se sugiere refactorizar el código para no depender del uso de estas funciones donde la entrada del usuario podría pasarse a la función y ejecutarse. Otra alternativa es desinfectar la entrada del usuario antes de pasarla a uno de estos métodos.

Aprende a chocar: esquiva los ataques de DOS

El proceso de nodo se bloqueará cuando no se manejen los errores. Muchas de las mejores prácticas incluso recomiendan salir a pesar de que se detectó un error y se manejó. Esto se debe a que si no se bloquea, esto abre un punto de ataque muy bueno para los atacantes que reconocen qué entrada hace que el proceso se bloquee y envían repetidamente la misma solicitud.
Un ataque de denegación de servicio (ataque DoS) es un ciberataque en el que el perpetrador busca hacer que una máquina o un recurso de red no estén disponibles para sus usuarios previstos interrumpiendo temporal o indefinidamente los servicios de un host conectado a Internet.
No hay una solución única para esto porque hay un humano sentado en el extremo atacante, pero hay algunas cosas que pueden ayudar.
  • Alerta cada vez que un proceso falla debido a un error no controlado
  • Validar y desinfectar la entrada
  • Evite bloquear el proceso debido a una entrada de usuario no válida
  • Envuelva todas las rutas con una captura y considere no bloquearse cuando se originó un error dentro de una solicitud
Chocar no se ve del todo mal ahora, ¿verdad?

Usando ESLint

ESLint es una herramienta estándar para verificar posibles errores de código y solucionar problemas de estilo de código. No solo se usa para identificar problemas menores de espaciado, sino también para detectar antipatrones de código graves, como los desarrolladores que arrojan errores sin clasificación o no escriben una declaración de retorno en el método que se supone que debe devolver algo. ESLint puede corregir estilos de código automáticamente, pero a menudo se usa con otras herramientas como más bonito y embellecido.
Linting obliga a los desarrolladores a seguir prácticas estándar y, por lo tanto, hace que el desarrollo sea más fácil y coherente para todos los que trabajan en el proyecto. En mi experiencia personal, el linting me ha convertido en un mejor desarrollador en general.

Publicar un comentario

0 Comentarios