En el panorama actual de desarrollo de software rápido, es esencial contar con herramientas que nos permitan construir, probar y desplegar nuestras aplicaciones de manera rápida y eficiente. Poder enviar características rápidamente implica tener una base de código saludable y mantenible, lo cual puede ser complicado y desafiante, especialmente a largo plazo.
En esta charla, exploraremos estrategias para construir backends de Node mantenibles aprovechando las herramientas que proporciona Nx. Esto incluye cómo modularizar una base de código, utilizar generadores de código para mantener la consistencia, establecer límites de código y cómo mantener la integración continua rápida a medida que crece la base de código.
This talk has been presented at Node Congress 2023, check out the latest edition of this JavaScript Conference.
FAQ
La arquitectura de código se refiere a la estructura y diseño de cómo se organizan los elementos de software en un proyecto. Es importante porque una buena arquitectura permite construir aplicaciones más mantenibles, escalables y eficientes, facilitando la adición de nuevas características y la integración de nuevos miembros al equipo sin conflictos.
Modularizar por límites de dominio ofrece varios beneficios como la mantenibilidad, ya que las características se vuelven más cohesivas y encapsuladas. También mejora la flexibilidad, permitiendo eliminar o modificar módulos específicos con mayor facilidad, y facilita la reutilización de patrones comunes en el código, además de mejorar la testabilidad de los componentes.
NX es una herramienta de código abierto que mejora la productividad del desarrollador ofreciendo un conjunto de herramientas y técnicas que se pueden adoptar de forma incremental. Es conocida por su uso en Monorepos, pero también es útil para proyectos individuales, facilitando la generación de código, la configuración de compilación y ofreciendo migraciones de código.
NX permite definir reglas y límites dentro de proyectos de software, lo que ayuda a evitar importaciones no deseadas y conflictos entre módulos. Esto es especialmente útil en grandes equipos de desarrollo, donde múltiples desarrolladores trabajan sobre una misma base de código, ya que asegura que las adiciones y cambios se realicen de manera coherente y controlada.
Un Monorepo es un enfoque de gestión de proyectos de software donde múltiples proyectos coexisten en un único repositorio. NX soporta este enfoque ofreciendo funcionalidades como la ejecución de tareas, almacenamiento en caché y análisis del espacio de trabajo, lo que facilita la escalabilidad y la gestión eficiente de múltiples aplicaciones y bibliotecas dentro del mismo repositorio.
NX permite definir y gestionar dependencias y límites mediante etiquetas y reglas configurables que especifican qué tipos de proyectos pueden depender unos de otros y dentro de qué dominios. Esto facilita la automatización del cumplimiento de estas reglas mediante herramientas de análisis de código estático, como Linting, integradas en NX.
La charla de hoy se centró en la arquitectura de código, la modularización y la escalabilidad en el desarrollo de software. El orador discutió los beneficios de separar el código por dominio y utilizar herramientas como NX para mejorar la productividad y aplicar una arquitectura modular. También destacaron la importancia de automatizar la creación y configuración de bibliotecas. Además, la charla cubrió estrategias de escalado y despliegue de código, incluyendo el almacenamiento en caché y las migraciones automáticas de código. El orador enfatizó la flexibilidad y escalabilidad de Fastify y las ventajas de utilizar un monorepo para el desarrollo de front-end y back-end.
Hoy discutiremos la arquitectura de código y la construcción de aplicaciones de nodo mantenibles desde una perspectiva de herramientas. A menudo vemos un problema con características dispersas en diferentes carpetas, lo cual dificulta la escalabilidad y causa conflictos de fusión. Un enfoque mejor es la separación por dominio, que permite características atómicas y localizadas. También exploraremos módulos de dominio, automatización y escalado de código a medida que el producto crece.
¡Así que vamos directo al grano! En realidad, es un título bastante largo, pero lo que quiero analizar un poco hoy es la arquitectura de código y la construcción de aplicaciones de nodo mantenibles, pero desde una perspectiva de herramientas.
La razón principal es que, independientemente de los proyectos de front-end o back-end, que he visto como parte de mi consultoría, como parte de trabajar con algunos de los clientes, a menudo veo una estructura como esta, que está perfectamente bien cuando se inicia un nuevo proyecto, pero el principal problema aquí que se ve es que si estoy hablando de agregar características a los productos, las tengo dispersas en esas diferentes carpetas basadas en la estructura que tengo aquí.
Y la cosa es que esto es una separación por tipo. Entonces tenemos todas las API que son REST o lo que estemos usando, tal vez TRPC, están en esa capa de API mientras que los servicios están en la capa de servicios y el acceso a datos en la capa de acceso a datos. Y el proyecto realmente no escala. A medida que agregas más características, no tendrás solo un archivo, como en este caso muy, muy simple aquí, un ejemplo, sino también si agregas nuevos miembros al equipo, pueden trabajar constantemente en estas carpetas, y es muy fácil que tengan problemas como conflictos de fusión, cosas así. Así que hay una alternativa para eso, que es la separación por dominio. Estoy bastante seguro de que has visto esto. Mucha gente realmente lo hace. Creo que ese es un enfoque mejor allí, simplemente porque ahora puedes ordenar las diferentes características en sus propias áreas para que sean más atómicas, más localizadas en una sola área de todo tu producto. Y nuevamente, obtienes los beneficios de eso. Y estas son las cosas de las que quiero hablar un poco hoy. Así que hablando un poco sobre módulos de dominio, cómo podemos estructurarlo, cómo podemos agregar automatización para ayudarnos con eso y asegurarnos de mantenernos dentro de esos módulos de dominio. Y luego también un poco sobre el escalado de código en el sentido de qué sucede si agrego más de estos y sigo agregando, tal vez agregar un Monorepo, cosas así. Entonces, ¿cómo puedo asegurarme de que mi código escala a medida que mi producto crece?
2. Introducción a NX y Arquitectura Modular
Short description:
Actualmente soy el director senior de experiencia de desarrollo para NX, experto en desarrollo de Google e instructor de IA. NX es de código abierto y ayuda a mejorar la productividad del desarrollador. Se puede utilizar tanto en Monorepo como en configuraciones de proyectos individuales. La modularización por límites de dominio mejora la mantenibilidad, flexibilidad, reutilización y testabilidad. Sin embargo, aún puede ocurrir la importación de módulos de diferentes dominios por accidente. NX aborda este problema proporcionando límites de seguridad y una arquitectura modular. La capa base de NX incluye el espacio de trabajo, mientras que los complementos ofrecen herramientas de automatización específicas de la tecnología. También se introdujo un producto independiente para reutilizar la estructura de NX.
¿más grande? Como se mencionó, mi nombre es Juris Strumflauner. Actualmente soy el director senior de experiencia de desarrollo para NX, experto en desarrollo de Google e instructor de IA. NX es de código abierto, y es una herramienta que ayuda a mejorar la productividad del desarrollador. Hay un conjunto de herramientas y técnicas que se pueden adoptar de forma incremental, como en el nivel inferior, y luego agregar más cosas encima de eso. Somos conocidos por los Monorepos, pero hoy en realidad estoy hablando más sobre el lado del producto independiente. Por lo tanto, no solo se puede utilizar NX en un Monorepo, sino que también es útil para proyectos individuales. ¿Por qué modularizar por límites de dominio? Hoy en día, casi necesitas preguntarle a chatGPD para asegurarte de que estás en el camino correcto, pero en realidad encontré algunas buenas respuestas allí. Y especialmente, obviamente, la parte de mantenibilidad, ¿verdad? Porque como mencionamos antes, tienes esas características pequeñas, más cohesivas, esos módulos están encapsulados de manera ordenada. La flexibilidad, porque puedes eliminar un módulo potencialmente, porque está fuera de lo consistente, no siempre es tan fácil, y la reutilización. A medida que divides, puedes ver patrones de cosas que se reutilizan y que son similares en diferentes dominios. Por lo tanto, puedes extraer aún más y realmente reutilizarlos en tu código. La testabilidad también es un buen efecto secundario. Y hay más de estos tipos de cosas, porque ahora que tienes módulos, puedes probar ese elemento individual de manera aislada también.
Entonces, ¿qué me impide hacer algo como esto, verdad? Porque ahora tengo mi estructura agradable estructurada por módulos, un enfoque de desarrollo orientado al dominio. Pero nada realmente me impide importar, digamos, aquí mi servicio de pedidos importa algo de la API de la lista de productos porque alguien tiene una función en su archivo de nodo y su API de nodo, y lo estoy importando. Incluso puede que no sea intencional, solo mi autocompletado de ideas y trae esa función de utilidad. ¿Podemos hacerlo mejor? ¿Podemos tener algo en su lugar para restringir eso un poco más? Y aquí es donde comenzamos a pensar en NX bastante. Porque, como se mencionó en la introducción, en realidad hicimos consultoría para empresas bastante grandes, que suelen tener una gran base de código. Se encuentran con este tipo de problemas continuamente. Porque tienen de 60 a 300 desarrolladores en esa misma base de código y siguen agregando características todo el día, ¿verdad? Por lo tanto, desea tener algunas limitaciones en su lugar. Ahora, como se mencionó, NX es conocido por el tipo de monorepo. Pero si observas la arquitectura de NX, en realidad es modular en sí mismo. Entonces, en la capa base, puedes ver en la parte superior, está tu espacio de trabajo. Eso puede usar directamente la capa base de NX, lo que significa que obtienes la ejecución de tareas, obtienes un almacenamiento en caché, que es útil para monorepos. Pero luego, opcionalmente, también puedes tener estos complementos. Y los complementos son, puedes imaginarlos como herramientas específicas de tecnología que facilitan tu vida. Pueden generar código, pueden abstraer parte de la configuración de compilación de nivel inferior, proporcionar migraciones de código, todas esas cosas. Y estos complementos específicamente son muy interesantes también en una configuración de producto individual. Esta generación de código no tiene que ver realmente con monorepos. Es solo una herramienta ergonómica que puedes usar para facilitarte la vida. Por lo tanto, se introdujo un producto independiente hace unos meses, casi medio año atrás, donde simplemente reutilizas cómo
3. Producto Independiente y Modularización
Short description:
Se introdujo un producto independiente para reutilizar la estructura de NX. Genera una aplicación Node única con Fastify, Express o Coa. La extracción de la lógica en bibliotecas locales separadas proporciona encapsulación y modularidad. La aplicación importa y registra las bibliotecas, lo que la hace más liviana. Nx proporciona mapeo de rutas para importaciones más limpias. Las partes extraídas se integran en la aplicación, que sirve como contenedor de empaquetado para el despliegue. Es posible una mayor modularización de los módulos locales.
Hace un par de meses, casi medio año atrás, se introdujo un producto independiente para reutilizar la estructura de NX. Por lo general, no nos gustan las carpetas de aplicaciones y bibliotecas, pero para un producto independiente, tienes una carpeta de origen en la raíz. Y hay un generador para eso, donde puedes agregar, por ejemplo, para Node, un conjunto predefinido de Node independiente y no generaría la configuración normal de Node para monorepos, sino que generaría solo una aplicación Node única con Fastify, Express o Coa. Tenemos un par de plantillas que simplemente te facilitan el inicio. Y la estructura se ve así. Entonces, puedes ver aquí que hay una carpeta de origen, hay una aplicación aquí, a la que ya le he agregado algunas características que son, nuevamente, por dominio. Entonces tenemos los pedidos, tenemos los detalles del producto, la lista de productos, cosas así. Y un enfoque obvio que ya tienes en un monorepo, tienes una aplicación y varias bibliotecas, pero puedes tomar ese mismo enfoque para modularizar también tu aplicación independiente, ¿verdad? Por lo tanto, podemos seguir adelante y, en lugar de tener solo ese código monolítico donde tienes solo carpetas, puedes extraerlos y crear bibliotecas locales separadas. Ahora las llamo bibliotecas locales porque no las vamos a publicar, ¿verdad? Pero tienen su propia configuración, su propio proceso de compilación, sus propias pruebas. Y así puedes extraer esa lógica en partes más modulares allí. ¿Cuál es la ventaja? Bueno, en primer lugar, estas están más encapsuladas porque cada una de estas bibliotecas, por ejemplo, viene con un archivo index.js, que es tu punto de entrada público, si quieres, tu API pública hacia el mundo exterior dentro de ese proyecto único. Aquí, por ejemplo, estoy exponiendo las rutas para esa biblioteca, por lo que esta es mi biblioteca de pedidos, por ejemplo, y luego puedo tener más facilidades internamente. Tal vez tenga una función dedicada para cada manejo de ruta y así sucesivamente, como aquí puedes agregar básicamente lo que necesites en tu proyecto. Pero ya puedes ver cómo esto está modularizado. Ahora esta es una aplicación Fastify, eso es solo porque Fastify tiene, en realidad, uso este ejemplo porque Fastify tiene algunos mecanismos incorporados que funcionan muy bien con la modularización. Y Matteo Collina en realidad tiene una charla más profunda sobre Fastify hoy, creo que es una de las últimas charlas, así que definitivamente deberías ver eso, donde él profundizará más en Fastify y por qué ya tiene esa modularidad incorporada. Pero puedes usarlo con Express, como se mencionó, con COA y todos los demás frameworks de Node también. Y luego, en el nivel superior, en este caso Fastify, todo lo que haces es simplemente importar esa biblioteca, ¿verdad? Entonces puedes ver que esto tiene un alcance de NPM y luego registrarlo con Fastify. Ahora probablemente haya una mejor manera de hacerlo, no soy un experto en Fastify, así que tal vez Matteo revele alguna mejor manera de cargarlo dinámicamente, por ejemplo, Fastify tiene propiedades de carga automática. Pero es la forma en que lo conectas. Entonces, la aplicación en realidad se vuelve muy liviana. Ahora puedes preguntarte por qué o cómo puedo importar eso en mi aplicación de nodo, slash, módulos y así sucesivamente. La razón es porque en Nx, por ejemplo, cuando creas una biblioteca de este tipo, ya proporcionamos tipos de mapeo de ruta, por lo que la importación es mucho más agradable, no tienes importaciones relativas extrañas a alguna ubicación dentro de tu proyecto. Esto es solo, nuevamente, por la ergonomía del desarrollador. Entonces, lo que obtenemos es una estructura casi como esta, donde la aplicación de nodo es nuestra aplicación, y las partes que extraemos se vuelven casi independientes. No podemos ejecutarlos solos, pero están integrados en la aplicación, que los agrupa. Por lo tanto, tu aplicación realmente se convierte en el contenedor de empaquetado, la parte de despliegue, porque al final, cuando implementas la aplicación, eso es lo que construiste, se incluirá y compilará los módulos, y luego los enviarás a algún lugar en tu servidor. Pero podemos ir más allá y modularizar esas bibliotecas locales
4. Estructura de Código y Cumplimiento
Short description:
Este es un ejemplo de cómo puedes estructurar tu código dividiéndolo en API, acceso a datos y servicios. Sin embargo, actualmente no hay un mecanismo para hacer cumplir las reglas de importación desde otras bibliotecas. Es posible que deseemos tener un flujo más simplificado desde la API hacia los servicios o el acceso a datos.
modules aún más. Y esto es solo un ejemplo, por lo que puedes estructurarlos como desees. Como uso la misma estructura de capa de servicio de API data aquí, solo por simplicidad. Pero podría ser una forma potencial de cómo dividir y estructurar las cosas. Y a nivel de código, se ve así, donde tienes la API, tienes el acceso a data y tienes los servicios. Entonces, son solo forms respectivos donde cada uno de estos es como su propia biblioteca, y simplemente se encuentra debajo de la carpeta de pedidos. Eso se convierte en mi límite de dominio. Pero aún así, si te das cuenta, todavía no tenemos un mecanismo aquí para hacer cumplir estas reglas, ¿verdad? Ahora tenemos una API más clara. Tenemos un archivo TS indexado público de cada una de estas bibliotecas. Por lo tanto, es más sólido que simplemente tener carpetas, pero aún no hay un mecanismo que no permita importar directamente desde algunas de estas otras bibliotecas, ¿verdad? Puedo acceder directamente. Y por ejemplo, tal vez dentro de la biblioteca de pedidos data acceso, simplemente acceder a alguna función de la API, lo cual potencialmente no queremos, ¿verdad? Es posible que deseemos tener un flujo más simplificado desde la API a través de los servicios.
5. Gestión de Dependencias con Reglas y Automatización de Nx
Short description:
Para manejar diferentes áreas de dominio que acceden a características de otra área de dominio, Nx define reglas en dos dimensiones: tipo y alcance. Los tipos incluyen API, servicio y acceso a datos, mientras que los alcances abarcan pedidos, gestión de perfiles y pago de productos. Etiquetar tipos y definir reglas permite tener dependencias controladas entre dominios. La automatización a través del linting asegura que estas reglas se apliquen automáticamente, evitando comprobaciones manuales durante las solicitudes de extracción. El linting también ofrece extensiones para varios editores, como VS Code.
o desde el acceso a datos de la API. Y de manera diferente, ¿qué sucede si un área de dominio diferente accede a características de otra área de dominio? Algo así es perfectamente legítimo, ¿verdad? El proceso simplemente, debe ser consciente de que permito conscientemente tal importación. Y para manejar esas situaciones, lo que hicimos en Nx es definir reglas, ¿verdad? Y generalmente vienen en dos dimensiones. En primer lugar, está la dimensión del tipo. La dimensión del tipo es básicamente qué tipo de proyecto soy y qué tipo de proyecto puede depender de qué otro tipo de proyecto. Y la segunda dimensión se refiere más al alcance o área de dominio. Entonces, ¿qué alcance puede depender de qué otro alcance? Puede haber algunos que puedan compartir cosas y otros que no puedan compartir cosas. Y así, el tipo en nuestro caso, en este ejemplo simple, pero realmente depende de la estructura de su proyecto, en realidad. Aquí podrían ser API, servicio y acceso adata. Esos son diferentes tipos. Y el alcance son simplemente pedidos, gestión de perfiles, pago de productos. Y generalmente también tienes algunos tipos compartidos, que son entidades, tal vez solo funciones de utilidad. Cosas así.
Ahora, para agregar esos tipos, debes etiquetarlos. Y es por eso que agregamos al proyecto una configuración donde puedes especificar una cadena. Esto puede ser una cadena arbitraria, ¿verdad? Por lo general, los especifico con dos puntos en términos de tipo, y luego el nombre o el valor como alcance y valor real. Pero esto es completamente libre. Puedes inventar tu propia notación si quieres. Y una vez que hayas etiquetado esos, puedes definir estas reglas. Entonces puedes decir, bueno, hay un tipo de API, que puede depender de servicios, de utilidades, de entidades. Incluso puede depender del acceso adata, dependiendo de cómo quieras hacerlo. Y luego está el tipo de alcance, donde puedes decir que este tipo de dominio puede acceder a este otro tipo de dominio. Y podrías ir potencialmente a profundidades arbitrarias, dependiendo de qué tan complejo quieras ir y qué tan estricto quieras ser en esto. Y luego viene laautomation.
Esta es una parte crucial aquí, porque obviamente no quieres verificar eso manualmente en cada PR, sino que quieres tenerlo automatizado. Y el Linting es en realidad un buen candidato para eso, porque es un análisis de código estático. Entonces, miras las reglas que tienes, miras el texto que tienes asociado, sabes qué archivo importa qué otro archivo, en qué productos residen, porque tienes esa información. Así que todo se trata de conectar esas cosas y hacer cumplirlas a través de una regla de lint personalizada, que realmente hemos escrito e integrado en X para asegurarnos de que se ejecuten. Y la parte genial, obviamente, es que el Linting tiene muchas extensiones para varios editores.
6. Automatización de Creación y Configuración de Bibliotecas
Short description:
Puedes utilizar complementos y generadores para automatizar el proceso de creación de bibliotecas y configuración. Esto facilita todo el proceso y evita el copiado y pegado manual. Los generadores te permiten configurar una biblioteca completa con pruebas y configuración, asegurándote de que haga referencia a las definiciones necesarias. También puedes crear tus propios complementos y usarlos localmente para automatizar tareas. Estos complementos se pueden utilizar para modificar proyectos existentes o crear nuevos archivos, como archivos Docker y configuraciones JSON del proyecto.
Este es un ejemplo para VS Code, por ejemplo. Así que tienes esa información lista cuando escribes el código, ya ves de inmediato que esto puede ser importado desde otra parte, porque las reglas no coinciden, no lo permiten. Y obviamente, es algo que puedes ejecutar en la línea de comandos de tu pipeline de CI, ¿verdad? Así que te aseguras incluso ahí de que las cosas que se incluyen en la rama principal sean consistentes. Genial, así que ahora podrías pensar que esto es bueno, ¿verdad? Pero requiere mucho esfuerzo. Necesitas crear esas bibliotecas, asociar etiquetas, idear esas reglas. Bueno, las reglas, probablemente solo necesitas pensarlas una vez y luego tal vez sea cuestión de tiempo, pero aún así es un poco ceremonioso en cierto sentido.
Y aquí es donde entra en juego otra característica de esos complementos, que son especialmente esos generadores. Están diseñados específicamente para hacer que ese proceso sea un poco más ligero y más fácil de abordar, ya que te permiten crear la estructura básica de algunas cosas. Por ejemplo, todas estas bibliotecas que hemos visto son simplemente el resultado de ejecutar este comando para generarlas automáticamente. Por lo general, tienes aquí un concepto en el que está el complemento, luego el generador que invocas y luego los parámetros que le das a ese generador. Y esto obviamente depende del generador que estés ejecutando, pero al ejecutar este comando te permite configurar toda una parte de esta biblioteca con su configuración de testing y tipos de configuración, asegurándote de que haga referencia a las definiciones de nivel de espacio de trabajo como mapeos de rutas, todas esas cosas funcionan de inmediato. Esto es obviamente importante porque facilita todo el proceso, ya que de lo contrario, si tuvieras que copiar y pegar y hacerlo manualmente, sería un poco engorroso. Aquí tienes una simulación de cómo sería. Así que también puedes agregar una simulación y ver qué generaría sin tocar el sistema de archivos. Pero te haces una idea, por ejemplo, de ejecutar aquí el generador de bibliotecas en el paquete de nodo. Crearía esa biblioteca de verificación de módulos de API con todo el archivo readme y todas las cosas que tengo ahí. Y curiosamente, también puedes crear los tuyos propios. Desde el equipo principal de NX, enviamos algunos complementos que nosotros mismos usamos, por lo que tiene sentido porque los usamos para nuestros clientes. Los mantenemos. Tenemos más de 80 complementos de la comunidad y esos son solo los publicados. Muchas personas en realidad solo usan esos complementos localmente en su espacio de trabajo para automatizar tareas. No necesariamente quieres publicarlos. Simplemente crea un complemento localmente, listo en ese mismo repositorio para automatizar la generación de bibliotecas. Y lo que suele suceder es que simplemente toma un proyecto de biblioteca de nodo existente, lo ejecuta primero. Básicamente lo envuelve y luego agrega cosas encima, elimina o ajusta según las pautas de la empresa, las pautas del proyecto, etc. Y no solo son bibliotecas. Son independientes de la tecnología en el sentido de que literalmente puedes escribir archivos. Hay plantillas que tienen marcadores de posición. Así que aquí, por ejemplo, algo que agregamos a nuestro propio complemento de nodo es la configuración de Docker, ¿verdad? Así que
7. Escalado y Despliegue de Código
Short description:
Ahora tenemos un objetivo que podemos ejecutar. Hemos hablado de la automatización de módulos de dominio, pero aún falta el escalado del código. Al expandirlo en piezas más pequeñas, logramos una configuración más modular, lo que facilita la asignación y reemplazo de equipos. Podemos probar piezas individuales y desplegar diferentes objetivos con frecuencias variables. NX proporciona características como el almacenamiento en caché, la distribución y las migraciones automáticas de código, asegurando la escalabilidad junto con una estructura de monorepo.
crea un archivo Docker para ti. Ya crea una configuración en el archivo JSON del proyecto. Ahora tenemos un objetivo que podemos ejecutar. Y aquí específicamente, puedes ver en la parte inferior donde dice que cada vez que ejecutas una construcción de Docker, eso depende de la construcción real del proyecto. Así que primero ejecutaremos la construcción, luego lo envolveremos en Docker, tendremos un contenedor de Docker que luego puedes ejecutar y desplegar.
Así que hemos hablado un poco sobre la automatización de módulos de dominio. Pero una pieza que aún falta un poco es el escalado del código. ¿Cómo se ve eso? Bueno, esta es la situación actual que tenemos. Si realmente expandimos esto en piezas más pequeñas, ya obtenemos una configuración más modular. Asignar equipos es más fácil. Tenemos reglas claras, como las reglas de límites que aseguran que no tengamos referencias extrañas entre esos proyectos. Es potencialmente más fácil de reemplazar. Es como la filosofía de los microservicios, donde puedes agregar un nuevo servicio al lado y eliminar el antiguo, porque si están lo suficientemente desacoplados, eso podría ser fácil debido a que tienen una API clara. Y obviamente podemos probar piezas individuales. No es necesario probar todos los proyectos que tenemos en nuestro espacio de trabajo, sino que podemos probar solo la API del producto si solo hemos cambiado eso. Cosas como esa pueden ayudar, pero también pueden ayudar en el sentido de que, en algún momento, necesites no solo en términos de escalado del código, sino también una frecuencia de despliegue diferente. Tal vez tengas un proyecto en esa área local o un producto que necesite escalar más o necesite desplegarse con más frecuencia. Ese podría ser un punto en el que también cambies a un monorepo. Donde digas, bueno, no solo tenemos una aplicación de nodo, sino que agregamos otra aplicación que simplemente importa algunos de estos módulos que tienen sentido. Y ahora tenemos dos objetivos de despliegue que podemos desplegar tal vez con diferentes frecuencias, tal vez servicios unitarios que se escalan de manera diferente. Porque tal vez para una parte no necesitamos todo el escalado que se necesita. Pero puedes ver que con esa modernización, esa importación es mucho más fácil. Porque todo lo que hacemos es tener una segunda aplicación. Simplemente importamos nuevamente esos espacios de nombres y eso es casi todo, ¿verdad? Y si hablamos de velocidad, obviamente NX proviene de un escenario de monorepo. Así que se escala perfectamente junto con eso, ¿verdad? Como esas características que he resaltado aquí en ese diagrama arquitectónico general, tiene todas estas características incorporadas, como el almacenamiento en caché, la distribución, el análisis del espacio de trabajo, las migraciones automáticas de código. Todas estas cosas que potencialmente necesitarías si luego escalas realmente, como tener múltiples aplicaciones y cientos de proyectos. Entonces, no te quedas solo en ese punto. Y los llamo capas de velocidad porque puedes agregarlas encima, ¿verdad? Puedes comenzar solo con la paralelización inteligente que NX proporciona, donde ejecutas todos los proyectos en paralelo según sus dependencias y el almacenamiento en caché y otras cosas de distribución encima de eso.
Entonces, ¿cómo se ve esto en la vida real? Creo que tengo un par de minutos, así que realmente solo quiero darte una descripción general de alto nivel de cómo se ve este proyecto.
8. Fastify y Estructura NX
Short description:
Esto es Fastify. NX conoce la estructura basada en las importaciones y la visualiza. Optimiza ejecutando pruebas específicas y respeta el orden de construcción. El almacenamiento en caché acelera las ejecuciones posteriores. La automatización es posible con complementos locales y generadores. Se puede generar un nuevo dominio con una configuración elegida. Gracias por su atención y no dude en hacer preguntas.
Entonces, esto es exactamente una aplicación así. Esto es Fastify. Si entro aquí, puedes ver aquí las importaciones de Fastify. Aquí tengo mis rutas que he importado, y estos son los módulos que he extraído aquí, ¿verdad? Por ejemplo, si miro las órdenes, aquí tengo una API, tiene un index.ts, tiene las rutas aquí, y a partir de ahí, lo estructuro como quiero, ¿verdad? Y nuevamente, esto es solo un ejemplo. Puedo ejecutar mbx.NXGraph para visualizar eso, donde muestra cómo se ve la estructura en términos de los módulos. Entonces, lo que NX hace detrás de escena es que conoce la estructura basada en los tipos que importa. Y esto es básicamente solo una visualización donde puedes hacer clic en estos y ver, ¿por qué existe este enlace? ¿Por qué hay una conexión? Y puedes entenderlo y depurarlo. Pero NX también lo utiliza para acelerar las cosas, ¿verdad? Entonces, si cambias algo aquí en los servicios de pago, solo se ejecutarán las pruebas del servicio de pago API y Nodab y así sucesivamente, ¿verdad? Puedes hacer optimizaciones donde no necesitas ejecutar todo. Y eso proviene del trasfondo de Monorepo en el que se encuentra NX. Y de manera similar, si quiero ejecutar digamos todas las pruebas de estilo y testing de este espacio de trabajo, puedes ver que ahora se ejecutan todas las pruebas para todos los proyectos y modelos que tenemos allí, que también podría ejecutar individualmente, ¿verdad? Si solo trabajo en uno y desarrollo uno, puedo ejecutarlo solo para uno y se ejecuta en paralelo en todos ellos, ¿verdad? Y esto también respeta los posibles órdenes de construcción entre los paquetes, ¿verdad? Si un paquete depende de otro, se construye primero, por lo que también se paraleliza de manera inteligente, de alguna manera. Esto tomó alrededor de 30 segundos ahora, 13 segundos, y luego si los ejecuto nuevamente, sería inmediato porque entonces entra en juego el almacenamiento en caché, ¿verdad? Entonces, si ya he ejecutado algunas pruebas antes, entonces si como parte de alguna otra construcción, vuelvo a ejecutar esas mismas pruebas, no se volverán a ejecutar, ¿verdad? Por lo tanto, se beneficiaría de ese almacenamiento en caché y se omitiría desde allí. Además, puedo automatizar cosas, ¿verdad? Aquí, por ejemplo, tengo un complemento local de generación, que tiene un generador y todo lo que tiene son archivos de plantilla que tienen, por ejemplo, aquí, algunos marcadores de posición y luego puedo ejecutarlo. Ni siquiera tengo que ejecutarlo solo a través de la interfaz de usuario o a través de la CLI. Incluso hemos desarrollado una extensión donde puedo ejecutar mi complemento local aquí, proporcionarle un nombre, digamos nuevo dominio, ¿verdad? Ves directamente la salida de Dry Run a continuación y puedo ejecutarlo y luego generaría un nuevo tipo de dominio aquí con la configuración que ya quiero tener, ¿verdad? Dependiendo obviamente de la configuración que elijas. Así que esta es una especie de descripción general de alto nivel súper rápida. Estoy afuera, así que encuéntrame y podemos profundizar un poco más si tienes más preguntas. De lo contrario, me gustaría agradecerles por su atención. Muchas gracias. ¿Te gustaría tomar asiento conmigo? Tengo algunas preguntas para ti. Solo un recordatorio para todos los que están en la sala y en línea, aún pueden hacer preguntas usando Slido hasta que se acabe el tiempo.
9. Haciendo que los Dominios se Comuniquen
Short description:
Para hacer que dos dominios diferentes se comuniquen entre sí, puedes importar código mediante el mapeo de rutas. La apertura de dominios depende de la estructura del producto. Los servicios pueden comunicarse entre sí, o puedes tener APIs internas dedicadas. Tienes la libertad de definir límites dentro de tu proyecto.
Muchas gracias por la charla. Me pareció muy interesante. Una de las primeras preguntas que tuvimos fue ¿cómo haces que dos dominios diferentes se comuniquen entre sí? Supongo que la pregunta se refiere a las reglas de límites, ¿verdad? Si solo quieres compartir código, puedes importarlo mediante ese tipo de mapeo de rutas que mostré antes. En cuanto a cómo quieres abrir esos dominios, realmente depende de la estructura de tu producto. He visto que algunas personas dicen que los servicios, las capas de servicio, siempre pueden comunicarse entre sí, esa sería la forma más liviana, ¿verdad? Donde dices que la API no puede obtener directamente una capa de servicio de otro dominio, sino que prefiero que pase por mi, si quieres, capa de negocio, ¿verdad? Y así abrirlo de esa manera. O incluso puedes tener APIs internas dedicadas donde tienes, no sé, APIs de servicio internas, algo así, un proyecto dedicado donde vuelves a exportar cosas desde tu propia capa de servicio, ¿verdad? Así que puedes ser tan detallado como quieras allí. Dentro de los límites de tu propio proyecto. Puedes definirlos completamente libremente.
10. Límites de módulo en proyectos Lerner
Short description:
Lerner es una herramienta simple que delega la ejecución de tareas a NX para obtener beneficios de caché. No tiene reglas adicionales de límites de módulo, las cuales son proporcionadas por complementos en NX. Este enfoque permite una capa delgada sobre los monolitos existentes, sin una gran implicación. El paquete NX en sí no proporciona estas reglas, deben agregarse a través de complementos.
La siguiente pregunta es si se pueden utilizar límites de módulo en proyectos Lerner. Lerner no lo tiene en este momento. Entonces, Lerner es básicamente, si recuerdas, el diagrama de NX está en la base, ¿verdad? Lerner solo se encarga de la ejecución de tareas, es lo mismo, en realidad delega muchas cosas a NX en segundo plano para obtener todos los beneficios de caché, pero eso es todo, se mantiene simple a propósito. Lo que tiene además es la publicación, cambios automáticos de versión, conversión semántica, ese tipo de cosas, pero en general se mantiene lo más simple posible. Por lo tanto, no tiene esas reglas adicionales de límites de módulo y cosas así. Los límites de módulo casi exclusivamente provienen de los complementos que NX proporciona en la parte superior, ¿verdad? Pero de alguna manera, discutimos la integración de algunos de esos aspectos directamente en NX, pero por otro lado, queremos mantenerlo lo más simple posible, porque generalmente tenemos dos situaciones en las que las personas dicen: `Oye, ya tengo mi monolito, no quiero tener una gran implicación en nada, solo quiero tener una capa muy delgada encima que acelere las cosas, ¿verdad?` Y para mantener eso lo más pequeño posible, el paquete NX en sí no proporciona ninguna de esas reglas de límites adicionales y cosas así, en cambio, debes agregarlas.
11. Estructura de módulo y rutas anidadas
Short description:
En el caso de las rutas anidadas como slash order, slash ID, slash products, la estructura de un módulo depende de los requisitos específicos. Es posible tener estas rutas anidadas dentro del mismo proyecto y API, o incluso crear un submódulo para manejarlas. A menudo se prefiere el enfoque de comenzar con una estructura más simple y luego extraer según sea necesario. Fastify es un marco flexible que permite delegar fácilmente las rutas a submódulos.
complementos en la parte superior. Gracias. ¿Cómo funcionaría o se estructuraría un módulo en el caso de cosas como rutas anidadas, como slash order, slash ID, slash products? Ahí realmente depende, eso también está relacionado con la charla que Matter va a dar, supongo, no sé exactamente de qué trata su charla, pero él va a profundizar en ese enfoque de modularización, pero potencialmente podrías tener esas rutas anidadas dentro del mismo proyecto en la misma API, potencialmente incluso podrías ir un paso más allá y tener un submódulo nuevamente y luego delegar eso a ese submódulo. Por lo general, yo comienzo con lo simple y luego extraigo, pero no hay limitación en ese sentido. Casi como si la limitación estuviera en lo que Fastify puede hacer por ti, básicamente, y lo que he visto, nuevamente, no soy un experto en Fastify, pero lo que he visto hasta ahora es que es bastante flexible en cierto sentido, puedes delegar fácilmente eso a un submódulo.
12. Monorepo y Monolito Modular
Short description:
Definimos la diferencia entre un monorepo y un monolito modular. Los monorepos son adecuados para la colocación conjunta de front-end y back-end. TRPC se puede utilizar para aprovechar el mecanismo de enrutamiento. La compilación de proyectos de Node TypeScript con múltiples módulos utiliza ESBuilt en segundo plano.
como enrutamiento interno. Genial. Tenemos muchas preguntas y, lamentablemente, no suficiente tiempo para responderlas todas, así que solo un recordatorio, lo haré de nuevo en un momento, hay una sala de preguntas y respuestas cerca de la recepción, para aquellos de ustedes en el lugar y para aquellos de ustedes en línea, vayan a Spatial Chat, hagan clic en Q&A para unirse a ese espacio, porque sé que no podremos responderlas todas, pero haremos nuestro mejor esfuerzo. ¿Cómo defines la diferencia entre un monorepo y un monolito modular como el que mostraste? Exactamente, sí. Nosotros en NX, nuestro equipo, tenemos una página web llamada monorepo.tools donde recopilamos diferentes soluciones de monorepo. Hemos recibido muchas contribuciones de diferentes proveedores de herramientas de monorepo donde enumeramos lo que es un monorepo para nosotros. Por lo general, decimos que es cuando tienes múltiples aplicaciones. Si solo tienes una aplicación, técnicamente podrías considerarlo como un monorepo porque tienes una aplicación y múltiples paquetes, pero con ese proyecto independiente ese es nuestro enfoque de monolito modular. Si quieres, donde tienes un proyecto, ese es el predeterminado. De hecho, si ejecutas NXserve, está sirviendo ese proyecto, no tienes que especificar el nombre y una vez que agregas otro, otra aplicación, como tu contenedor de implementación y sistema de empaquetado, entonces comenzaría a hablar de un monorepo. Pero obviamente la línea es difusa, no hay una regla única. ¿Ves esta arquitectura también para aplicaciones de pila completa? ¿Algo así como TRPC? Sí, sí. Funciona perfectamente bien. Y eso es lo que, quiero decir, el proyecto independiente llegó recientemente, pero hemos tenido soporte para Node durante mucho tiempo porque muchos de nuestros clientes y usuarios de NX tenían un escenario donde tenían React en el front-end y luego un back-end de Node, ¿verdad? Y tenerlos ubicados en el mismo lugar, ya podías compartir tipos. Ahora, cosas como TRPC hacen que eso sea aún más fácil, ¿verdad? Porque tienes el mecanismo de enrutamiento incorporado, por lo que puedes aprovecharlo más. De hecho, tenemos un artículo en el blog. Si vas a dev.to.nx, hay un artículo en el blog sobre cómo usar TRPC en un espacio de trabajo NX, por ejemplo. Y nuevamente, es solo cómo los unirías. ¿Cómo encajarían? Creo que incluso hay un generador local que facilita la configuración de cosas como esa. Pero sí, los monorepos son muy adecuados para tener el front-end y el back-end ubicados en el mismo lugar y compartir cosas entre ellos. Sí, tipos especiales.
Siguiente pregunta. Creo que tenemos tiempo para dos más. ¿Cómo funciona la compilación para proyectos de Node TypeScript con múltiples módulos? ¿Necesitas un empaquetador o solo la compilación de TypeScript es suficiente? Sí, básicamente, aprovechamos ESBuilt en segundo plano. Si miras la configuración del proyecto, habrá un complemento base de ESBuilt que usamos para construir esto a partir de TypeScript. Y obviamente, en Node, no necesitarías el proceso de compilación real. Lo único que hacemos adicionalmente es que cuando tienes esos módulos y con los mapeos de rutas de TypeScript, una vez que los compilas a JavaScript, obviamente no tendrás los mapeos de rutas de TypeScript. Así que hemos creado una capa intermedia donde implementamos un resolutor de nombres de módulos, y eso los mapea. Así que generamos un mapa para esos módulos de manera que aún puedas implementarlos como si fuera una sola aplicación de Node. Está en una carpeta de distribución, y luego los módulos se copiarán allí, precompilados, y simplemente se vincularán a través de ese resolutor de módulos que es tu punto de entrada para una aplicación de Node.
13. Empaquetado y Despliegue
Short description:
Puedes empaquetar tu código en un solo archivo sin necesidad de módulos de Node. Esto te permite desplegar funciones o módulos simples fuera de tu monorepo. El contenedor Docker de Node empaquetado consiste en unos pocos archivos individuales que se pueden desplegar directamente en un proveedor. Existe una opción que habilita este empaquetado en un solo archivo. Gracias por sus preguntas y por favor únase a la sección de preguntas y respuestas del orador para más discusión.
Así es como resolvimos ese problema. Pero no necesitas ningún mecanismo de empaquetado en absoluto. Puedes, como agregamos la opción de empaquetarlo en un solo archivo donde ni siquiera necesitas módulos de Node. Y esa fue principalmente nuestra idea, ¿qué pasa si quieres desplegar funciones serias, cosas así, que son simples, pero aún así tal vez quieras desplegarlas fuera de tu monorepo o estos monolitos modulares, entonces tal vez quieras tener ese contenedor Docker de Node empaquetado, solo un par de archivos individuales que despliegas directamente en algún proveedor, como un proveedor de funciones de borde o algo así. Y así puedes configurarlo. No recuerdo la bandera exacta, pero hay una bandera que se puede habilitar, que está habilitada de forma predeterminada, que puede empaquetarlos en un solo archivo. Eso es posible.
Muchas gracias. Se nos acabó el tiempo para preguntas. Todavía hay algunas preguntas encantadoras que deben ser respondidas, incluyendo una de Felix. Muchas gracias por enviarla. Les animo a todos a dirigirse a la sección de preguntas y respuestas del orador junto a la recepción. Si quieren seguir charlando con Yuri, aquellos de ustedes en línea, una vez más, pueden hacer clic en el chat en el espacio espacial para unirse a ese espacio físico. Y demos un gran aplauso a Yuri por su tiempo. Muchas gracias. Gracias.
The talk discusses the importance of supply chain security in the open source ecosystem, highlighting the risks of relying on open source code without proper code review. It explores the trend of supply chain attacks and the need for a new approach to detect and block malicious dependencies. The talk also introduces Socket, a tool that assesses the security of packages and provides automation and analysis to protect against malware and supply chain attacks. It emphasizes the need to prioritize security in software development and offers insights into potential solutions such as realms and Deno's command line flags.
There is a need for a standard library of APIs for JavaScript runtimes, as there are currently multiple ways to perform fundamental tasks like base64 encoding. JavaScript runtimes have historically lacked a standard library, causing friction and difficulty for developers. The idea of a small core has both benefits and drawbacks, with some runtimes abusing it to limit innovation. There is a misalignment between Node and web browsers in terms of functionality and API standards. The proposal is to involve browser developers in conversations about API standardization and to create a common standard library for JavaScript runtimes.
ESM Loaders enhance module loading in Node.js by resolving URLs and reading files from the disk. Module loaders can override modules and change how they are found. Enhancing the loading phase involves loading directly from HTTP and loading TypeScript code without building it. The loader in the module URL handles URL resolution and uses fetch to fetch the source code. Loaders can be chained together to load from different sources, transform source code, and resolve URLs differently. The future of module loading enhancements is promising and simple to use.
This talk covers various techniques for getting diagnostics information out of Node.js, including debugging with environment variables, handling warnings and deprecations, tracing uncaught exceptions and process exit, using the v8 inspector and dev tools, and generating diagnostic reports. The speaker also mentions areas for improvement in Node.js diagnostics and provides resources for learning and contributing. Additionally, the responsibilities of the Technical Steering Committee in the TS community are discussed.
Deno aims to provide Node.js compatibility to make migration smoother and easier. While Deno can run apps and libraries offered for Node.js, not all are supported yet. There are trade-offs to consider, such as incompatible APIs and a less ideal developer experience. Deno is working on improving compatibility and the transition process. Efforts include porting Node.js modules, exploring a superset approach, and transparent package installation from npm.
Today's Talk is about logging with Pino, one of the fastest loggers for Node.js. Pino's speed and performance are achieved by avoiding expensive logging and optimizing event loop processing. It offers advanced features like async mode and distributed logging. The use of Worker Threads and Threadstream allows for efficient data processing. Pino.Transport enables log processing in a worker thread with various options for log destinations. The Talk concludes with a demonstration of logging output and an invitation to reach out for job opportunities.
¿Alguna vez has tenido dificultades para diseñar y estructurar tus aplicaciones Node.js? Construir aplicaciones que estén bien organizadas, sean probables y extensibles no siempre es fácil. A menudo puede resultar ser mucho más complicado de lo que esperas. En este evento en vivo, Matteo te mostrará cómo construye aplicaciones Node.js desde cero. Aprenderás cómo aborda el diseño de aplicaciones y las filosofías que aplica para crear aplicaciones modulares, mantenibles y efectivas.
Platformatic te permite desarrollar rápidamente APIs GraphQL y REST con un esfuerzo mínimo. La mejor parte es que también te permite aprovechar todo el potencial de Node.js y Fastify cuando lo necesites. Puedes personalizar completamente una aplicación de Platformatic escribiendo tus propias características y complementos adicionales. En el masterclass, cubriremos tanto nuestros módulos de código abierto como nuestra oferta en la nube:- Platformatic OSS (open-source software) — Herramientas y bibliotecas para construir rápidamente aplicaciones robustas con Node.js (https://oss.platformatic.dev/).- Platformatic Cloud (actualmente en beta) — Nuestra plataforma de alojamiento que incluye características como aplicaciones de vista previa, métricas integradas e integración con tu flujo de Git (https://platformatic.dev/). En este masterclass aprenderás cómo desarrollar APIs con Fastify y desplegarlas en la nube de Platformatic.
Construyendo un Servidor Web Hiper Rápido con Deno
WorkshopFree
2 authors
Deno 1.9 introdujo una nueva API de servidor web que aprovecha Hyper, una implementación rápida y correcta de HTTP para Rust. El uso de esta API en lugar de la implementación std/http aumenta el rendimiento y proporciona soporte para HTTP2. En este masterclass, aprende cómo crear un servidor web utilizando Hyper en el fondo y mejorar el rendimiento de tus aplicaciones web.
La autenticación sin contraseña puede parecer compleja, pero es fácil de agregar a cualquier aplicación utilizando la herramienta adecuada. Mejoraremos una aplicación JS de pila completa (backend de Node.JS + frontend de React) para autenticar usuarios con OAuth (inicio de sesión social) y contraseñas de un solo uso (correo electrónico), incluyendo:- Autenticación de usuario - Administrar interacciones de usuario, devolver JWT de sesión / actualización- Gestión y validación de sesiones - Almacenar la sesión para solicitudes de cliente posteriores, validar / actualizar sesiones Al final del masterclass, también tocaremos otro enfoque para la autenticación de código utilizando Flujos Descope en el frontend (flujos de arrastrar y soltar), manteniendo solo la validación de sesión en el backend. Con esto, también mostraremos lo fácil que es habilitar la biometría y otros métodos de autenticación sin contraseña. Tabla de contenidos- Una breve introducción a los conceptos básicos de autenticación- Codificación- Por qué importa la autenticación sin contraseña Requisitos previos- IDE de tu elección- Node 18 o superior
Cómo construir una aplicación GraphQL fullstack (Postgres + NestJs + React) en el menor tiempo posible. Todos los comienzos son difíciles. Incluso más difícil que elegir la tecnología es desarrollar una arquitectura adecuada. Especialmente cuando se trata de GraphQL. En este masterclass, obtendrás una variedad de mejores prácticas que normalmente tendrías que trabajar en varios proyectos, todo en solo tres horas. Siempre has querido participar en un hackathon para poner algo en funcionamiento en el menor tiempo posible, entonces participa activamente en este masterclass y únete a los procesos de pensamiento del instructor.
Node.js test runner es moderno, rápido y no requiere bibliotecas adicionales, pero entenderlo y usarlo bien puede ser complicado. Aprenderás a utilizar Node.js test runner a su máximo potencial. Te mostraremos cómo se compara con otras herramientas, cómo configurarlo y cómo ejecutar tus pruebas de manera efectiva. Durante la masterclass, haremos ejercicios para ayudarte a sentirte cómodo con el filtrado, el uso de afirmaciones nativas, la ejecución de pruebas en paralelo, el uso de CLI y más. También hablaremos sobre trabajar con TypeScript, hacer informes personalizados y la cobertura de código.
Comments