<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dailos Rafael Díaz Lara</title>
    <description>The latest articles on DEV Community by Dailos Rafael Díaz Lara (@ddialar).</description>
    <link>https://dev.to/ddialar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F444998%2Faa212574-8269-49cf-bc6e-6e37d759efce.jpeg</url>
      <title>DEV Community: Dailos Rafael Díaz Lara</title>
      <link>https://dev.to/ddialar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ddialar"/>
    <language>en</language>
    <item>
      <title>Definiendo nuestras infraestructuras para desarrollo y testing con Docker</title>
      <dc:creator>Dailos Rafael Díaz Lara</dc:creator>
      <pubDate>Mon, 28 Dec 2020 16:39:44 +0000</pubDate>
      <link>https://dev.to/ddialar/definiendo-nuestras-infraestructuras-de-desarrollo-y-testing-con-docker-12ai</link>
      <guid>https://dev.to/ddialar/definiendo-nuestras-infraestructuras-de-desarrollo-y-testing-con-docker-12ai</guid>
      <description>&lt;p&gt;🇬🇧 &lt;a href="https://dev.to/ddialar/mocking-our-development-and-testing-infrastructures-with-docker-4nf0"&gt;English version&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Objetivo
&lt;/h2&gt;

&lt;p&gt;Cuando estamos creando una nueva aplicación o funcionalidad, normalmente necesitamos enviar peticiones a recursos independientes como pueden ser una base de datos o servicios con comportamiento controlado pero obviamente, realizar estas tareas contra servidores en la nube tiene un coste.&lt;/p&gt;

&lt;p&gt;En este tipo de situaciones es cuando el aislamiento de sistemas que nos proporcionan los contenedores de Docker, es realmente útil.&lt;/p&gt;

&lt;p&gt;En este artículo vamos a ver cómo podemos usar Docker para levantar una infraestructura mínima que nos permita ejecutar las tareas de desarrollo y/o testing, localmente.&lt;/p&gt;

&lt;p&gt;El principal objetivo de este texto es mostrar cómo utilizar un único archivo &lt;code&gt;docker-compose.yml&lt;/code&gt; para ambos entornos, empleando diferentes archivos &lt;code&gt;.env&lt;/code&gt; para personalizar cada contenedor específico tanto para desarrollo como para testing.&lt;/p&gt;

&lt;p&gt;Además, nos centraremos en cómo arrancar un nuevo contenedor para testing, ejecutar los tests que sean pertinentes y finalmente, apagar dicho contenedor.&lt;/p&gt;

&lt;h2&gt;
  
  
  💻 Configuración del sistema
&lt;/h2&gt;

&lt;p&gt;Si vamos a hablar sobre Docker, es obvio que necesitamos tenerlo instalado en nuestro sistema. Si aún no lo tienes, puedes seguir las indicaciones dadas en la &lt;a href="https://docs.docker.com/get-docker/"&gt;documentación oficial&lt;/a&gt;, para el sistema operativo que corresponda.&lt;/p&gt;

&lt;p&gt;Otro elemento que vamos a necesitar tener instalado en nuestro sistema es &lt;code&gt;docker-compose&lt;/code&gt;. De nuevo, si aún no lo tienes instalado, puedes seguir las indicaciones de la &lt;a href="https://docs.docker.com/compose/install/"&gt;documentación oficial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Por último, dado que este ejemplo está orientado a aplicaciones basadas en JavaScript/TypeScript, necesitamos tener instalado NodeJS (&lt;a href="https://nodejs.org/en/download/"&gt;documentación oficial&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  🏗 Inicialización del proyecto
&lt;/h2&gt;

&lt;p&gt;🔥 Si ya tienes inicializando tu propio proyecto basado en NodeJS, puedes saltarte esta sección 🔥&lt;/p&gt;

&lt;p&gt;Vamos a inicializar nuestro proyecto NodeJS abriendo una consola de comandos, en el directorio donde queramos trabajar, y escribimos el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Esta acción nos creará una único archivo &lt;code&gt;package.json&lt;/code&gt; en la raíz de nuestro proyecto, con el siguiente contenido:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Ahora podemos instalar &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt; ejecutando la siguiente instrucción en nuestra consola de comandos, para incluir esta librería en nuestro proyecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; jest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;El siguiente paso es crear la estructura más básica de directorios para el proyecto.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/
|-- /docker &lt;span class="c"&gt;# &amp;lt;= Nuevo directorio.&lt;/span&gt;
|-- /node_modules
|-- /src &lt;span class="c"&gt;# &amp;lt;= Nuevo directorio.&lt;/span&gt;
|-- package-lock.json
|-- package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  🐳 Definiendo la configuración de Docker
&lt;/h2&gt;

&lt;p&gt;Vamos a tener dos entornos principales (&lt;code&gt;development&lt;/code&gt; y &lt;code&gt;test&lt;/code&gt;) y la idea es tener un único archivo &lt;code&gt;docker-compose.yml&lt;/code&gt; para gestionar los contenedores de ambos entornos.&lt;/p&gt;
&lt;h3&gt;
  
  
  📄 Definición del archivo &lt;code&gt;docker-compose.yml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Para conseguir nuestro objetivo, dentro del directorio &lt;code&gt;/docker&lt;/code&gt; vamos a crear un único archivo llamado &lt;code&gt;docker-compose.yml&lt;/code&gt;, el cual contendrá el siguiente código:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Como podemos apreciar, hay varias líneas marcadas como &lt;code&gt;coupling smell&lt;/code&gt;. Esto significa que, con la configuración actual, podemos ejecutar un único contenedor de Docker destinado principalmente para tareas de desarrollo. Por lo tanto, está altamente acoplado a su entorno de ejecución.&lt;/p&gt;

&lt;p&gt;¿No sería genial si fuésemos capaces de reemplazar esas configuraciones definidas directamente en el código, por referencias las cuales vinieran establecidas por algún tipo de archivo de configuración?&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚙ Archivos &lt;code&gt;.env&lt;/code&gt; para contenedores Docker
&lt;/h3&gt;

&lt;p&gt;!Sí! Podemos usar archivos &lt;code&gt;.env&lt;/code&gt; de la misma manera que ya los usamos para nuestras aplicaciones, pero para configurar contenedores de Docker.&lt;/p&gt;

&lt;p&gt;Lo primero que necesitamos hacer es modificar el archivo &lt;code&gt;docker-compose.yml&lt;/code&gt; que acabamos de crear para usar plantillas basadas en llaves, para definir nombres de constantes que reemplazaremos con los valores indicados en nuestros archivos &lt;code&gt;.env&lt;/code&gt;. De este modo, el contenido del archivo &lt;code&gt;docker-compose.yml&lt;/code&gt; quedará de la siguiente manera:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Como podemos ver, hemos reemplazado los valores directamente escritos en el código por referencias del tipo &lt;code&gt;${CONSTANT_NAME}&lt;/code&gt;. El nombre de las variables escrito entre llaves será el nombre de los valores definidos en nuestros archivos &lt;code&gt;.env&lt;/code&gt;. De esta manera, cuando arranquemos el comando &lt;code&gt;docker-compose&lt;/code&gt; usando una opción específica de la línea de comandos que veremos más adelante, el contenido del archivo &lt;code&gt;.env&lt;/code&gt; será reemplazado en nuestro archivo &lt;code&gt;docker-compose.yml&lt;/code&gt; antes de que se cree el contenedor de Docker.&lt;/p&gt;

&lt;p&gt;Ahora es el momento de definir nuestros entornos así que modificamos el contenido del directorio &lt;code&gt;/docker&lt;/code&gt; para que quede tal que así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/
|-- /docker
|   |-- /dev &lt;span class="c"&gt;# &amp;lt;= Nuevo directorio y archivo.&lt;/span&gt;
|   |   |-- .docker.dev.env
|   |-- /test &lt;span class="c"&gt;# &amp;lt;= Nuevo directorio y archivo.&lt;/span&gt;
|   |   |-- .docker.test.env
|   |-- docker-compose.yml
|-- /node_modules
|-- /src
|-- package-lock.json
|-- package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Por cada entorno hemos creado un único subdirectorio: &lt;code&gt;dev&lt;/code&gt; y &lt;code&gt;test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Dentro de cada subdirectorio de entorno hemos creado un archivo &lt;code&gt;.env&lt;/code&gt; específico: &lt;code&gt;.docker.dev.env&lt;/code&gt; y &lt;code&gt;.docker.test.env&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;🙋❓ &lt;strong&gt;¿Sería posible nombrar los archivos de entorno sólo como  &lt;code&gt;.env&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sí, es posible y además, no habría ningún problema en ello pero... un nombre de archivo tan descriptivo es una ayuda para nuestro rol como profesionales del desarrollo. Dado que en un mismo proyecto es muy probable que haya múltiples archivos de configuración, es útil ser capaz de diferenciarlos cuando tenemos varios de ellos abiertos, en el editor de código, al mismo tiempo. Esta es la razón por la que los archivos &lt;code&gt;.env&lt;/code&gt; tienen uno nombres tan descriptivos.&lt;/p&gt;

&lt;p&gt;Ahora pasaremos a definir el contenido de nuestros archivos de entornos, para que queden de la siguiente manera:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;y...&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Hay cuatro propiedades a las que debemos prestar atención a la hora de diferenciar entre los dos archivos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CONTAINER_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EXTERNAL_PORT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VOLUME_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CONFIGURATION_PATH&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La propiedad &lt;code&gt;CONTAINER_NAME&lt;/code&gt; nos permite definir el nombre del contenedor que veremos después de que éste ha sido creado y además, cuando ejecutamos el comando &lt;code&gt;docker ps -a&lt;/code&gt; para listar todos los contenedores presentes en nuestro sistema.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EXTERNAL_PORT&lt;/code&gt; es una propiedad realmente sensible ya que nos permite definir el puerto que el contenedor tendrán publicado y a través del cual, nuestra aplicación podrá conectarse con él. Es realmente importante tener cuidado con este parámetro porque algunas veces nos interesará tener levantados ambos entornos al mismo tiempo (&lt;code&gt;development&lt;/code&gt; y &lt;code&gt;test&lt;/code&gt;), pero si hemos definido el mismo puerto de acceso para ambos contenedores, el sistema nos lanzará un error al lanzar el segundo contenedor, ya que el puerto estará ocupado.&lt;/p&gt;

&lt;p&gt;La propiedad &lt;code&gt;VOLUME_NAME&lt;/code&gt; definirá el nombre del almacenamiento de datos en nuestro sistema.&lt;/p&gt;

&lt;p&gt;Finalmente, en caso de que hayamos definido cualquier tipo de conjunto de datos para inicializar nuestra base de datos antes de usarla, la propiedad &lt;code&gt;CONFIGURATION_PATH&lt;/code&gt; nos permitirá definir dónde está ubicado ese conjunto de datos.&lt;/p&gt;

&lt;p&gt;🙋‍♀️❓ &lt;strong&gt;Oye pero, ¿qué pasa con la propiedad &lt;code&gt;COMPOSE_PROJECT_NAME&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Esa es una magnífica pregunta.&lt;/p&gt;

&lt;p&gt;Nuestro primer objetivo es crear un contenedor específico por cada entorno, basándonos en el mismo archivo &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ahora mismo, si ejecutamos nuestro &lt;code&gt;docker-compose&lt;/code&gt; para &lt;code&gt;development&lt;/code&gt;, por ejemplo, crearemos el contenedor con esa definición de entorno y el archivo &lt;code&gt;docker-compose.yml&lt;/code&gt; quedará enlazado a dicho contenedor.&lt;/p&gt;

&lt;p&gt;De este modo, si intentamos ahora arrancar el mismo archivo pero utilizando la configuración para &lt;code&gt;testing&lt;/code&gt;, el resultado final será que hemos actualizado el contenedor previo de &lt;code&gt;development&lt;/code&gt;, sin la configuración para el entorno de &lt;code&gt;testing&lt;/code&gt;. ¿Por qué? Pues porque el archivo de composición está enlazado al contenedor que arrancamos inicialmente.&lt;/p&gt;

&lt;p&gt;Para conseguir nuestro objetivo satisfactoriamente, empleamos la propiedad &lt;code&gt;COMPOSE_PROJECT_NAME&lt;/code&gt; dentro de cada archivo &lt;code&gt;.env&lt;/code&gt; y le asignamos valores diferentes dependiendo del entorno al que pertenezca.&lt;/p&gt;

&lt;p&gt;De esta manera, cada vez que ejecutemos el archivo de composición, dado que el nombre de proyecto es diferente para cada archivo &lt;code&gt;.env&lt;/code&gt;, las modificaciones que se apliquen sólo afectarán al contenedor que corresponda con dicho nombre de proyecto.&lt;/p&gt;

&lt;p&gt;🙋❓ &lt;strong&gt;Vale, bien, pero hemos usado la propiedad &lt;code&gt;COMPOSE_PROJECT_NAME&lt;/code&gt; sólo dentro de nuestros archivos &lt;code&gt;.env&lt;/code&gt; y no en el archivo &lt;code&gt;docker-compose.yml&lt;/code&gt;. ¿Cómo es posible que afecte al resultado final?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Es posible porque esa propiedad es leída directamente por el comando &lt;code&gt;docker-compose&lt;/code&gt; y no es necesario que esté incluida dentro del archivo &lt;code&gt;docker-compose.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;En este enlace puedes encontrar toda la &lt;a href="https://docs.docker.com/compose/reference/envvars/#compose_project_name"&gt;documentación oficial&lt;/a&gt; about &lt;code&gt;COMPOSE_PROJECT_NAME&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤹‍♂️ Inicializando la base de datos
&lt;/h2&gt;

&lt;p&gt;🔥 Advertencia: El proceso que se expone a continuación está dirigido a inicializar el contenido de una base de datos MongoDB. Si quieres usar un motor diferente, necesitarás adaptar este proceso así como la configuración del &lt;code&gt;docker-compose.yml&lt;/code&gt; para ello. 🔥&lt;/p&gt;

&lt;p&gt;El concepto más básico que debemos saber, si es que no lo sabemos ya, es que cuando un contenedor basado en MongoDB se ejecuta por primera vez, todos los archivos con extensión &lt;code&gt;.sh&lt;/code&gt; o &lt;code&gt;.js&lt;/code&gt; ubicados en el directorio &lt;code&gt;/docker-entrypoint-initdb.d&lt;/code&gt; dentro del propio contenedor, son ejecutados.&lt;/p&gt;

&lt;p&gt;Esto nos proporciona una manera para inicializar nuestra base de datos.&lt;/p&gt;

&lt;p&gt;Si quieres profundizar en esta propiedad, puedes consultar la &lt;a href="https://hub.docker.com/_/mongo"&gt;documentación de la imagen oficial de MongoDB en Docker&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧪 Configuración del entorno de testing
&lt;/h3&gt;

&lt;p&gt;Para ver cómo podemos hacer esto, vamos a empezar por el entorno de &lt;code&gt;testing&lt;/code&gt; así que antes de nada, tenemos que crear la siguiente estructura de archivos dentro del directorio &lt;code&gt;/docker/test&lt;/code&gt; de nuestro proyecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/
|-- /docker
|   |-- /dev
|   |   |-- .docker.dev.env
|   |-- /test
|   |   |-- /configureDatabase &lt;span class="c"&gt;# &amp;lt;= Nuevo directorio y archivo.&lt;/span&gt;
|   |   |   |-- initDatabase.js
|   |   |-- .docker.test.env
|   |-- docker-compose.yml
|-- /node_modules
|-- /src
|-- package-lock.json
|-- package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;El contenido del archivo &lt;code&gt;initDatabase.js&lt;/code&gt; será el siguiente:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Este script está dividido en tres elementos diferentes.&lt;/p&gt;

&lt;p&gt;La constante &lt;code&gt;apiDatabases&lt;/code&gt; contiene todas las definiciones de bases de datos que queremos crear para nuestro contenedor.&lt;/p&gt;

&lt;p&gt;Cada definición de base de datos contendrá su nombre (&lt;code&gt;dbName&lt;/code&gt;), un array de usuarios (&lt;code&gt;dbUsers&lt;/code&gt;) los cuales estarán autorizados para operar con la base de datos (incluyendo la definición de sus privilegios de acceso) y el conjunto de datos con los que inicializaremos la base de datos.&lt;/p&gt;

&lt;p&gt;La función &lt;code&gt;createDatabaseUser&lt;/code&gt; está destinada a gestionar la información contenida en cada bloque del &lt;code&gt;apiDatabases&lt;/code&gt;, procesar los datos de usuarios y crearlos dentro de la base de datos indicada.&lt;/p&gt;

&lt;p&gt;Finalmente, el bloque &lt;code&gt;try/catch&lt;/code&gt; contiene la magia porque en este bloque iteramos sobre la constante &lt;code&gt;apiDatabase&lt;/code&gt;, conmutamos entre bases de datos y procesamos la información.&lt;/p&gt;

&lt;p&gt;Una vez que hemos analizado este código, si recordamos el contenido de nuestro archivo &lt;code&gt;docker-compose.yml&lt;/code&gt;, dentro de la sección &lt;code&gt;volumes&lt;/code&gt; definimos la siguiente línea:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;- ${CONFIGURATION_PATH}:/docker-entrypoint-initdb.d:rw&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Además, para el entorno de &lt;code&gt;testing&lt;/code&gt;, dentro del archivo &lt;code&gt;.docker.test.env&lt;/code&gt;, configuramos lo siguiente:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CONFIGURATION_PATH="./test/configureDatabase"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Con esta acción, el proceso &lt;code&gt;docker-compose&lt;/code&gt; está copiando el contenido de la ruta indicada por &lt;code&gt;CONFIGURATION_PATH&lt;/code&gt; dentro del directorio del contenedor &lt;code&gt;/docker-entrypoint-initdb.d:rw&lt;/code&gt; antes de que éste se arranque por primera vez. Así es como estamos definiendo el script de configuración de nuestra base de datos, para que sea ejecutado al iniciarse el contenedor.&lt;/p&gt;

&lt;p&gt;🙋‍♀️❓ &lt;strong&gt;Para esta configuración no estás usando ningún conjunto de datos iniciales. ¿Por qué?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Porque esta será la base de datos de testing y la intención es que se almacenen y eliminen datos ad-hoc en base a los tests que estén ejecutándose en un momento concreto. Por esta razón no tiene sentido que inicialicemos la base de datos con información que vamos a crear/editar/eliminar dinámicamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠 Configuración del entorno de desarrollo
&lt;/h3&gt;

&lt;p&gt;Esta configuración es muy similar a la de &lt;code&gt;testing&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lo primero que tenemos que hacer es modificar el subdirectorio  &lt;code&gt;/docker/dev&lt;/code&gt; de nuestro proyecto, para que quede tal que así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/
|-- /docker
|   |-- /dev
|   |   |-- /configureDatabase &lt;span class="c"&gt;# &amp;lt;= Nuevo directorio y archivos.&lt;/span&gt;
|   |   |   |-- initDatabase.js
|   |   |   |-- postsDataToBePersisted.js
|   |   |   |-- usersDataToBePersisted.js
|   |   |-- .docker.dev.env
|   |-- /test
|   |   |-- /configureDatabase
|   |   |   |-- initDatabase.js
|   |   |-- .docker.test.env
|   |-- docker-compose.yml
|-- /node_modules
|-- /src
|-- package-lock.json
|-- package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Los archivos &lt;code&gt;postsDataToBePersisted.js&lt;/code&gt; y &lt;code&gt;usersDataToBePersisted.js&lt;/code&gt; sólo contienen información estática definida dentro de constantes independientes. Esta información será almacenad en la base de datos indicada, dentro de la colección especificada.&lt;/p&gt;

&lt;p&gt;La estructura de dichos contenidos será la siguiente:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Por otro lado, el contenido del archivo &lt;code&gt;initDatabase.js&lt;/code&gt; es bastante similar al del entorno de &lt;code&gt;testing&lt;/code&gt; pero un poco más complejo ya que ahora tenemos que gestionar colecciones y datos. De este modo, el resultado final es este:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;En este script hay varias partes que necesitamos analizar.&lt;/p&gt;

&lt;p&gt;En la cabecera tenemos un bloque compuesto por dos llamadas a la función &lt;code&gt;load()&lt;/code&gt; encaminadas a importar los datos preparados y almacenados en las constantes que declaramos en los otros archivos JavaScript.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔥 Hay que prestar atención a que la ruta indicada para hacer referencia a los archivos de datos, es relativa al interior de la estructura de ficheros del contenedor de Docker y no a la de nuestro sistema. 🔥&lt;/p&gt;

&lt;p&gt;ℹ️ Si quieres aprender más acerca de cómo ejecutar MongoDB archivos JavaScript en su consola de comandos, echa un vistazo a su &lt;a href="https://docs.mongodb.com/manual/tutorial/write-scripts-for-the-mongo-shell/#execute-a-javascript-file"&gt;documentación oficial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Después de "importar" las definiciones de las constantes &lt;code&gt;usersToBePersisted&lt;/code&gt; y &lt;code&gt;postsToBePersisted&lt;/code&gt; mediante el uso de la función &lt;code&gt;load()&lt;/code&gt;, estas están disponibles globalmente dentro del contexto de nuestro script de inicialización.&lt;/p&gt;

&lt;p&gt;El siguiente bloque a analizar es el de la constante &lt;code&gt;apiDatabases&lt;/code&gt; donde, además de los campos &lt;code&gt;dbName&lt;/code&gt; y &lt;code&gt;dbUsers&lt;/code&gt; que ya vimos en la configuración de &lt;code&gt;testing&lt;/code&gt;, en este caso el array &lt;code&gt;dbData&lt;/code&gt; es un poco más complejo.&lt;/p&gt;

&lt;p&gt;Cada objeto declarado dentro del array &lt;code&gt;dbData&lt;/code&gt; define el nombre de la colección así como el conjunto de datos que debe ser almacenado en dicha colección.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Ahora nos encontramos con la definición de la constante &lt;code&gt;collections&lt;/code&gt;. Es la definición de un mapa de funciones el cual contiene las acciones que se deben ejecutar por cada colección definida en el bloque &lt;code&gt;apiDatabases.dbData&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Como podemos ver, en estas funciones estamos invocando directamente instrucciones nativas de MongoDB.&lt;/p&gt;

&lt;p&gt;La siguiente función que nos encontramos es &lt;code&gt;createDatabaseUsers&lt;/code&gt; la cual no tiene diferencias con la que definimos para el entorno de &lt;code&gt;testing&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Justo antes de terminar el archivo, encontramos la función &lt;code&gt;populateDatabase&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;En esta función es donde vamos a través de las colecciones de bases de datos, insertando los datos asignados y aquí es donde invocamos al mapa de funciones &lt;code&gt;collections&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finalmente tenemos el bloque &lt;code&gt;try/catch&lt;/code&gt; donde ejecutamos las mismas acciones que para el entorno &lt;code&gt;testing&lt;/code&gt; pero hemos incluido la llamada a la función &lt;code&gt;populateDatabase&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;De esta manera es como hemos podido configurar el script de inicialización para nuestra base de datos del entorno de desarrollo.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧩 Comando de Docker Compose
&lt;/h2&gt;

&lt;p&gt;Una vez que hemos definido el archivo de composición así como el conjunto de datos que inicializará nuestra base de datos, tenemos que definir los campos mediante los cuales, operaremos nuestros contenedores.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔥 Hay que prestar especial atención al hecho de que las rutas empleadas están referenciadas a la raíz de nuestro proyecto. 🔥&lt;/p&gt;

&lt;h2&gt;
  
  
  🌟 Configurando los últimos detalles para NodeJS
&lt;/h2&gt;

&lt;p&gt;El último paso es definir los scripts necesarios dentro de nuestro archivo &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Para proporcionar una mejor modularización de los scripts, es muy recomendable que se dividan en diferentes scripts atómicos y luego, crear otros scripts diferentes para agrupar aquellos que sean más específicos.&lt;/p&gt;

&lt;p&gt;Por ejemplo, en este código hemos definido los scripts &lt;code&gt;dev_infra:up&lt;/code&gt;, &lt;code&gt;dev_infra:down&lt;/code&gt;, &lt;code&gt;test:run&lt;/code&gt;, &lt;code&gt;test_infra:up&lt;/code&gt; and &lt;code&gt;test_infra:down&lt;/code&gt; que son atómicos porque definen una acción simple y serán los encargados de arrancar y para los contenedores para cada entorno, así como de ejecutar la suite de test.&lt;/p&gt;

&lt;p&gt;Por el contrario tenemos los scripts &lt;code&gt;build:dev&lt;/code&gt; y &lt;code&gt;test&lt;/code&gt; que son compuestos ya que cada uno involucra varios scripts atómicos.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 FAQ
&lt;/h2&gt;

&lt;p&gt;❓ &lt;strong&gt;¿Qué pasa si la suite de testing se para repentinamente porque alguno de los tests ha fallado?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No hay que preocuparse por esto porque es verdad que la infraestructura de testing continuará ejecutándose pero tenemos dos opciones:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mantener en ejecución el contenedor ya que la próxima vez que ejecutemos la suite de tests, el comando &lt;code&gt;docker-compose&lt;/code&gt; actualizará el contenido del contenedor.&lt;/li&gt;
&lt;li&gt;Ejecutar manualmente el script de apagado del contenedor de testing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;❓ &lt;strong&gt;¿Qué sucede si en lugar de una base de datos, necesitamos ejecutar algún servicio más complejo como una API?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sólo necesitamos configurar los contenedores/servicios necesarios dentro del archivo &lt;code&gt;docker-compose.yml&lt;/code&gt;, prestando especial atención a la configuración &lt;code&gt;.env&lt;/code&gt; para cada entorno.&lt;/p&gt;

&lt;p&gt;No importa lo que queramos incluir en nuestros contenedores. Lo importante aquí es que vamos a ser capaces de arrancarlos y detenerlos cuando nuestro proyecto lo necesite.&lt;/p&gt;

&lt;h2&gt;
  
  
  👋 Conclusiones finales
&lt;/h2&gt;

&lt;p&gt;Con esta configuración podemos incluir la gestión de la infraestructura necesaria para nuestros proyectos con NodeJS.&lt;/p&gt;

&lt;p&gt;Este tipo de configuraciones nos proporciona un nivel de desacoplamiento que aumenta nuestra independencia durante la fase de desarrollo, ya que vamos a tratar elementos externos a nuestro código como una caja negra con la cual interactuar.&lt;/p&gt;

&lt;p&gt;Otro punto interesante de esta estrategia es que cada vez que arrancamos el contenedor mediante el comando &lt;code&gt;docker-compose&lt;/code&gt;, éste es totalmente renovado lo que nos permite asegurar que nuestras suites de tests van a ejecutarse sobre sistemas completamente limpios.&lt;/p&gt;

&lt;p&gt;Además, mantendremos limpio nuestro propio sistema ya que no necesitaremos instalar ningún tipo de aplicación auxiliar porque todas ellas, estarán incluidas en diferentes contenedores que compondrán nuestras infraestructura de pruebas.&lt;/p&gt;

&lt;p&gt;Sólo una advertencia a este respecto, trata de mantener el contenido de dichos contenedores lo más actualizado posible para, de ese modo, hacer las pruebas contra un entorno lo más parecido posible al que podemos encontrarnos en producción.&lt;/p&gt;

&lt;p&gt;Espero que este contenido te sea útil. Si tienes cualquier pregunta, siéntete totalmente libre de contactar conmigo. Aquí están mis perfiles de &lt;a href="https://twitter.com/ddialar"&gt;Twitter&lt;/a&gt;, &lt;a href="https://linkedin.com/in/ddialar"&gt;LinkedIn&lt;/a&gt; y &lt;a href="https://github.com/ddialar"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🙏 Reconocimientos y agradecimientos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/jntramosbonilla"&gt;Jonatan Ramos&lt;/a&gt; por darme la pista del &lt;code&gt;COMPOSE_PROJECT_NAME&lt;/code&gt; para crear archivos  &lt;code&gt;docker-compose.yml&lt;/code&gt; único que se comparten entre diferentes entornos.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>tdd</category>
    </item>
    <item>
      <title>Mocking our development and testing infrastructures with Docker</title>
      <dc:creator>Dailos Rafael Díaz Lara</dc:creator>
      <pubDate>Mon, 28 Dec 2020 16:39:18 +0000</pubDate>
      <link>https://dev.to/ddialar/mocking-our-development-and-testing-infrastructures-with-docker-4nf0</link>
      <guid>https://dev.to/ddialar/mocking-our-development-and-testing-infrastructures-with-docker-4nf0</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/ddialar/definiendo-nuestras-infraestructuras-de-desarrollo-y-testing-con-docker-12ai"&gt;🇪🇸 Versión en español&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Context
&lt;/h2&gt;

&lt;p&gt;When we are creating a new application or feature, we usually need to send requests to independent resources such as databases or mocked services, but it's obvious that running these kind of actions against deployed servers have a cost.&lt;/p&gt;

&lt;p&gt;On these kind of situations is where the isolation of systems provided by Docker containers becomes really useful.&lt;/p&gt;

&lt;p&gt;In this post we are going to see how to use Docker for getting up the minimum infrastructure which allows us to run the development and/or testing tasks... locally.&lt;/p&gt;

&lt;p&gt;The main target of this text is to show how to user a single &lt;code&gt;docker-compose.yml&lt;/code&gt; file for both environments, using different &lt;code&gt;.env&lt;/code&gt; files to customize the specific container for every one, development and testing.&lt;/p&gt;

&lt;p&gt;In addition, we will focus on how to start up the new container for testing purposes, execute the tests and then, shut down the container.&lt;/p&gt;

&lt;h2&gt;
  
  
  💻 System configuration
&lt;/h2&gt;

&lt;p&gt;If we are going to be talking about Docker, it's obvious that we need to have it already installed in our system. If you don't have it yet, you can follow the &lt;a href="https://docs.docker.com/get-docker/"&gt;official documentation&lt;/a&gt; instruction for your specific operative system.&lt;/p&gt;

&lt;p&gt;Another element that we are going to need is &lt;code&gt;docker-compose&lt;/code&gt;. Once again, if you have not installed it yet, you can follow the &lt;a href="https://docs.docker.com/compose/install/"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, due to this example is aimed to applications development based on JavaScript/TypeScript, we need to have installed NodeJS (&lt;a href="https://nodejs.org/en/download/"&gt;official documentation&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  🏗 Project initialization
&lt;/h2&gt;

&lt;p&gt;🔥 If you have already started your NodeJS project, you can skip this section 🔥&lt;/p&gt;

&lt;p&gt;We are going to initialize our NodeJS project opening a CLI, in the folder where we want to work, and typing the next command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This action will create a single &lt;code&gt;package.json&lt;/code&gt; file in the root of our project, with the next content:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Now we can install &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt; running the next command in our CLI, in order to include this library in the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; jest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The next step is to create the most basic folder structure for the project.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/
|-- /docker &lt;span class="c"&gt;# &amp;lt;= New subfolder.&lt;/span&gt;
|-- /node_modules
|-- /src &lt;span class="c"&gt;# &amp;lt;= New subfolder.&lt;/span&gt;
|-- package-lock.json
|-- package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  🐳 Setting up the Docker configuration
&lt;/h2&gt;

&lt;p&gt;We are going to have two main environments (&lt;code&gt;development&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;) and the main idea is to have a single &lt;code&gt;docker-compose.yml&lt;/code&gt; file in order to manage both environment containers.&lt;/p&gt;
&lt;h3&gt;
  
  
  📄 &lt;code&gt;docker-compose.yml&lt;/code&gt; file definition
&lt;/h3&gt;

&lt;p&gt;In order to reach that goal, inside the &lt;code&gt;/docker&lt;/code&gt; folder we are going to create our single &lt;code&gt;docker-compose.yml&lt;/code&gt; file which will contains the next code:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;As we can see, there are several lines marked as &lt;code&gt;coupling smell&lt;/code&gt;. It means that, with the current configuration, we can only run a single Docker container mainly aimed for development tasks. So we are strongly coupled to this environment.&lt;/p&gt;

&lt;p&gt;Wouldn't it be fine whether we were able to replace those hardcoded configurations by references and that those references are defined by any kind of configuration file?&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚙ &lt;code&gt;.env&lt;/code&gt; files for Docker containers
&lt;/h3&gt;

&lt;p&gt;Yes!!! We can use &lt;code&gt;.env&lt;/code&gt; files in the same way we do that for our applications, but for configuring Docker containers.&lt;/p&gt;

&lt;p&gt;First at all, we need to edit the &lt;code&gt;docker-compose.yml&lt;/code&gt; file we created recently in order to use &lt;code&gt;curly-braces&lt;/code&gt; templates to define the constant names which will be replaced with the value defined in our &lt;code&gt;.env&lt;/code&gt; files. This way, the &lt;code&gt;docker-compose.yml&lt;/code&gt; file content will be defined this way:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As we can see, we have replaced the hardcoded values by &lt;code&gt;${CONSTANT_NAME}&lt;/code&gt; references. The name typed between curly braces will be the name of the values defined into our &lt;code&gt;.env&lt;/code&gt; files. This way, when we run the &lt;code&gt;docker-compose&lt;/code&gt; command, using some special CLI options that we will see later, the &lt;code&gt;.env&lt;/code&gt; file content will be replaced into our &lt;code&gt;docker-compose.yml&lt;/code&gt; file before creating the Docker container.&lt;/p&gt;

&lt;p&gt;Now it's time to define our environments so we are edit the &lt;code&gt;/docker&lt;/code&gt; folder content this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/
|-- /docker
|   |-- /dev
|   |   |-- .docker.dev.env
|   |-- /test
|   |   |-- .docker.test.env
|   |-- docker-compose.yml
|-- /node_modules
|-- /src
|-- package-lock.json
|-- package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For every environment, we have created a single subfolder: &lt;code&gt;dev&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Into every environment subfolder we have created a specific &lt;code&gt;.env&lt;/code&gt; file: &lt;code&gt;.docker.dev.env&lt;/code&gt; and &lt;code&gt;.docker.test.env&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;🙋❓ &lt;strong&gt;Could it be possible just naming the environment files as &lt;code&gt;.env&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, it could and besides, there wouldn't be any issue with it but... a so descriptive file name is a kindly help for us as developers. Due to in the same project it's really likely there are multiple configuration files, it's useful to be able to differentiate between then when we have several ones open, at the same time, in the code editor. That is the reason why the &lt;code&gt;.env&lt;/code&gt; files have a so descriptive names.&lt;/p&gt;

&lt;p&gt;Now it's time to define the content of our environment files this way:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;and...&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;There are four properties which you must pay attention in order to differentiate both files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CONTAINER_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EXTERNAL_PORT&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;VOLUME_NAME&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CONFIGURATION_PATH&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;CONTAINER_NAME&lt;/code&gt; property will define the name that we will see after the container is created and we run the command &lt;code&gt;docker ps -a&lt;/code&gt; in order to list the whole containers in our system.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EXTERNAL_PORT&lt;/code&gt; is a really sensitive property due to it will define the connection port published by the container through which our application will connect with it. It's really important to be careful with this parameter because some times we will want to run the testing suite at the same time we have up the application in development mode, so if we define the same port for both containers, the system will throw an error because the selected port is already in use.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;VOLUME_NAME&lt;/code&gt; property will define the data storage name in our system.&lt;/p&gt;

&lt;p&gt;Finally, in case we have defined any kind of data to prepopulate the database before using it, the &lt;code&gt;CONFIGURATION_PATH&lt;/code&gt; property will allow us to define where that set of data is located.&lt;/p&gt;

&lt;p&gt;🙋‍♀️❓ &lt;strong&gt;Hey but, what about the &lt;code&gt;COMPOSE_PROJECT_NAME&lt;/code&gt; property?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's a great question.&lt;/p&gt;

&lt;p&gt;Our main goal is to create a specific container per environment, based on the same &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Right now, if we run our &lt;code&gt;docker-compose&lt;/code&gt; for &lt;code&gt;development&lt;/code&gt;, for instance, we will create the container with that environment definition and the &lt;code&gt;docker-compose.yml&lt;/code&gt; file will be bound with that container.&lt;/p&gt;

&lt;p&gt;This way, if we try to run the same file but setting the &lt;code&gt;testing&lt;/code&gt; configuration, the final result will be an update of the previous &lt;code&gt;development&lt;/code&gt; container, without the defined &lt;code&gt;testing&lt;/code&gt; configuration. Why? Because the compose file is bound to the first started container.&lt;/p&gt;

&lt;p&gt;In order to reach our target successfully, we use the &lt;code&gt;COMPOSE_PROJECT_NAME&lt;/code&gt; property into every &lt;code&gt;.env&lt;/code&gt; file and we set a different value depending on the environment.&lt;/p&gt;

&lt;p&gt;This way, every time we run the compose file, due to the project name is different for every &lt;code&gt;.env&lt;/code&gt; file, the modifications will only affect to the containers bound with every project name.&lt;/p&gt;

&lt;p&gt;🙋❓ &lt;strong&gt;That's fine but we are using &lt;code&gt;COMPOSE_PROJECT_NAME&lt;/code&gt; only into our &lt;code&gt;.env&lt;/code&gt; files and not in the &lt;code&gt;docker-compose.yml&lt;/code&gt; one. How is possible that it affect to the final result?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's possible because that property is read directly by &lt;code&gt;docker-compose&lt;/code&gt; command and it's not needed to be included into the &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;In this link you have the whole &lt;a href="https://docs.docker.com/compose/reference/envvars/#compose_project_name"&gt;official documentation&lt;/a&gt; about &lt;code&gt;COMPOSE_PROJECT_NAME&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤹‍♂️ Populating the database
&lt;/h2&gt;

&lt;p&gt;🔥 Caveat: The next explained process is aimed to populate a MongoDB database. If you want to use a different engine, you have to adapt this process and the &lt;code&gt;docker-compose.yml&lt;/code&gt; configuration for it. 🔥&lt;/p&gt;

&lt;p&gt;The most basic concept we must know, if we already don't, is that when a MongoDB based on container starts first time, the whole files with extension &lt;code&gt;.sh&lt;/code&gt; or &lt;code&gt;.js&lt;/code&gt; located into the container folder &lt;code&gt;/docker-entrypoint-initdb.d&lt;/code&gt; are executed.&lt;/p&gt;

&lt;p&gt;This situation provides us a way to initialize our database.&lt;/p&gt;

&lt;p&gt;If you want to get deeper about it, you can find the whole information about it in this link of the &lt;a href="https://hub.docker.com/_/mongo"&gt;MongoDB Docker image documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧪 Testing environment configuration
&lt;/h3&gt;

&lt;p&gt;In order to see how we can do that, we are going to start by the &lt;code&gt;testing&lt;/code&gt; environment so first at all, we have to create the next file structure into the &lt;code&gt;/docker/test&lt;/code&gt; folder of our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/
|-- /docker
|   |-- /dev
|   |   |-- .docker.dev.env
|   |-- /test
|   |   |-- /configureDatabase &lt;span class="c"&gt;# &amp;lt;= New subfolder and file.&lt;/span&gt;
|   |   |   |-- initDatabase.js
|   |   |-- .docker.test.env
|   |-- docker-compose.yml
|-- /node_modules
|-- /src
|-- package-lock.json
|-- package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The content of the &lt;code&gt;initDatabase.js&lt;/code&gt; file will be the next one:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;This script is divided in three different elements.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;apiDatabases&lt;/code&gt; constant contains the whole databases definitions that we want to create for this container.&lt;/p&gt;

&lt;p&gt;Every database definition will contain its name (&lt;code&gt;dbName&lt;/code&gt;), an array of users (&lt;code&gt;dbUsers&lt;/code&gt;) whose will be allowed to operate with the database (including their accessing privilege definitions) and the dataset which we will populate the database.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;createDatabaseUser&lt;/code&gt; function is focused on handle the information contained into every &lt;code&gt;apiDatabases&lt;/code&gt; block, process the users data and create them into the specified database.&lt;/p&gt;

&lt;p&gt;Finally the &lt;code&gt;try/catch&lt;/code&gt; block contains the magic because in this block we iterate over the &lt;code&gt;apiDatabases&lt;/code&gt; constant, switch between databases and process the information.&lt;/p&gt;

&lt;p&gt;Once we have checked this code, if we remember our &lt;code&gt;docker-compose.yml&lt;/code&gt; file content, into the &lt;code&gt;volumes&lt;/code&gt; section we defined the next line:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;- ${CONFIGURATION_PATH}:/docker-entrypoint-initdb.d:rw&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In addition, for the &lt;code&gt;testing&lt;/code&gt; environment, into the &lt;code&gt;.docker.test.env&lt;/code&gt; file we set this configuration:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CONFIGURATION_PATH="./test/configureDatabase"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With this action, the &lt;code&gt;docker-compose&lt;/code&gt; process is copying the content of the path defined by &lt;code&gt;CONFIGURATION_PATH&lt;/code&gt; into the container &lt;code&gt;/docker-entrypoint-initdb.d:rw&lt;/code&gt; before it's run first time. So we are setting our database configuration script to be executed in the container start up.&lt;/p&gt;

&lt;p&gt;🙋‍♀️❓ &lt;strong&gt;For this configuration you are not setting any initial data. Why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because it will be the testing database so the intention is to persist and remove data ad-hoc based on the tests that are running in a specific moment. By this reason, it has not sense to populate this database with mocked information once we are going to create/edit/delete it dynamically.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠 Development environment configuration
&lt;/h3&gt;

&lt;p&gt;This configuration is pretty similar to the &lt;code&gt;testing&lt;/code&gt; one.&lt;/p&gt;

&lt;p&gt;First at all, we have to modify the &lt;code&gt;/docker/dev&lt;/code&gt; subfolder content in our project, in order to get this result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/
|-- /docker
|   |-- /dev
|   |   |-- /configureDatabase &lt;span class="c"&gt;# &amp;lt;= New subfolder and files.&lt;/span&gt;
|   |   |   |-- initDatabase.js
|   |   |   |-- postsDataToBePersisted.js
|   |   |   |-- usersDataToBePersisted.js
|   |   |-- .docker.dev.env
|   |-- /test
|   |   |-- /configureDatabase
|   |   |   |-- initDatabase.js
|   |   |-- .docker.test.env
|   |-- docker-compose.yml
|-- /node_modules
|-- /src
|-- package-lock.json
|-- package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;postsDataToBePersisted.js&lt;/code&gt; and &lt;code&gt;usersDataToBePersisted.js&lt;/code&gt; files only contain static data defined into independent constants. That information will be stored in the defined database, into the specified collection.&lt;/p&gt;

&lt;p&gt;The structure for the content included into these files is like that:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;




&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the other hand, the content of &lt;code&gt;initDatabase.js&lt;/code&gt; file is pretty similar to the &lt;code&gt;testing&lt;/code&gt; environment definition but a little bit complex due to we have to manage collections and data. So the final result is this one:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;At this script there are several parts that we need to analyze.&lt;/p&gt;

&lt;p&gt;The header block composed by two &lt;code&gt;load()&lt;/code&gt; function calls which are used in order to import the mocked data constants declarations that we did in the other JavaScript files.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔥 Pay attention to the full data location path is referenced to the inner Docker container file structure, not to our system. 🔥&lt;/p&gt;

&lt;p&gt;ℹ️ If you want to learn more about how MongoDB executes JavaScript files in its console, take a look to the &lt;a href="https://docs.mongodb.com/manual/tutorial/write-scripts-for-the-mongo-shell/#execute-a-javascript-file"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After "importing" the &lt;code&gt;usersToBePersisted&lt;/code&gt; and &lt;code&gt;postsToBePersisted&lt;/code&gt; constants definitions via &lt;code&gt;load()&lt;/code&gt; function, they are globally available into the context of our initialization script.&lt;/p&gt;

&lt;p&gt;The next block to be analyzed is the &lt;code&gt;apiDatabases&lt;/code&gt; constant definition where besides the &lt;code&gt;dbName&lt;/code&gt; and &lt;code&gt;dbUsers&lt;/code&gt; that we covered in the &lt;code&gt;testing&lt;/code&gt; configuration, in this case the &lt;code&gt;dbData&lt;/code&gt; array is a little bit more complex.&lt;/p&gt;

&lt;p&gt;Every object declared into the &lt;code&gt;dbData&lt;/code&gt; array defines the collection name as well as the dataset that must be persisted in that collection.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now we find the &lt;code&gt;collections&lt;/code&gt; constant definition. It's a set of mapped functions (or object lookup) which contains the actions to execute for every collection defined into the &lt;code&gt;apiDatabases.dbData&lt;/code&gt; block.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As we can see, in these functions we are directly invoking native MongoDB instructions.&lt;/p&gt;

&lt;p&gt;The next function is &lt;code&gt;createDatabaseUsers&lt;/code&gt; which has not differences with the defined for the &lt;code&gt;testing&lt;/code&gt; environment.&lt;/p&gt;

&lt;p&gt;Just before ending the script file we can find the &lt;code&gt;populateDatabase&lt;/code&gt; function.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In this function we go through the database collections inserting the assigned data and here is where we invoke the &lt;code&gt;collections&lt;/code&gt; mapped functions object.&lt;/p&gt;

&lt;p&gt;Finally we have the &lt;code&gt;try/catch&lt;/code&gt; block where we run the same actions that we did for the &lt;code&gt;testing&lt;/code&gt; environment but we have included the &lt;code&gt;populateDatabase&lt;/code&gt; function call.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This way is how we can configure the initialization script for our &lt;code&gt;development&lt;/code&gt; environment database.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧩 Docker Compose commands
&lt;/h2&gt;

&lt;p&gt;Once we have defined the composing file as well as the dataset that will initialize our databases, we have to define the commands which will run our containers.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;🔥 Pay attention to the used paths are referenced to our project root. 🔥&lt;/p&gt;

&lt;h2&gt;
  
  
  🌟 Setting the final NodeJS commands
&lt;/h2&gt;

&lt;p&gt;The final step is to define the needed scripts into our &lt;code&gt;package.json&lt;/code&gt; file.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In order to provide a better modularization of scripts, it's strongly recommended to divide the different scripts in atomic ones and then, create new ones which group the more specific ones.&lt;/p&gt;

&lt;p&gt;For instance, in this code we have defined the &lt;code&gt;dev_infra:up&lt;/code&gt;, &lt;code&gt;dev_infra:down&lt;/code&gt;, &lt;code&gt;test:run&lt;/code&gt;, &lt;code&gt;test_infra:up&lt;/code&gt; and &lt;code&gt;test_infra:down&lt;/code&gt; scripts which are atomic because define a single action to do and will be in charge to start and turning off the containers for every environment as well as to run the testing suite.&lt;/p&gt;

&lt;p&gt;In opposite we have the &lt;code&gt;build:dev&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; scripts which are composed due to they include several atomic actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤔 FAQ
&lt;/h2&gt;

&lt;p&gt;❓ &lt;strong&gt;What happen if the testing suite suddenly stops because any test fails?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don't worry about that because it's true that the testing infrastructure will keep running but we have two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To keep it running so the next time we run the testing suite, the &lt;code&gt;docker-compose&lt;/code&gt; command will update the current container.&lt;/li&gt;
&lt;li&gt;To run manually the shutting down script for the testing container.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;❓ &lt;strong&gt;What happen whether instead of a database we need to run a more complex service like an API?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We just need to configure the needed containers/services into the &lt;code&gt;docker-compose.yml&lt;/code&gt; file, paying special attention to the &lt;code&gt;.env&lt;/code&gt; configurations for every environment.&lt;/p&gt;

&lt;p&gt;It doesn't matter what we wrap and/or include in our container/s. The important point here is that we are going to be able to start and turning off them when our project needs it.&lt;/p&gt;

&lt;h2&gt;
  
  
  👋 Final words
&lt;/h2&gt;

&lt;p&gt;With this configuration, we can include infrastructure management to our NodeJS based on project.&lt;/p&gt;

&lt;p&gt;This kind of configuration provides us a decoupling level that will increase our independency during the development period, because we are going to treat the external elements to our code as a black box which we interact.&lt;/p&gt;

&lt;p&gt;Another interesting point for this strategy is that every time we start up the container via &lt;code&gt;docker-compose&lt;/code&gt;, it's totally renewed so we can be sure that our testing suites are going to be run in a completely clean system.&lt;/p&gt;

&lt;p&gt;In addition, we will keep clean our system due to we don't need to install any auxiliar application on it because all of them will be included into the different containers that compose our mocked infrastructure.&lt;/p&gt;

&lt;p&gt;Just a caveat, try to keep the content of the containers up-to-date in order to work with the closest production environment conditions as it's possible.&lt;/p&gt;

&lt;p&gt;I hope this tip is useful for you. If you have any question, feel free to contact me. Here there are my &lt;a href="https://twitter.com/ddialar"&gt;Twitter&lt;/a&gt;, &lt;a href="https://linkedin.com/in/ddialar"&gt;LinkedIn&lt;/a&gt; and &lt;a href="https://github.com/ddialar"&gt;Github&lt;/a&gt; profiles.&lt;/p&gt;

&lt;h2&gt;
  
  
  🙏 Credits and thanks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/jntramosbonilla"&gt;Jonatan Ramos&lt;/a&gt; for providing the clue of &lt;code&gt;COMPOSE_PROJECT_NAME&lt;/code&gt; to create a single &lt;code&gt;docker-compose.yml&lt;/code&gt; file shared between different environments.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>tdd</category>
    </item>
    <item>
      <title>De if/switch a mapped functions (a.k.a. object lookup)</title>
      <dc:creator>Dailos Rafael Díaz Lara</dc:creator>
      <pubDate>Mon, 14 Dec 2020 22:12:23 +0000</pubDate>
      <link>https://dev.to/ddialar/de-if-switch-a-mapped-functions-a-k-a-object-lookup-1pb8</link>
      <guid>https://dev.to/ddialar/de-if-switch-a-mapped-functions-a-k-a-object-lookup-1pb8</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/ddialar/from-if-switch-to-mapped-functions-a-k-a-object-lookup-i3d"&gt;🇬🇧 English version&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Objetivo
&lt;/h2&gt;

&lt;p&gt;Este texto está orientado a proporcionar una alternativa para aquellas situaciones donde nuestro código debe estructurarse para ejecutar una u otra función, dependiendo de un conjunto definido de posibles condiciones.&lt;/p&gt;

&lt;p&gt;En ningún momento es mi intención criticar el uso de &lt;code&gt;if/else&lt;/code&gt; o de &lt;code&gt;switch/case&lt;/code&gt;. Mi único objetivo es proporcionar una propuesta diferente con que mejorar el mantenimiento y la escalabilidad de nuestro código.&lt;/p&gt;

&lt;p&gt;Una vez dicho esto... empecemos!!!&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 Instrucción if/else
&lt;/h2&gt;

&lt;p&gt;Desde que empezamos a aprender a programar, el primer control de flujo de información que aprendemos es el &lt;code&gt;if/else&lt;/code&gt; (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else"&gt;MDN if/else documentation&lt;/a&gt;). De este modo, cuando ya lo hemos aprendido, es realmente fácil utilizarlo.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Incluso cuando la cantidad de posibles opciones se incrementa, podemos encadenar multiples &lt;code&gt;if/else&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Además, cuando tenemos varias opciones que deben tratarse de la misma manera, es decir que comparten la misma lógica de negocio, podemos usar operadores booleanos (el &lt;code&gt;OR&lt;/code&gt; en este caso), para agrupar todas esas opciones bajo el mismo bloque de código.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Todo esto está genial pero cuando los posibles casos superan las dos o tres opciones, el código empieza a parece un poco sucio.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pros (✅) y contras (👎)
&lt;/h4&gt;

&lt;p&gt;✅ Es la manera más fácil de controlar el flujo de información.&lt;br&gt;
✅ Es relativamente fácil de aprender.&lt;br&gt;
✅ discriminar entre dos posibles opciones es realmente cómodo.&lt;/p&gt;

&lt;p&gt;👎 Cuando gestionamos más de tres opciones, el código empieza a parece un poco sucio..&lt;br&gt;
👎 Encadenar múltiples opciones disminuye la legibilidad y el mantenimiento de nuestro código.&lt;br&gt;
👎 Agrupar opciones empleando operadores booleanos puede hacer más complicadas las reglas de comparación en cada situación.&lt;br&gt;
👎 Para una cantidad relativamente grande de casos posibles, es más lento ya que cada condición deber ser comprobada hasta alcanzar aquella que coincida con el valor de referencia proporcionado.&lt;/p&gt;
&lt;h2&gt;
  
  
  🤓 Instrucción switch/case
&lt;/h2&gt;

&lt;p&gt;Cuando queremos mejorar la legibilidad y mantenimiento de nuestro código debido a que tenemos múltiples opciones que gestionar, es cuando aprendemos la alternativa al &lt;code&gt;if/else&lt;/code&gt;, es decir, el &lt;code&gt;switch/case&lt;/code&gt; (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch"&gt;MDN switch/case documentation&lt;/a&gt;).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;De la misma manera que hacíamos con el &lt;code&gt;if/else&lt;/code&gt;, con el &lt;code&gt;switch/case&lt;/code&gt; también podremos agrupar opciones pero en este caso, no necesitamos utilizar ningún operador booleano. Sólo necesitamos mantener unidos los diferentes casos a agrupar.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Como ya sabrás, esto es posible gracias a que la ejecución del &lt;code&gt;switch/case&lt;/code&gt; es un proceso secuencial, donde cada posible caso definido en el conjunto de opciones, es comparado con la referencia proporcionada.&lt;/p&gt;

&lt;p&gt;Si ambos valores coincide, el bloque de código incluido en ese caso se ejecuta y, si no hay una instrucción &lt;code&gt;break&lt;/code&gt; o &lt;code&gt;return&lt;/code&gt; al final de dicho bloque de código, el siguiente caso será comprobado hasta encontrar la próxima coincidencia o hasta llegar al bloque &lt;code&gt;default&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Basándonos en esto, para agrupar múltiples opciones las cuales van a ser gestionadas por el mismo bloque de código, sólo necesitamos definir el caso para el valor deseado, sin ningún tipo de lógica de negocio. De este modo seremos capaces de encadenar múltiples opciones para el mismo resultado.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pros (✅) y contras (👎)
&lt;/h4&gt;

&lt;p&gt;✅ Proporciona una mejor estructura del código que al usar instrucciones &lt;code&gt;if/else&lt;/code&gt;.&lt;br&gt;
✅ Es posible crear agrupamiento de casos de una manera más clara que con instrucciones &lt;code&gt;if/else&lt;/code&gt;.&lt;br&gt;
✅ Es realmente sencillo discriminar entre más de dos opciones.&lt;/p&gt;

&lt;p&gt;👎 Tenemos que estar pendiente de completar todos los bloques de código con una instrucción &lt;code&gt;break&lt;/code&gt; o &lt;code&gt;return&lt;/code&gt;. Si nos olvidamos de hacerlo, nos podemos meter en un buen lío.&lt;br&gt;
👎 Para cantidades relativamente grandes de casos, es lento dado que cada condición debe ser comprobada hasta llegar a aquella que coincide con la referencia que le hemos proporcionado.&lt;/p&gt;
&lt;h2&gt;
  
  
  🔥 Mapped functions
&lt;/h2&gt;

&lt;p&gt;Esta es una estrategia poco conocida (también llamada &lt;code&gt;object lookup&lt;/code&gt;) y está destinada a mejorar determinados aspectos del uso de instrucciones &lt;code&gt;if/else&lt;/code&gt; y &lt;code&gt;switch/case&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La idea es aprovechar el comportamiento de los objetos de JavaScript para usar sus claves como mapa de referencias y acceder directamente a lógica de negocio específica.&lt;/p&gt;

&lt;p&gt;Antes de nada, necesitamos tener definidos los posibles casos que van a ser gestionados.&lt;/p&gt;

&lt;p&gt;Cada caso individual será asociado a una clave del objeto literal.&lt;/p&gt;

&lt;p&gt;Una vez hemos creado nuestro objeto, usaremos el estilo de acceso array para ejecutar el código de cada caso individual.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Pros (✅) y contras (👎)
&lt;/h4&gt;

&lt;p&gt;✅ Proporciona una estructuración del código mejor que la que obtenemos al usar instrucciones &lt;code&gt;if/else&lt;/code&gt; y &lt;code&gt;switch/case&lt;/code&gt;.&lt;br&gt;
✅ No hay agrupamiento de posibles casos dado que cada uno de ellos tiene definida su propia lógica de negocio.&lt;br&gt;
✅ Es extremadamente fácil diferenciar entre múltiples opciones de ejecución.&lt;br&gt;
✅ Puede ser reutilizado en varias partes de nuestra aplicación (via exportación de módulo).&lt;br&gt;
✅ Es más rápido que &lt;code&gt;if/else&lt;/code&gt; y &lt;code&gt;switch/case&lt;/code&gt; dado que accedemos a la condición específica que queremos ejecutar, sin necesitar verificar cada uno de los casos secuencialmente, hasta encontrar el correcto.&lt;/p&gt;

&lt;p&gt;👎 Esta estrategia rara vez aparece en las formaciones más habituales.&lt;br&gt;
👎 Si el objeto no se define en el lugar indicado de la aplicación, puede consumir un poco más de memoria de la necesaria.&lt;/p&gt;
&lt;h2&gt;
  
  
  🤔 FAQ
&lt;/h2&gt;
&lt;h4&gt;
  
  
  ❓ ¿Qué sucede si proporcionamos una opción que no están entre las claves del objeto?
&lt;/h4&gt;

&lt;p&gt;La respuesta corta es que se disparará una excepción ya que no es posible ejecutar una función de &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No obstante, podemos prevenir esto definiendo un caso &lt;code&gt;default&lt;/code&gt;, de la misma manera que hacemos en la instrucción &lt;code&gt;switch/case&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para ser capaces de acceder a este nuevo caso, comprobaremos si la opción proporcionada existe dentro del objeto y si no existe, entonces ejecutaremos la opción &lt;code&gt;default&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para estos casos, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator"&gt;operador condicional (ternario)&lt;/a&gt; será nuestro aliado.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  ❓ ¿Qué puedo o debo devolver en el caso &lt;code&gt;default&lt;/code&gt;?
&lt;/h4&gt;

&lt;p&gt;Esto va a depender del caso de uso que estemos definiendo pero básicamente, vamos a tener tres opciones principales:&lt;/p&gt;

&lt;p&gt;1 - Devolver el mismo valor que hemos proporcionado:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;2 - Devolver &lt;code&gt;null&lt;/code&gt; o &lt;code&gt;undefined&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;En este caso, podemos incluso aprovechar el &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining"&gt;optional chaining&lt;/a&gt; y dejar más limpio nuestro código:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Debemos prestar atención porque in este caso, si no hay coincidencia en las opciones disponibles, vamos a devolver &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;3 - Definir una lógica de negocio específica:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Aquí debemos tener cuidado si nuestro código, como se muestra en el ejemplo, va a disparar un error. Tenemos que gestionar dicho error para evitar un error total que bloquee nuestra aplicación.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Obviamente el código que implementa el error puede ser reemplazado por cualquier otra lógica de negocio que se adecue mejor al comportamiento de nuestra aplicación.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❓ ¿Necesito definir una función anónima para cada caso?
&lt;/h4&gt;

&lt;p&gt;No, en absoluto.&lt;/p&gt;

&lt;p&gt;Si tenemos perfectamente definida la función que debe ser ejecutada para cada caso y además, dicha función recibe únicamente un argumento que coincide con el que estamos proporcionando cuando invocamos al mapa, podemos usar esta sintaxis:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Incluso si queremos devolver &lt;code&gt;undefined&lt;/code&gt; cuando la opción proporcionada no está incluida dentro del mapa, podemos usar esta otra sintaxis extremadamente simplificada (&lt;strong&gt;Advertencia ‼️&lt;/strong&gt;: todas las funciones usadas para crear las claves del mapa, han de estar definidas previamente):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  ❓ ¿Es posible que el nombre de una propiedad entre en conflicto con el de un objeto?
&lt;/h4&gt;

&lt;p&gt;Rotundamente sí.&lt;/p&gt;

&lt;p&gt;Es totalmente posible, pero para evitar esto tenemos que prestar atención a los nombres que estamos usando, de la misma manera que nunca utilizaríamos una palabra reservada del lenguaje como nombre de variable, función u objeto.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❓ ¿Esto podría formar una nueva convención de nombres?
&lt;/h4&gt;

&lt;p&gt;Sí, claro.&lt;/p&gt;

&lt;p&gt;Pero para este tipo de situaciones tenemos el apoyo y las guías proporcionadas por el Clean Code.&lt;/p&gt;

&lt;p&gt;Cada código que creemos requerirá una convención de nombres. En algunos casos cuando seamos la única persona que ha iniciado el proyecto, podremos definir dicha convención (pet-projects principalmente). En otras situaciones, será el equipo de desarrollo el responsable de cualquier acuerdo alcanzado a tal efecto.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❓ ¿Requerirá un uso de memoria adicional mientras que el &lt;code&gt;if/else&lt;/code&gt; y el &lt;code&gt;switch/case&lt;/code&gt; no lo hacen?
&lt;/h4&gt;

&lt;p&gt;Sí, lo hará.&lt;/p&gt;

&lt;p&gt;Sin embargo, basándonos en los tipos de dispositivos que ejecutan nuestras aplicaciones JavaScript hoy en día así como en sus características, el incremento de memoria es prácticamente insignificante en comparación con el resto de la aplicación.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❓ ¿Sería esta opción más lenta que el &lt;code&gt;if/else&lt;/code&gt; o el &lt;code&gt;switch/case&lt;/code&gt; dependiendo del motor de JavaScript que se use?
&lt;/h4&gt;

&lt;p&gt;Esto va a depender de cómo definamos el objeto en sí.&lt;/p&gt;

&lt;p&gt;Por ejemplo, si definimos el objeto de mapeado de funciones dentro de una función, la cual va a ser invocada cada vez que queramos hacer uso del mapa, obviamente esta solución va a ser más lenta que las otras opciones, porque el objeto debe ser creado cada vez.&lt;/p&gt;

&lt;p&gt;En este código podemos ver la situación donde la función &lt;code&gt;mappedFunction&lt;/code&gt; tiene definido el objeto dentro de ella:&lt;/p&gt;

&lt;p&gt;Codepen 👉 &lt;a href="https://codepen.io/ddialar/pen/JjRWNBJ"&gt;Speed race Switch 🐇 vs Object Lookup 🐢 v1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aquí no importa qué motor de JavaScript estemos usando para ejecutar el código (&lt;a href="https://en.wikipedia.org/wiki/WebKit#JavaScriptCore"&gt;AppleWebKit&lt;/a&gt; para Safari, &lt;a href="https://en.wikipedia.org/wiki/SpiderMonkey"&gt;SpiderMonkey&lt;/a&gt; para Firefox o &lt;a href="https://en.wikipedia.org/wiki/V8_(JavaScript_engine)"&gt;V8&lt;/a&gt; para Google Chrome y/o NodeJS), porque el mapeado de funciones será siempre más lento (incluso si operamos los primeros casos), debido a que el objeto se está creando ad-hoc en cada ejecución de la función.&lt;/p&gt;

&lt;p&gt;Sin embargo, si definimos el mapeado de funciones de manera global (al módulo o a la aplicación), el objeto se cargará cuando el módulo o la aplicación lo usen. De este modo, el acceso a las funciones mapeadas será siempre más rápido que las otras dos opciones.&lt;/p&gt;

&lt;p&gt;En este código hemos definido el mapa fuera de la función  &lt;code&gt;mappedFunction&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;Codepen 👉 &lt;a href="https://codepen.io/ddialar/pen/ZEpeKqW"&gt;Speed race Switch 🐢 vs Object Lookup 🐇 v2&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  ❓ ¿Qué pasa con el recolector de basura?
&lt;/h4&gt;

&lt;p&gt;Hoy en día el recolector de basura es algo a lo que quienes desarrollamos con JavaScript no le prestamos mucha atención, debido a que está ampliamente cubierto por las especificaciones del lenguaje así que, una vez el mapa de funciones ya no está en uso en el proceso de ejecución actual, el objeto será gestionado por el recolector de basura automáticamente.&lt;/p&gt;

&lt;p&gt;Para más información respecto a este tema, recomiendo echar un vistazo a esta documentación de la MDN relativa a la &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management"&gt;gestión de la memoria&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Recursos adicionales:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://javascript.info/garbage-collection"&gt;Garbage collection por javascript.info (2020)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  👋 Conclusiones finales
&lt;/h2&gt;

&lt;p&gt;Como ya he dicho al principio de este post, no es mi intención criticar de ningún modo el uso de &lt;code&gt;if/else&lt;/code&gt; o &lt;code&gt;switch/case&lt;/code&gt;, sino que únicamente pretendo proporcionar otra manera de realizar dichas operaciones.&lt;/p&gt;

&lt;p&gt;Resumiendo, cuando tengamos que discriminar entre dos simples opciones, es obvio que la alternativa más sencilla es usar &lt;code&gt;if/else&lt;/code&gt;. Además recomiendo encarecidamente que intentes usar el operador ternario allí donde sea posible.&lt;/p&gt;

&lt;p&gt;Para aquellos casos donde tengamos que diferenciar entre tres o más opciones, sinceramente recomiendo el uso de funciones mapeadas para proporcionar una mejor legibilidad, mantenimiento y reutilización de nuestro código.&lt;/p&gt;

&lt;p&gt;Espero que este contenido te sea útil. Si tienes cualquier pregunta, siéntete totalmente libre de contactar conmigo. Aquí están mis perfiles de &lt;a href="https://twitter.com/ddialar"&gt;Twitter&lt;/a&gt;, &lt;a href="https://linkedin.com/io/ddialar"&gt;Linkedin&lt;/a&gt; y &lt;a href="https://github.com/ddialar"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🙏 Reconocimientos y agradecimientos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://twitter.com/LissetteIbnz"&gt;Lissette Luis&lt;/a&gt;, &lt;a href="https://twitter.com/AdrianFerrera91"&gt;Adrián Ferrera&lt;/a&gt; e &lt;a href="https://twitter.com/ivanbtrujillo"&gt;Iván Bacallado&lt;/a&gt; por formar parte de un equipo fantástico donde se comparte el conocimiento y especialmente, por sus propuestas sobre el tema abordado en este texto.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://twitter.com/SimonHoiberg"&gt;Simon Høiberg&lt;/a&gt; por iniciar este interesantísimo &lt;a href="https://twitter.com/SimonHoiberg/status/1337688868527726593?s=20"&gt;hilo de Twitter&lt;/a&gt; que ha originado la creación de este post.&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://twitter.com/knnyldz90"&gt;Kenan Yildiz&lt;/a&gt; y &lt;a href="https://twitter.com/tluzat"&gt;Thomas Luzat&lt;/a&gt; por compartir una opción más simplificada de la implementación del mapa de funciones.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>From if/switch to mapped functions (a.k.a. object lookup)</title>
      <dc:creator>Dailos Rafael Díaz Lara</dc:creator>
      <pubDate>Mon, 14 Dec 2020 13:53:43 +0000</pubDate>
      <link>https://dev.to/ddialar/from-if-switch-to-mapped-functions-a-k-a-object-lookup-i3d</link>
      <guid>https://dev.to/ddialar/from-if-switch-to-mapped-functions-a-k-a-object-lookup-i3d</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/ddialar/de-if-switch-a-mapped-functions-a-k-a-object-lookup-1pb8"&gt;🇪🇸 Versión en español&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 Context
&lt;/h2&gt;

&lt;p&gt;This text is aimed to provide an alternative to these situations where our code must be structured in order to run one or another function, depending on a bunch of possible conditions.&lt;/p&gt;

&lt;p&gt;I don't want to criticize the use of &lt;code&gt;if/else&lt;/code&gt; or &lt;code&gt;switch/case&lt;/code&gt; sentences far from it. My only goal is to provide a different approach which can improve the maintenance and scalability of our code.&lt;/p&gt;

&lt;p&gt;So... engage!!!&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 if/else sentences
&lt;/h2&gt;

&lt;p&gt;Since all of us start learning to code, the first flow control sentence that we learn is the &lt;code&gt;if/else&lt;/code&gt; one (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else"&gt;MDN if/else documentation&lt;/a&gt;). So once we have got it, it's really easy to use.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Even when the amount of possible options increases, we can chain multiple &lt;code&gt;if/else&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In addition, when we have several options which must be treated in the same way (it means with the same business logic), we can use boolean operators (the &lt;code&gt;OR&lt;/code&gt; one in this case), in order to group all these options under the same block.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That's fine but when the possible cases are upper than two or three options, the code starts to look like a little bit messy.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pros (✅) and cons (👎)
&lt;/h4&gt;

&lt;p&gt;✅ It's the easier way to control data flow.&lt;br&gt;
✅ It's relatively easy to learn.&lt;br&gt;
✅ It's really comfortable to discriminate between two options.&lt;/p&gt;

&lt;p&gt;👎 For handling more than three options, the code starts to look like a little bit messy.&lt;br&gt;
👎 To chain multiple options reduce the readability and maintenance of our code.&lt;br&gt;
👎 To group options using boolean operators could turn on complex assertion rules for every situation.&lt;br&gt;
👎 For a relatively huge amount of cases, it's slow due to every condition must be checked until getting the only one that matches.&lt;/p&gt;
&lt;h2&gt;
  
  
  🤓 switch/case sentence
&lt;/h2&gt;

&lt;p&gt;When we want to improve the readability and maintenance of our code due to we have multiple options to be handled, is when we learn the &lt;code&gt;if/else&lt;/code&gt; alternative, it means, the &lt;code&gt;switch/case&lt;/code&gt; sentence (&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch"&gt;MDN switch/case documentation&lt;/a&gt;).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In the same way we did with the &lt;code&gt;if/else&lt;/code&gt; sentence, with &lt;code&gt;switch/case&lt;/code&gt; we can also group options but now, we don't need to use any boolean operator. We just need to keep joined the different cases.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you already know, that's possible due to the &lt;code&gt;switch/case&lt;/code&gt; execution is a sequential process, where every possible case defined in the block of options, is compared with the provided value.&lt;/p&gt;

&lt;p&gt;If both values match, the code block included into that case is executed and, if there is not a &lt;code&gt;break&lt;/code&gt; or &lt;code&gt;return&lt;/code&gt; instruction at the end of the code block, the next case will be checked until the next matching or the &lt;code&gt;default&lt;/code&gt; option is reached.&lt;/p&gt;

&lt;p&gt;Based on that, in order to group several options which are going to be handled by the same code block, we just need to define the &lt;code&gt;case&lt;/code&gt; for the wished value, with no business logic. This way we're able to chain multiple options for the same result.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pros (✅) and cons (👎)
&lt;/h4&gt;

&lt;p&gt;✅ It provides a better code structuring than &lt;code&gt;if/else&lt;/code&gt; sentences.&lt;br&gt;
✅ It's possible to create clearest cases grouping than &lt;code&gt;if/else&lt;/code&gt; sentences.&lt;br&gt;
✅ It's really easy to discriminate between more than two options.&lt;/p&gt;

&lt;p&gt;👎 You have to be aware about completing all your code blocks with a &lt;code&gt;break&lt;/code&gt; or a &lt;code&gt;return&lt;/code&gt; instruction. If you forget it, you'll have a real nightmare.&lt;br&gt;
👎 For a relatively huge amount of cases, it's slow due to every condition must be checked until getting the only one that matches.&lt;/p&gt;
&lt;h2&gt;
  
  
  🔥 Mapped functions
&lt;/h2&gt;

&lt;p&gt;This is a little known strategy (a.k.a. &lt;code&gt;object lookup&lt;/code&gt;) aimed to improve several aspects of &lt;code&gt;if/else&lt;/code&gt; and &lt;code&gt;switch/case&lt;/code&gt; sentences.&lt;/p&gt;

&lt;p&gt;The idea is to take advantage of a JavaScript object behavior in order to use its keys as map references to access to specific business logic.&lt;/p&gt;

&lt;p&gt;First at all, we need to have defined the possible cases which must be handled.&lt;/p&gt;

&lt;p&gt;Every single case will be bound to a key in the literal object.&lt;/p&gt;

&lt;p&gt;Once we have created our object, we'll use array-access style to run the code for every single case.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  Pros (✅) and cons (👎)
&lt;/h4&gt;

&lt;p&gt;✅ It provides a better code structuring than &lt;code&gt;if/else&lt;/code&gt; and &lt;code&gt;switch/case&lt;/code&gt; sentences.&lt;br&gt;
✅ There is no cases grouping due to every single case has its own business logic.&lt;br&gt;
✅ It's extremely easy to differentiate between multiple options.&lt;br&gt;
✅ Can be reused in several parts of our application (via module export).&lt;br&gt;
✅ It's faster than &lt;code&gt;if/else&lt;/code&gt; and &lt;code&gt;switch/case&lt;/code&gt; due to we access to the specific condition without need to check every defined case sequentially until the correct one is located.&lt;/p&gt;

&lt;p&gt;👎 This strategy rarely appears in common trainings.&lt;br&gt;
👎 If the object is not defined in the right place, it can consume a little bit more memory that it really needs.&lt;/p&gt;
&lt;h2&gt;
  
  
  🤔 FAQ
&lt;/h2&gt;
&lt;h4&gt;
  
  
  ❓ What happen if the provided option is not defined as object key?
&lt;/h4&gt;

&lt;p&gt;The short answer is that an exception will be throw due to it's not possible to run a function from &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, we can prevent it defining a &lt;code&gt;default&lt;/code&gt; case, in the same way we do in &lt;code&gt;switch/case&lt;/code&gt; sentences.&lt;/p&gt;

&lt;p&gt;In order to be able to access this new case, we will check if the provided one already exists into the object and if it doesn't, we run the &lt;code&gt;default&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;For these cases, the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator"&gt;conditional (ternary) operator&lt;/a&gt; will be our allied.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  ❓ What can/must I return in the &lt;code&gt;default&lt;/code&gt; case?
&lt;/h4&gt;

&lt;p&gt;It'll depend on the use case we are defining but basically, we have three main options:&lt;/p&gt;

&lt;p&gt;1 - To return the same value that you have provided:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;2 - To return &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In this case, we can even take advantage of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining"&gt;optional chaining&lt;/a&gt; and clean up the code this way:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We have to pay attention because in this last case, if there are no matching options, we are going to be returning &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;3 - To define a specific business logic:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;We must be careful if our code, like in this example, is going to throw an error. We need to handle it in order to avoid a full blocking error.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Obviously the code that implements the error can be replaced for any other business logic which suites better with our application behavior.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❓ Do I need to define an anonymous function for every case?
&lt;/h4&gt;

&lt;p&gt;No, you don't.&lt;/p&gt;

&lt;p&gt;If we have perfectly defined the function that must be run for every case and in addition, that function receives only a single argument which matches with the provided one when you invoke the map, we can use this syntax:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Even if we want to return &lt;code&gt;undefined&lt;/code&gt; when the provided option is not included into the map, we can use this extremely simplified syntax (&lt;strong&gt;Caveat ‼️&lt;/strong&gt;: the whole functions used in order to create the mapped object keys must be defined previously):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h4&gt;
  
  
  ❓ It could be possible that property name clashes with an object one?
&lt;/h4&gt;

&lt;p&gt;Absolutely yes.&lt;/p&gt;

&lt;p&gt;It's possible at all, but in order to avoid that we have to pay attention what names are we using, in the same way we never use a language reserved word as variable, function or object name.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❓ It could force a naming convention?
&lt;/h4&gt;

&lt;p&gt;Yes, it could.&lt;/p&gt;

&lt;p&gt;But for these situation we have the support and guidances of Clean Code.&lt;/p&gt;

&lt;p&gt;Every code we create requires naming convention. Some cases when we are the only person who has started the project, we can define that convention (pet-projects mainly). In other situations, the development team will be the responsible of any agreement about that.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❓ Is it going to require additional memory meanwhile &lt;code&gt;if/else&lt;/code&gt; and &lt;code&gt;switch/case&lt;/code&gt; does not do it?
&lt;/h4&gt;

&lt;p&gt;Yes, it will.&lt;/p&gt;

&lt;p&gt;However, based on the kind of devices that run our JavaScript applications nowadays and its characteristics, the increment of used memory is insignificant compared with the rest of the application.&lt;/p&gt;

&lt;h4&gt;
  
  
  ❓ Should it be slower that &lt;code&gt;if/else&lt;/code&gt; or &lt;code&gt;switch/case&lt;/code&gt; depending on the JavaScript engine?
&lt;/h4&gt;

&lt;p&gt;It depends on where we define the object.&lt;/p&gt;

&lt;p&gt;For instance, if we define the mapped functions object into a function which is going to be called every time we want to use the map, obviously this solution is going to be slower that the other options because the object must be created every time.&lt;/p&gt;

&lt;p&gt;In this code we can see that situation where the &lt;code&gt;mappedFunction&lt;/code&gt; has defined the object lookup inside:&lt;/p&gt;

&lt;p&gt;Codepen 👉 &lt;a href="https://codepen.io/ddialar/pen/JjRWNBJ"&gt;Speed race Switch 🐇 vs Object Lookup 🐢 v1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It doesn't matter which JavaScript engine you use to run this code (&lt;a href="https://en.wikipedia.org/wiki/WebKit#JavaScriptCore"&gt;AppleWebKit&lt;/a&gt; for Safari, &lt;a href="https://en.wikipedia.org/wiki/SpiderMonkey"&gt;SpiderMonkey&lt;/a&gt; for Firefox or &lt;a href="https://en.wikipedia.org/wiki/V8_(JavaScript_engine)"&gt;V8&lt;/a&gt; for Google Chrome and/or NodeJS), because the mapped function will be always slower (even with the first cases) due to the object is created ad-hoc for every function run.&lt;/p&gt;

&lt;p&gt;Nevertheless, if we define the mapped functions globally (to the module or to the application), the object will be loaded just once when the module or the application is used so, this way, the mapped function access is always faster than the other two options.&lt;/p&gt;

&lt;p&gt;In this another code we have defined the object lookup outside the &lt;code&gt;mappedFunction&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;Codepen 👉 &lt;a href="https://codepen.io/ddialar/pen/ZEpeKqW"&gt;Speed race Switch 🐢 vs Object Lookup 🐇 v2&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  ❓ What about the garbage collector?
&lt;/h4&gt;

&lt;p&gt;Nowadays the garbage collector is something that the JavaScript developers don't pay too much attention due to it's widely covered by the language specifications so, once the mapped functions object is not used any more by the current runtime, it will be managed by the garbage collector automatically.&lt;/p&gt;

&lt;p&gt;For further information about that, I recommend you to take a look to this documentation of the MDN about &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management"&gt;memory management&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Additional resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://javascript.info/garbage-collection"&gt;Garbage collection by javascript.info (2020)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  👋 Final words
&lt;/h2&gt;

&lt;p&gt;As I said at the beginning of this post, it's not my intention to criticize the use of &lt;code&gt;if/else&lt;/code&gt; or &lt;code&gt;switch/case&lt;/code&gt;, but I only want to provide another way to do these operations.&lt;/p&gt;

&lt;p&gt;Summarizing, when we've to discriminate between two single options, it's obvious that the easier alternative is to use &lt;code&gt;if/else&lt;/code&gt; sentence. Moreover I strongly recommend you to try to use the ternary operator when it's possible.&lt;/p&gt;

&lt;p&gt;For cases where you have to differentiate between three or more options, I sincerely recommend you to use mapped functions in order to provide a better readability, maintenance and code reuse.&lt;/p&gt;

&lt;p&gt;I hope this tip is useful for you. If you have any question, feel free to contact me. Here there are my &lt;a href="https://twitter.com/ddialar"&gt;Twitter&lt;/a&gt;, &lt;a href="https://linkedin.com/io/ddialar"&gt;Linkedin&lt;/a&gt; and &lt;a href="https://github.com/ddialar"&gt;Github&lt;/a&gt; profiles.&lt;/p&gt;

&lt;h2&gt;
  
  
  🙏 Credits and thanks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/LissetteIbnz"&gt;Lissette Luis&lt;/a&gt;, &lt;a href="https://twitter.com/AdrianFerrera91"&gt;Adrián Ferrera&lt;/a&gt; and &lt;a href="https://twitter.com/ivanbtrujillo"&gt;Iván Bacallado&lt;/a&gt; for being part of an awesome knowledge sharing team and specially, for their proposals about the subject covered on this post.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/SimonHoiberg"&gt;Simon Høiberg&lt;/a&gt; for starting this interesting &lt;a href="https://twitter.com/SimonHoiberg/status/1337688868527726593?s=20"&gt;Twitter thread&lt;/a&gt; that originated the creation of this post.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/knnyldz90"&gt;Kenan Yildiz&lt;/a&gt; and &lt;a href="https://twitter.com/tluzat"&gt;Thomas Luzat&lt;/a&gt; for sharing a shorter way to implement the object lookup.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Jest with global Dotenv configuration</title>
      <dc:creator>Dailos Rafael Díaz Lara</dc:creator>
      <pubDate>Sat, 01 Aug 2020 18:44:34 +0000</pubDate>
      <link>https://dev.to/ddialar/jest-with-global-dotenv-configuration-cgo</link>
      <guid>https://dev.to/ddialar/jest-with-global-dotenv-configuration-cgo</guid>
      <description>&lt;h2&gt;
  
  
  🎯 Target
&lt;/h2&gt;

&lt;p&gt;I want to have several &lt;code&gt;.env&lt;/code&gt; files in order to define different conditions depending on the environment where my code is running. Based on that, in my testing process I want to load a global configuration once for the whole testing suites.&lt;/p&gt;

&lt;h2&gt;
  
  
  😅 Overview
&lt;/h2&gt;

&lt;p&gt;There are some options to load environment variables in my tests, using Dotenv.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;node -r dotenv/config node_modules/.bin/jest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That is one of the most usual approaches but I don't like it because this way, Dotenv literally needs a &lt;code&gt;.env&lt;/code&gt; file defined at the root of the project so I cannot set a custom configuration file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;require(dotenv).config({ path: 'path/to/env_file' });&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This option requires to type this command in every testing file where I'm going to use environment variables. It could be a solution but I don't like it at all because I have to pay attention to the relative path for the environment file location in every testing file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://jestjs.io/docs/en/configuration#setupfiles-array"&gt;&lt;code&gt;setupFiles&lt;/code&gt;&lt;/a&gt; Jest configuration property.&lt;/p&gt;

&lt;p&gt;That is fine but as the official documentation suggests, the environment is processed once per testing file. This conditions will dealy a little my tests execution and in addition, I don't want it. I want a global configuration at the very begining of the testing process.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  😎 My best matching
&lt;/h2&gt;

&lt;p&gt;After diving a little in the Jest documentation, I found this configuration property: &lt;a href="https://jestjs.io/docs/en/configuration#globalsetup-string"&gt;&lt;code&gt;globalSetup&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In order to use this property, I created the &lt;a href="https://github.com/ddialar/testing.jest.global.dotenv/dotenv/dotenv-test.js"&gt;&lt;code&gt;dotenv-test.js&lt;/code&gt;&lt;/a&gt; file into &lt;code&gt;dotenv&lt;/code&gt; folder (located at the root of the project).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// dotenv-test.js file content.&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dotenv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;dotenv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../env/.env.test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Following the property documentation guidelines, this file must export an asynchronous function that will be executed before the whole testing files.&lt;/p&gt;

&lt;p&gt;When the testing framework runs at the first time, this file is executed, loading the selected environment variables and setting them globally, for the whole testing files and just once. That's all.&lt;/p&gt;

&lt;p&gt;Finally, I have just to introduce this property into the Jest configuration file (&lt;a href="https://github.com/ddialar/testing.jest.global.dotenv/jest.config.json"&gt;&lt;code&gt;jest.config.json&lt;/code&gt;&lt;/a&gt;) and provide the location of the Dotenv file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"globalSetup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;rootDir&amp;gt;/dotenv/dotenv-test.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  👋 Final words
&lt;/h2&gt;

&lt;p&gt;I hope this tip is useful for you. If you have any question, feel free to contact me. Here there are my &lt;a href="https://twitter.com/ddialar"&gt;Twitter&lt;/a&gt;, &lt;a href="https://linkedin.com/io/ddialar"&gt;Linkedin&lt;/a&gt; and &lt;a href="https://github.com/ddialar"&gt;Github&lt;/a&gt; profiles.&lt;/p&gt;

&lt;h2&gt;
  
  
  💾 Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Example code repository &lt;a href="https://github.com/ddialar/testing.jest.global.dotenv"&gt;https://github.com/ddialar/testing.jest.global.dotenv&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Jest configuration docs &lt;a href="https://jestjs.io/docs/en/configuration.html"&gt;https://jestjs.io/docs/en/configuration.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tdd</category>
      <category>typescript</category>
      <category>webpack</category>
    </item>
  </channel>
</rss>
