Stairway to Heaven: Saliendo de Folder Hell

Este post es una continuación del artículo de Introducción al backend con arquitectura en capas, pasando de esta arquitectura a una modular, ganando escalabilidad, legibilidad, abstracción y orden.

La razón del título, es una mezcla de analogías entre Stairway to Heaven de Led Zeppelin y los círculos del infierno de la Divina Comedia de Dante Alighieri en los que se basó Alan Perez alias Scorpion para su charla en Nerdearla 2022 llamada justamente, Folder Hell.

Sin más preámbulos, ¡Comencemos!

Primeros pasos

Hagamos un clone de dicho repositorio.

git clone https://github.com/brahianpdev/blog-intro-backend-node-express-mongo

Instalemos las dependencias correspondientes y levantamos el proyecto.

npm install
npm run dev

Recordar que, se debe tener previamente creada una base de datos en Mongo y las variables de entorno configuradas correctamente en el archivo .env.

Una vez confirmamos que nuestro proyecto levanta correctamente, empezamos a reestructurar nuestros archivos y carpetas.

Arquitectura en capas vs Modular

Actualmente, nuestra estructura se ve de la siguiente forma:

Arquitectura de 4 capas

src
│   index.ts        # App entry point
└───controllers     # route controllers for all the endpoints of the app
└───config          # Environment variables and configuration related stuff
└───models          # Database models
└───repositories    # Custom queries to database
└───services        # All the business logic is here
└───routes          # Express.js entry points to controllers
Arquitectura modular

src
│   index.ts        # App entry point
└── config      
└── products 
        └── controller
        └── service
        └── model
        └── repository
        └── route

La forma de interpretar el siguiente esquema es, que nuestra aplicación esta compuesta por dos modulos, uno de configuracion, y uno de productos.

Nota al margen, es que, el modulo productos en caso de necesitar una carpeta de configuración, sera dentro del propio modulo, no fuera. En el ejemplo, se supone configuraciones globales, como lo son por ejemplo, las variables de entorno.

Comencemos

Primeramente, podemos eliminar la carpeta explanation que solo fue creada a efectos practicos de explicaciones teoricas vistas en el articulo anterior. Tambien, eliminaremos los archivos relacionados al articulo de FTP (rutas, servicios).

Creemos una carpeta dentro de src, llamada products.

Seguidamente, movamos los siguientes archivos dentro de la carpeta recien creada.

- product.route.js
- product.controller.js
- product.service.js
- product.model.js
- product.repository.js

Correccion de errores

En este punto, si intentamos levantar nuestro proyecto, tendremos errores, principalmente, de importaciones.

node:internal/modules/cjs/loader:988
  throw err;
  ^

Error: Cannot find module './path...'
Require stack:
- src/routes/index.js

Por lo que, debemos recorrer cada uno de nuestros archivos ahora, dentro de la carpeta products, corrigiendo el path del que importa lo que necesita.

Por ejemplo, nuestro product.route, tiene lo siguiente:

const productsController = require("../controllers/products.controller");

Y pasaria a ser

const productsController = require("./products.controller");

Lo mismo, aplicaría para los demas archivos.

En este punto, tendríamos solo un problema de importacion, las rutas.

Dado que las rutas, son globales, procedemos a crear en nuestra carpeta config, un archivo llamado config.routes.js, de paso, aprovechamos a cambiar el nombre del archivo config, a uno con mas sentido con respecto a lo que se aloja en el, cambiándole el nombre a config.enviroment.js

Nuestro archivo config.routes.js, deberia tener lo siguiente:

const { Router } = require("express");
const routes = Router();

const productsRoutes = require("../products/products.route");

routes.use("/products", productsRoutes);

module.exports = routes;

Ahora, debemos corregir las importaciones asi como el nombramiento correcto de las mismas, quedando de la siguiente manera:

const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");

const enviromentConfig = require("./config/config.enviroment");
const routes = require("./config/config.routes");

mongoose
  .connect(enviromentConfig.db.mongo)
  .then((res) => {
    const app = express();

    app.use(
      express.urlencoded({
        extended: true,
      })
    );

    app.use(express.json());
    app.use(cors());
    app.use("/", routes);

    app.listen(config.app.port, () => {
      console.log(`🔥 Server is running at port ${config.app.port}`);
    });

    console.log("Connected to MongoDB");
  })
  .catch((error) => console.log(error));

Despedida

Y listo, hemos pasado de una arquitectura en capas a una modular.

¡Hasta pronto 👋!

Si deseas colaborar con el contenido, regalame un cafecito