Cómo organizar un proyecto monorepo con frontend y backend
En el mundo del desarrollo de software, entender la estructura de un proyecto open source es crucial para quienes desean aprender, contribuir o incluso replicar buenas prácticas.
Hoy vamos a analizar la estructura de HeyForm, un generador de formularios conversacionales open source, desglosando sus componentes y organización para ayudarte a comprender cómo se organiza un proyecto real y complejo.
Qué es HeyForm ¶
HeyForm es una herramienta para crear formularios interactivos y conversacionales de forma sencilla, sin necesidad de conocimientos de código. Ofrece una interfaz intuitiva y personalizable, permitiendo a los usuarios crear encuestas, cuestionarios y encuestas de manera eficiente.
Principales funcionalidades de HeyForm ¶
HeyForm destaca por sus características robustas y versátiles, entre las que se incluyen:
- Diversos tipos de inputs: Campos básicos como texto, email y número de teléfono, así como opciones avanzadas como selección de imágenes, carga de archivos y selectores de fechas.
- Lógica condicional: Permite crear formularios dinámicos que adaptan su comportamiento según las respuestas del usuario.
- Integraciones poderosas: Soporte para integraciones con herramientas como Zapier y webhooks para automatización.
- Análisis de datos: Proporciona métricas detalladas como tasas de abandono y finalización, y permite exportar datos en CSV para un análisis más profundo.
- Personalización visual: Ofrece opciones de temas visuales y permite personalizar fuentes, colores y fondos para que coincidan con la identidad de la marca.
Tecnologías utilizadas en HeyForm ¶
HeyForm aprovecha un stack tecnológico moderno y escalable:
- Frontend: Utiliza React con TypeScript para construir una interfaz interactiva y modular.
- Backend: Implementado con Nest.js, proporcionando una arquitectura escalable y fácil de mantener.
- Monorepo con pnpm: La estructura monorepo facilita la gestión de múltiples paquetes con
pnpm
para la instalación y manejo de dependencias.
Estructura del proyecto: Un vistazo al árbol de directorios ¶
La organización de archivos es esencial para el mantenimiento y escalabilidad del proyecto. A continuación, se muestra una vista simplificada del árbol de directorios de HeyForm:
.
├── Dockerfile
├── README.md
├── package.json
├── packages
│ ├── answer-utils
│ ├── embed
│ ├── shared-types-enums
│ ├── utils
│ ├── server
│ └── webapp
└── pnpm-workspace.yaml
HeyForm sigue una arquitectura de monorepo (que explicamos en detalle más abajo), donde cada paquete se encuentra separado bajo el directorio packages
. Esta es una práctica recomendada para proyectos con múltiples módulos interdependientes.
Archivos de configuración
Los archivos de configuración permiten definir cómo debe comportarse el proyecto en diferentes entornos. Algunos de los más importantes son:
.env
: Variables de entorno para configurar claves API y configuraciones sensibles.tsconfig.json
: Configuración de TypeScript, lo que permite un desarrollo seguro y tipado.vite.config.ts
: Configuración para Vite, utilizada en la construcción del frontend.docker-compose.yml
: Facilita la ejecución del proyecto en contenedores Docker.
Arquitectura del proyecto HeyForm ¶
La arquitectura de HeyForm está diseñada para ser modular, escalable y fácil de mantener. Esto se logra mediante la combinación de un monorepo con una clara separación de responsabilidades entre el frontend, el backend y los paquetes compartidos. A continuación, exploraremos cómo se organizan estos componentes y cómo interactúan entre sí para formar una aplicación robusta y eficiente.
División modular en el monorepo ¶
HeyForm sigue una arquitectura modular utilizando un enfoque monorepo. Esto significa que todas las partes del proyecto, desde el servidor hasta la interfaz de usuario y las utilidades compartidas, están organizadas en distintos paquetes bajo un solo repositorio. Esta separación modular permite un desarrollo más ágil y facilita la colaboración entre diferentes equipos.
- Frontend (
webapp
): La webapp de HeyForm está construida con React y TypeScript, enfocándose en una arquitectura de componentes reutilizables. Utiliza MobX para la gestión del estado y Apollo Client para manejar las peticiones GraphQL al backend. - Backend (
server
): El backend utiliza Nest.js, un framework para Node.js que sigue una arquitectura modular y orientada a controladores. Esto permite una separación clara entre los controladores, servicios y modelos de datos. - Paquetes compartidos: Los paquetes como
utils
yshared-types-enums
contienen funciones y tipos reutilizables que se comparten entre el frontend y el backend, asegurando consistencia y reduciendo duplicación de código.
Comunicación entre frontend y backend ¶
HeyForm utiliza GraphQL como la capa principal de comunicación entre el frontend y el backend. Esta elección permite una interacción eficiente y flexible, donde el cliente puede solicitar solo los datos necesarios, reduciendo el ancho de banda y mejorando la velocidad de la aplicación.
- Apollo Client: Maneja las peticiones desde el frontend, optimizando las consultas y el almacenamiento en caché de datos.
- Nest.js con Apollo Server: El backend utiliza Apollo Server integrado con Nest.js para manejar las resoluciones de GraphQL, facilitando una implementación clara y escalable de la API.
Gestión del estado y lógica de negocio ¶
El estado de la aplicación y la lógica de negocio se gestionan de forma eficiente gracias al uso de MobX en el frontend y servicios dedicados en el backend.
- MobX: Permite una gestión del estado reactiva y sencilla, eliminando la necesidad de estructuras complejas como Redux.
- Servicios en Nest.js: El backend sigue el patrón de servicios para encapsular la lógica de negocio, facilitando la reutilización y el testing. Por ejemplo, el servicio
form.service.ts
se encarga de todas las operaciones relacionadas con la creación y gestión de formularios.
Persistencia y almacenamiento de datos ¶
HeyForm utiliza MongoDB como base de datos para almacenar formularios, respuestas y datos de usuarios. Esta elección permite una fácil escalabilidad y un modelado flexible de los datos.
- Mongoose: Se utiliza para manejar la conexión y modelado de datos en MongoDB, proporcionando una API sencilla y robusta para las operaciones CRUD.
- Redis: Implementado para el almacenamiento en caché y la gestión de sesiones, mejorando el rendimiento de la aplicación.
Manejo de trabajos en segundo plano ¶
HeyForm utiliza Bull, una biblioteca para manejar trabajos en cola, permitiendo la ejecución asíncrona de tareas como el envío de correos electrónicos, generación de reportes y procesamiento de formularios.
- Bull con Redis: Esta combinación permite una gestión eficiente de las colas de trabajo, utilizando Redis para el almacenamiento temporal de los trabajos y su procesamiento en segundo plano.
Frameworks y librerías utilizadas en HeyForm ¶
HeyForm utiliza un stack tecnológico robusto y moderno para ofrecer una experiencia de usuario fluida y asegurar la mantenibilidad del proyecto. En esta sección, detallaremos los frameworks y librerías clave, explicando su uso y las razones detrás de su elección.
Frontend: React y TypeScript ¶
El frontend de HeyForm está construido con React, una de las bibliotecas más populares para crear interfaces de usuario dinámicas y declarativas. Su uso permite una arquitectura basada en componentes reutilizables, facilitando el desarrollo y mantenimiento de la webapp.
- React: Utilizado para crear una interfaz de usuario reactiva, basada en componentes.
- React Router: Para la navegación entre diferentes vistas de la aplicación.
- MobX: Maneja el estado global de la webapp, ofreciendo una alternativa simple y eficiente a Redux.
- TailwindCSS: Utilizado para el diseño, permite escribir estilos de forma rápida y eficiente utilizando clases utilitarias.
- Apollo Client: Maneja la comunicación GraphQL entre el frontend y el backend, facilitando la gestión del estado remoto.
Webapp: Componentes React ¶
La webapp utiliza una arquitectura basada en componentes. Aquí un ejemplo del directorio de componentes:
packages/webapp/src/components
├── Button.tsx
├── FormField.tsx
├── Loader.tsx
├── Modal.tsx
├── Navbar.tsx
└── Tooltip.tsx
Cada componente es independiente y reutilizable, siguiendo las mejores prácticas de React y TypeScript.
Backend: Nest.js y Node.js ¶
El backend de HeyForm está desarrollado con Nest.js, un framework progresivo para Node.js que facilita la creación de aplicaciones escalables y bien estructuradas. Nest.js aprovecha TypeScript, lo que permite un desarrollo tipado y seguro.
- Nest.js: Ofrece una arquitectura modular y orientada a controladores, facilitando la organización del código.
- Mongoose: Maneja la conexión con MongoDB, permitiendo un modelado sencillo de los datos.
- Bull: Utilizado para manejar trabajos en cola y tareas asíncronas, como el envío de emails y procesamiento de formularios.
- Axios: Realiza peticiones HTTP desde el servidor para integraciones externas, como OpenAI y APIs de Google.
- jsonwebtoken: Permite la autenticación basada en tokens JWT para gestionar la seguridad y el acceso a la API.
Estructura del backend ¶
El servidor está implementado con Nest.js, utilizando una estructura modular para servicios y controladores:
packages/server/src
├── app.module.ts
├── controller
│ ├── form.controller.ts
│ ├── auth.controller.ts
└── service
├── form.service.ts
├── user.service.ts
Esta estructura facilita la separación de responsabilidades y mejora la mantenibilidad del código.
Utilidades y herramientas de desarrollo ¶
Para mantener la calidad del código y facilitar el proceso de desarrollo, HeyForm incluye una variedad de herramientas y utilidades:
- TypeScript: Utilizado en todo el proyecto para proporcionar tipado estático, mejorando la robustez del código y ayudando a prevenir errores.
- Vitest: Herramienta para testing, similar a Jest, utilizada para ejecutar pruebas unitarias y de integración.
- ESLint y Prettier: Configurados para garantizar la consistencia del código y aplicar buenas prácticas de programación.
- Rollup y Tsup: Utilizados para la construcción de paquetes, optimizando el código para el despliegue.
Integraciones externas ¶
HeyForm se conecta con varias APIs y servicios externos para proporcionar una funcionalidad más amplia y mejorar la experiencia del usuario:
- Zapier: Permite integraciones automáticas con miles de aplicaciones, facilitando la automatización de procesos.
- Stripe: Utilizado para procesar pagos dentro de los formularios, ofreciendo una solución segura y confiable.
- AWS S3: Almacena archivos subidos a través de los formularios, garantizando escalabilidad y durabilidad.
- OpenAI: Integración con la API de OpenAI para posibles funcionalidades de IA, como análisis de texto y recomendaciones automáticas.
Cómo es un monorepo en un proyecto real ¶
HeyForm utiliza una arquitectura monorepo, lo que significa que todos los paquetes y módulos del proyecto se encuentran dentro de un único repositorio.
Esta elección permite una mejor gestión del código compartido, simplifica el desarrollo y facilita la coordinación entre el frontend y el backend. A continuación, explicaremos cómo se organiza el monorepo y qué herramientas se utilizan para manejarlo eficientemente.
Estructura del monorepo ¶
La estructura del monorepo en HeyForm está organizada bajo el directorio packages
, donde se encuentran los distintos módulos:
.
├── Dockerfile
├── README.md
├── package.json
├── packages
│ ├── answer-utils
│ ├── embed
│ ├── shared-types-enums
│ ├── utils
│ ├── server
│ └── webapp
└── pnpm-workspace.yaml
answer-utils
: Contiene funciones relacionadas con el procesamiento de respuestas, compartidas entre el servidor y la webapp.embed
: Biblioteca JavaScript para incrustar formularios de HeyForm en sitios externos.shared-types-enums
: Define tipos y enumeraciones comunes que utilizan tanto el frontend como el backend.utils
: Paquete de utilidades que ofrece funciones reutilizables para el servidor y la webapp.server
: Implementa el backend utilizando Nest.js.webapp
: El frontend de HeyForm construido con React y TypeScript.
Herramientas para gestionar el monorepo ¶
HeyForm utiliza pnpm para manejar las dependencias y scripts del monorepo. A diferencia de npm o Yarn, pnpm tiene un enfoque más eficiente en la gestión de dependencias, ya que utiliza enlaces simbólicos para evitar la duplicación de módulos. Esto reduce el uso de espacio en disco y acelera la instalación de paquetes.
pnpm-workspace.yaml
: Este archivo define los paquetes incluidos en el workspace de pnpm, permitiendo que compartan dependencias y scripts.
packages:
- "packages/*"
- Instalación de dependencias compartidas: Los módulos compartidos como
@heyform-inc/utils
pueden ser utilizados tanto en el frontend como en el backend sin duplicar dependencias, facilitando la sincronización entre ambos.
Scripts compartidos ¶
El archivo raíz package.json
contiene scripts para gestionar tanto la webapp como el servidor desde el monorepo:
"scripts": {
"dev": "run-p dev:webapp dev:server",
"build": "run-p build:server build:webapp",
"test": "pnpm --recursive test"
}
dev:webapp
ydev:server
: Permiten iniciar el desarrollo simultáneo del frontend y backend.build
: Compila tanto la webapp como el servidor para producción.test
: Ejecuta pruebas en todos los paquetes del monorepo de forma recursiva.
Beneficios de usar un monorepo ¶
El uso de un monorepo en HeyForm ofrece varias ventajas:
- Código compartido: Los tipos, utilidades y funciones comunes se mantienen en un solo lugar (
shared-types-enums
yutils
), evitando duplicación y errores de consistencia. - Sincronización del desarrollo: Los cambios realizados en módulos compartidos afectan inmediatamente a todos los paquetes que los usan, lo que facilita la integración y reduce problemas de compatibilidad.
- Facilidad de mantenimiento: Tener todos los paquetes en un solo repositorio simplifica la gestión de versiones y el despliegue de nuevas funcionalidades.
- Eficiencia en la instalación de dependencias: Gracias a pnpm, la instalación de paquetes es rápida y optimizada, utilizando enlaces simbólicos para evitar duplicación.
Desventajas y cómo mitigarlas ¶
Aunque los monorepos ofrecen muchos beneficios, también presentan algunos desafíos:
- Escalabilidad: Con el crecimiento del proyecto, el tamaño del repositorio y el tiempo de instalación pueden aumentar. En HeyForm, esto se mitiga usando pnpm y scripts bien definidos para manejar el monorepo de forma eficiente.
- Complejidad de scripts: Gestionar scripts para múltiples paquetes puede volverse complicado. HeyForm aborda esto utilizando
run-p
, que permite ejecutar scripts en paralelo y simplifica la ejecución de comandos compartidos.
Conclusión ¶
HeyForm es un excelente ejemplo de cómo estructurar un proyecto open source siguiendo buenas prácticas y utilizando tecnologías modernas.
La combinación de un frontend basado en React, un backend con Nest.js, y una estructura monorepo proporciona escalabilidad y mantenibilidad.
Si estás buscando aprender cómo organizar y desarrollar un proyecto complejo, HeyForm es una referencia útil para adoptar en tus propios proyectos. Puedes explorar el código fuente en su repositorio de GitHub.
Escrito por:
Daniel Primo
12 recursos para developers cada domingo en tu bandeja de entrada
Además de una skill práctica bien explicada, trucos para mejorar tu futuro profesional y una pizquita de humor útil para el resto de la semana. Gratis.