Cómo aprovechar los parámetros predeterminados de JavaScript para la inyección de dependencias

En estos días es bastante común usar la inyección de dependencia, que permite que los módulos de un proyecto se acoplen libremente. Pero a medida que los proyectos crecen en complejidad, tenemos un número astronómico de dependencias que controlar.

Para solucionar este problema, a menudo recurrimos a los contenedores de inyección de dependencia. ¿Pero es necesario en cada situación?

En esta publicación, cubriré cómo los parámetros predeterminados de JavaScript pueden ayudarnos con esta pregunta. Para hacer esto, implementaremos una aplicación simple en Node.JS. Tendrá las funcionalidades de crear y leer la información de los usuarios utilizando tres enfoques diferentes:

  1. Sin inyección de dependencia
  2. Con inyección de dependencia
  3. Con inyección de dependencia y parámetros predeterminados

Estructura del proyecto

Estructuraremos nuestro proyecto de ejemplo por función (por cierto, no estructure sus archivos en función de los roles). Entonces, la estructura será algo como esto:

├── usuarios /
│ ├── users-repository.js
│ ├── users.js
│ ├── users.spec.js
│ ├── index.js
├── app.js

Nota: a los fines de este ejemplo, guardaremos la información de los usuarios en la memoria.

Sin inyección de dependencia

Analizando el código anterior, verificamos que estamos limitados por la declaración: const usersRepo = require ('./ users-repository') en los usuarios. El módulo de usuarios, con este enfoque, está fuertemente acoplado al repositorio de usuarios.

Esto nos limita a usar la implementación de otro repositorio sin cambiar la instrucción require. Cuando se utiliza el requisito, creamos una dependencia estática del módulo requerido. Con eso, no podemos usar otro repositorio en el modelo de la aplicación además del definido por el módulo de repositorio de usuarios.

Además de eso, también estamos vinculados al repositorio de usuarios en la especificación de usuarios debido a la dependencia estática mencionada anteriormente. Estas pruebas unitarias son para probar solo el módulo de usuarios y nada más. Imagínese si el repositorio estuviera conectado a una base de datos externa. Tendríamos que interactuar con la base de datos para poder probar.

Con inyección de dependencia

Con la inyección de dependencia, el módulo de usuarios ya no está acoplado al módulo de repositorio de usuarios.

La principal diferencia con el enfoque anterior es que ahora no tenemos la dependencia estática en el módulo de usuarios (no tenemos la declaración: const usersRepo = require ('./ users-repository')). En lugar de eso, el módulo de usuarios exporta una función de fábrica con un parámetro para el repositorio. Esto nos permite pasar cualquier repositorio al módulo en un nivel superior.

Una alternativa a la función de fábrica es agregar un parámetro para el argumento del repositorio en las funciones crear y leer. Pero si las dos funciones dependen del mismo repositorio, podemos encapsularlas con una función y aprovechar los cierres de JavaScript.

Ahora, en el módulo de la aplicación, tenemos la libertad de definir qué repositorio queremos usar. Además, mira las pruebas unitarias. Ahora podemos probar el módulo de usuarios sin preocuparnos por el repositorio. ¡Solo búrlate!

Sin embargo, seamos honestos: ¿con qué frecuencia definimos dependencias que cambian a lo largo del ciclo de vida de la aplicación? Normalmente, tratamos de evitar dependencias estáticas porque dificulta las pruebas. Pero ahora, dado que queremos que sea comprobable, tenemos que pasar una instancia del repositorio al módulo de usuarios cada vez que queremos usarlo.

¿Sabes lo que sería realmente increíble? Si pudiéramos usar el módulo sin tener que darle un repositorio cada vez. Podemos hacer esto en JavaScript con los parámetros predeterminados.

Con inyección de dependencia y parámetros predeterminados

Con esta estrategia, además de la Inyección de dependencia que hemos visto en el enfoque anterior, el parámetro definido en la función de fábrica exportada por el módulo de usuarios ahora es un parámetro predeterminado: usersRepo = defaultUsersRepo.

Con el parámetro predeterminado, si no pasamos un argumento, la función utiliza el valor del parámetro predeterminado. De lo contrario, se utiliza el valor del argumento. Esto es lo mismo que usar la técnica de inyección de dependencia definida en el enfoque anterior.

Ahora, tenemos la dependencia estática nuevamente en el módulo de usuarios. Sin embargo, esta dependencia estática es solo para definir el valor utilizado en el parámetro predeterminado si no se pasa ningún argumento a la función de fábrica.

Con este enfoque, no estamos obligados a pasar el repositorio en el módulo de la aplicación cuando se requiera el módulo de usuarios. Aún así, podemos hacerlo. También podemos verificar que las pruebas unitarias puedan seguir usando el repositorio simulado, porque podemos pasarlo en lugar de usar el valor del parámetro predeterminado.

Conclusión

Los parámetros predeterminados son una función simple de JavaScript, pero potente. Con ellos, podemos implementar mejores soluciones.

Siéntete libre de preguntarme cualquier cosa.

Más recursos

Repositorio de GitHub con los ejemplos: aquí.

Mattias Petter Johansson tiene un excelente video explicativo sobre la inyección de dependencia:

Si disfrutaste este artículo, por favor dame algunos aplausos para que más personas lo vean. ¡Gracias!