<?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: Axel Espinosa</title>
    <description>The latest articles on DEV Community by Axel Espinosa (@fromchiapasdev).</description>
    <link>https://dev.to/fromchiapasdev</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%2F186583%2F9cef57b1-206b-4316-9880-0fe5907f987f.jpeg</url>
      <title>DEV Community: Axel Espinosa</title>
      <link>https://dev.to/fromchiapasdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fromchiapasdev"/>
    <language>en</language>
    <item>
      <title>Two Pointers en entrevistas técnicas: 3 problemas resueltos</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Wed, 22 Apr 2026 20:31:27 +0000</pubDate>
      <link>https://dev.to/aws/two-pointers-en-entrevistas-tecnicas-3-problemas-resueltos-324n</link>
      <guid>https://dev.to/aws/two-pointers-en-entrevistas-tecnicas-3-problemas-resueltos-324n</guid>
      <description>&lt;p&gt;Si estás preparándote para entrevistas técnicas, tarde o temprano vas a encontrarte con problemas de arrays y strings. Y varios se resuelven con una misma familia de técnicas: two pointers.&lt;/p&gt;

&lt;p&gt;En los artículos anteriores vimos &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;cómo funcionan los arrays&lt;/a&gt; y &lt;a href="https://dev.to/aws/strings-en-programacion-mas-que-un-simple-array-de-caracteres-1knd"&gt;los strings&lt;/a&gt; por debajo: memoria contigua, acceso por índice, operaciones y sus costos. Hoy toca usar todo eso para resolver problemas reales.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lo que vas a encontrar en este artículo:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Qué son las entrevistas técnicas y por qué te piden resolver problemas&lt;/li&gt;
&lt;li&gt;Qué es two pointers y qué técnicas incluye&lt;/li&gt;
&lt;li&gt;Cómo identificar cuál técnica usar&lt;/li&gt;
&lt;li&gt;Un problema resuelto paso a paso por cada técnica&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Qué son los problemas de entrevistas técnicas?
&lt;/h2&gt;

&lt;p&gt;Son ejercicios de programación que te ponen en entrevistas para puestos de desarrollo de software. Ojo, las entrevistas técnicas existen para muchos roles (arquitectura, DevOps, SRE, developer) y no todas se ven igual. Este artículo se enfoca en las entrevistas para roles de developer.&lt;/p&gt;

&lt;p&gt;El objetivo no es que te sepas la respuesta de memoria. Lo que evalúan es cómo piensas: cómo descompones un problema, qué estructura de datos eliges y si tu solución es eficiente.&lt;/p&gt;

&lt;p&gt;Y aquí viene lo interesante: existen técnicas que se crearon específicamente para resolver estos problemas de forma óptima. No es magia, es práctica y reconocimiento de patrones.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es Two Pointers?
&lt;/h2&gt;

&lt;p&gt;Two pointers es un paradigma general para resolver problemas con arrays y strings. La idea es simple: usas dos variables (los "punteros") que recorren la estructura de datos de formas específicas.&lt;/p&gt;

&lt;p&gt;Ojo, cuando digo "punteros" no me refiero a punteros de memoria como en C. Aquí son simplemente variables que guardan índices para acceder a posiciones del array o string.&lt;/p&gt;

&lt;p&gt;¿Por qué funciona? Porque con dos punteros moviéndose de forma inteligente, puedes evitar soluciones de fuerza bruta O(n²) y resolverlo en O(n). Eso es exactamente lo que buscan en una entrevista.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué técnicas incluye?
&lt;/h3&gt;

&lt;p&gt;Two pointers incluye tres variantes principales:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast and slow pointers&lt;/strong&gt; (lento y rápido): un puntero explora y otro se queda marcando una posición.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Opposite direction pointers&lt;/strong&gt; (punteros convergentes): empiezan en los extremos y se acercan al centro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel pointers&lt;/strong&gt; (punteros paralelos): cada puntero recorre un array diferente al mismo tiempo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lo que todas tienen en común: usan al menos 2 variables para recorrer un arreglo o string, y nos ayudan a pasar de O(n²) a O(n).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Vamos a usar los nombres en inglés porque así los encuentras en la mayoría de recursos, LeetCode y entrevistas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ¿Cómo saber cuál técnica usar?
&lt;/h3&gt;

&lt;p&gt;Antes de entrar a los problemas, una guía rápida. Si en el enunciado ves algo de esto, probablemente necesitas two pointers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Te dan uno o dos arreglos/strings.&lt;/li&gt;
&lt;li&gt;Te piden espacio O(1) o modificar el array en su lugar.&lt;/li&gt;
&lt;li&gt;La solución obvia sería O(n²) pero necesitas algo mejor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ahora, ¿cuál variante? Aquí va un resumen:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Técnica&lt;/th&gt;
&lt;th&gt;Úsala cuando...&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fast and slow&lt;/td&gt;
&lt;td&gt;Necesitas comparar o modificar elementos dentro del mismo array&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Opposite direction&lt;/td&gt;
&lt;td&gt;Necesitas verificar propiedades simétricas, encontrar pares, o trabajar desde los extremos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parallel pointers&lt;/td&gt;
&lt;td&gt;Tienes dos arrays y necesitas compararlos o fusionarlos&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sé que puede parecer mucho, pero conforme resolvamos los problemas vas a ver que es más intuitivo de lo que parece. Vamos a eso.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opposite direction: Verificar un palíndromo
&lt;/h2&gt;

&lt;p&gt;Empecemos con opposite direction porque es la más visual.&lt;/p&gt;

&lt;p&gt;Tomemos el problema &lt;a href="https://leetcode.com/problems/valid-palindrome/description/" rel="noopener noreferrer"&gt;"Valid Palindrome" de LeetCode&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problema:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Una frase es un palíndromo si, tras convertir todas las letras a minúsculas y eliminar los caracteres no alfanuméricos, se lee igual de izquierda a derecha que de derecha a izquierda.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dada una cadena &lt;code&gt;s&lt;/code&gt;, devuelve &lt;code&gt;true&lt;/code&gt; si es un palíndromo, o &lt;code&gt;false&lt;/code&gt; en caso contrario.&lt;/p&gt;

&lt;p&gt;
  Ejemplos
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input:  s = "A man, a plan, a canal: Panama"
Output: true
// Porque "amanaplanacanalpanama" se lee igual en ambas direcciones

Input:  s = "race a car"
Output: false
// Porque "raceacar" no es palíndromo

Input:  s = " "
Output: true
// Un string vacío se lee igual al derecho y al revés
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo lo pensamos?
&lt;/h3&gt;

&lt;p&gt;La solución de fuerza bruta sería limpiar el string, invertirlo y comparar. Funciona, pero crea strings nuevos en memoria (recuerda que los strings son inmutables, así que cada operación crea uno nuevo).&lt;/p&gt;

&lt;p&gt;Con opposite direction pointers hacemos algo más elegante: ponemos un puntero al inicio y otro al final. Los vamos acercando al centro comparando los caracteres. Si en algún momento no coinciden, no es palíndromo. Si los punteros se cruzan sin encontrar diferencias, sí lo es.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solución paso a paso
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {string} s
 * @return {boolean}
 */&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;isPalindrome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isAlphanumeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isAlphanumeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="o"&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// función auxiliar: ¿es letra o número?&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isAlphanumeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&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;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="c1"&gt;// 0-9&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="c1"&gt;// A-Z&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;97&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;122&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// a-z&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;Vamos línea por línea:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;l&lt;/code&gt; arranca en &lt;code&gt;0&lt;/code&gt; (inicio del string) y &lt;code&gt;r&lt;/code&gt; en &lt;code&gt;s.length - 1&lt;/code&gt; (final). Son nuestros dos punteros que se van a acercar al centro.&lt;/li&gt;
&lt;li&gt;El &lt;code&gt;while (l &amp;lt; r)&lt;/code&gt; se ejecuta mientras los punteros no se hayan cruzado.&lt;/li&gt;
&lt;li&gt;Dentro del loop hay cuatro casos:

&lt;ul&gt;
&lt;li&gt;Si &lt;code&gt;s[l]&lt;/code&gt; no es alfanumérico (un espacio, coma, dos puntos...), lo saltamos moviendo &lt;code&gt;l&lt;/code&gt; a la derecha.&lt;/li&gt;
&lt;li&gt;Si &lt;code&gt;s[r]&lt;/code&gt; no es alfanumérico, lo saltamos moviendo &lt;code&gt;r&lt;/code&gt; a la izquierda.&lt;/li&gt;
&lt;li&gt;Si ambos son alfanuméricos pero no coinciden (comparando en minúsculas), no es palíndromo. Retornamos &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si coinciden, avanzamos ambos punteros hacia el centro (&lt;code&gt;l++&lt;/code&gt;, &lt;code&gt;r--&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Si el loop termina sin retornar &lt;code&gt;false&lt;/code&gt;, los punteros se cruzaron sin encontrar diferencias. Es palíndromo, retornamos &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;La función auxiliar &lt;code&gt;isAlphanumeric&lt;/code&gt; &lt;a href="https://dev.to/fromchiapasdev/encodings-por-que-importan-mas-de-lo-que-crees-41a5"&gt;revisa el código ASCII del carácter&lt;/a&gt;: &lt;code&gt;48-57&lt;/code&gt; son dígitos, &lt;code&gt;65-90&lt;/code&gt; letras mayúsculas, &lt;code&gt;97-122&lt;/code&gt; letras minúsculas. Todo lo demás (espacios, puntuación, etc.) retorna &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Complejidad: O(n) en tiempo, O(1) en espacio. Un solo recorrido del string, sin crear copias ni estructuras extra.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Veamos cómo se ve con &lt;code&gt;s = "A man, a plan, a canal: Panama"&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8e5tzx2idnwpgti20buy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8e5tzx2idnwpgti20buy.png" alt="Paso a paso de opposite direction pointers para validar un palíndromo" width="800" height="957"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fast and slow: Remove Duplicates
&lt;/h2&gt;

&lt;p&gt;Ahora veamos fast and slow con el clásico &lt;a href="https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/" rel="noopener noreferrer"&gt;"Remove Duplicates from Sorted Array" de LeetCode&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problema:&lt;/strong&gt;&lt;br&gt;
Te dan una lista de números &lt;code&gt;nums&lt;/code&gt; ya ordenada de menor a mayor, pero con algunos repetidos. Tienes que dejar cada número una sola vez, moviendo los únicos al inicio de la misma lista (sin crear otra lista nueva).&lt;br&gt;
Por ejemplo, si te dan &lt;code&gt;[1, 1, 2, 3, 3]&lt;/code&gt;, la lista debe quedar así: &lt;code&gt;[1, 2, 3, ?, ?]&lt;/code&gt;. Los primeros tres espacios tienen los números únicos en orden, y los últimos dos espacios no importan (pueden quedar con cualquier valor, por eso los marcamos con &lt;code&gt;?&lt;/code&gt;).&lt;br&gt;
Además, tu función debe devolver cuántos números únicos quedaron al inicio. En el ejemplo anterior, devolverías &lt;code&gt;3&lt;/code&gt; porque hay tres números únicos (&lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;). A ese número lo llaman &lt;code&gt;k&lt;/code&gt; en el enunciado.&lt;/p&gt;

&lt;p&gt;
  Ejemplos
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ejemplo 1

Entrada: nums = [1,1,2]
Salida: 2, nums = [1,2,_]

Explicación: Tu función debe devolver k = 2, y los primeros dos elementos de nums deben ser 1 y 2 respectivamente. No importa qué quede después de los primeros k espacios (por eso aparecen como guiones bajos).

Ejemplo 2

Entrada: nums = [0,0,1,1,1,2,2,3,3,4]
Salida: 5, nums = [0,1,2,3,4,_,_,_,_,_]

Explicación: Tu función debe devolver k = 5, y los primeros cinco elementos de nums deben ser 0, 1, 2, 3 y 4 respectivamente. No importa qué quede después de los primeros k espacios (por eso aparecen como guiones bajos).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo lo pensamos?
&lt;/h3&gt;

&lt;p&gt;La fuerza bruta sería crear un nuevo array y copiar solo los valores que no se repiten. Pero el problema dice explícitamente que lo hagas "in-place", o sea, modificando el mismo array sin crear otro. Ahí es donde entra fast and slow.&lt;/p&gt;

&lt;p&gt;La idea es esta: usamos dos punteros que arrancan casi juntos. &lt;code&gt;slow&lt;/code&gt; marca la posición donde va el siguiente número único. &lt;code&gt;fast&lt;/code&gt; se adelanta recorriendo todo el array buscando valores nuevos.&lt;/p&gt;

&lt;p&gt;Como el array ya está ordenado, los duplicados siempre están juntos. Entonces &lt;code&gt;fast&lt;/code&gt; solo necesita comparar su valor con el de &lt;code&gt;slow&lt;/code&gt;. Si son diferentes, encontramos un número nuevo: avanzamos &lt;code&gt;slow&lt;/code&gt; una posición y copiamos ahí el valor de &lt;code&gt;fast&lt;/code&gt;. Si son iguales, &lt;code&gt;fast&lt;/code&gt; simplemente sigue avanzando.&lt;/p&gt;

&lt;p&gt;Piénsalo así: &lt;code&gt;slow&lt;/code&gt; es el que construye la respuesta, y &lt;code&gt;fast&lt;/code&gt; es el explorador que le dice "oye, encontré uno nuevo".&lt;/p&gt;

&lt;h3&gt;
  
  
  Solución paso a paso
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {number[]} nums
 * @return {number}
 */&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;removeDuplicates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;fast&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fast&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;slow&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;slow&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fast&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;slow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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;Vamos línea por línea:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;slow&lt;/code&gt; arranca en &lt;code&gt;0&lt;/code&gt;, apuntando al primer elemento. Ese siempre es único porque no hay nada antes con qué comparar.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fast&lt;/code&gt; arranca en &lt;code&gt;1&lt;/code&gt; y recorre el array completo con el &lt;code&gt;for&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;En cada paso, comparamos &lt;code&gt;nums[fast]&lt;/code&gt; con &lt;code&gt;nums[slow]&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;Si son &lt;strong&gt;iguales&lt;/strong&gt;, es un duplicado. &lt;code&gt;fast&lt;/code&gt; avanza y &lt;code&gt;slow&lt;/code&gt; se queda donde está. No hacemos nada.&lt;/li&gt;
&lt;li&gt;Si son &lt;strong&gt;diferentes&lt;/strong&gt;, encontramos un valor nuevo. Avanzamos &lt;code&gt;slow&lt;/code&gt; una posición (&lt;code&gt;slow++&lt;/code&gt;) y copiamos el valor de &lt;code&gt;fast&lt;/code&gt; ahí (&lt;code&gt;nums[slow] = nums[fast]&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Al final, &lt;code&gt;slow&lt;/code&gt; queda apuntando al último elemento único. Como los índices empiezan en &lt;code&gt;0&lt;/code&gt;, el total de únicos es &lt;code&gt;slow + 1&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Veamos cómo se ve con &lt;code&gt;nums = [0, 0, 1, 1, 1, 2, 2, 3, 3, 4]&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbc29qo1ge8gmobk34f4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbc29qo1ge8gmobk34f4g.png" alt="Ejemplo visual de fast and slow pointers eliminando duplicados en un array ordenado" width="800" height="1560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Los primeros 5 elementos son &lt;code&gt;[0, 1, 2, 3, 4]&lt;/code&gt;, exactamente los valores únicos en orden. Lo que queda después del índice 4 no importa.&lt;/p&gt;

&lt;p&gt;¿Ves el patrón? &lt;code&gt;fast&lt;/code&gt; recorre todo el array una sola vez, y &lt;code&gt;slow&lt;/code&gt; solo avanza cuando encuentra algo nuevo. Eso nos da O(n) en tiempo y O(1) en espacio, porque no creamos ninguna estructura extra.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Complejidad: O(n) en tiempo, O(1) en espacio. Un solo recorrido, sin estructuras extra.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Parallel pointers: Intersección de dos arrays
&lt;/h2&gt;

&lt;p&gt;Por último, parallel pointers con &lt;a href="https://leetcode.com/problems/intersection-of-two-arrays/description/" rel="noopener noreferrer"&gt;"Intersection of Two Arrays" de LeetCode&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problema:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Dados dos arreglos de enteros, devuelve un arreglo con su intersección. Cada elemento del resultado debe ser único y puede estar en cualquier orden.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;
  Ejemplos
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input:  nums1 = [1, 2, 2, 1], nums2 = [2, 2]
Output: [2]

Input:  nums1 = [4, 9, 5], nums2 = [9, 4, 9, 8, 4]
Output: [9, 4]  // el orden no importa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo lo pensamos?
&lt;/h3&gt;

&lt;p&gt;La fuerza bruta sería usar dos loops anidados: por cada elemento de &lt;code&gt;nums1&lt;/code&gt;, recorrer todo &lt;code&gt;nums2&lt;/code&gt; buscando coincidencias.&lt;/p&gt;

&lt;p&gt;Con parallel pointers hacemos algo más inteligente: primero ordenamos ambos arrays y después los recorremos una sola vez con dos punteros. Como están ordenados, podemos comparar los valores y decidir cuál puntero mover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si los valores son iguales, encontramos una intersección. Avanzamos ambos.&lt;/li&gt;
&lt;li&gt;Si el valor de &lt;code&gt;p1&lt;/code&gt; es menor, lo avanzamos porque no puede haber coincidencia más atrás en &lt;code&gt;nums2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si el valor de &lt;code&gt;p2&lt;/code&gt; es menor, lo avanzamos por la misma razón.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Es como hacer merge de dos listas ordenadas, pero solo nos quedamos con los valores que aparecen en ambas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solución paso a paso
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;intersection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// ordenar arreglos&lt;/span&gt;
  &lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&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;intersection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Evita duplicados en el resultado&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="nx"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p1&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;span class="nx"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;p2&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;p1&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;p2&lt;/span&gt;&lt;span class="o"&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;intersection&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;Vamos línea por línea:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ordenamos ambos arrays con &lt;code&gt;.sort()&lt;/code&gt;. Esto es clave: sin el orden, no podríamos saber hacia dónde mover los punteros.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;p1&lt;/code&gt; y &lt;code&gt;p2&lt;/code&gt; arrancan en &lt;code&gt;0&lt;/code&gt;, cada uno apuntando al inicio de su array.&lt;/li&gt;
&lt;li&gt;El &lt;code&gt;while&lt;/code&gt; se ejecuta mientras ambos punteros estén dentro de sus arrays.&lt;/li&gt;
&lt;li&gt;Dentro del loop hay tres casos:

&lt;ul&gt;
&lt;li&gt;Si &lt;code&gt;nums1[p1] === nums2[p2]&lt;/code&gt;, encontramos un valor en común. Antes de agregarlo, verificamos que no sea un duplicado (comparando con el último elemento del resultado). Avanzamos ambos punteros.&lt;/li&gt;
&lt;li&gt;Si &lt;code&gt;nums1[p1] &amp;lt; nums2[p2]&lt;/code&gt;, el valor de &lt;code&gt;p1&lt;/code&gt; es más chico. Como ambos arrays están ordenados, ese valor no puede existir más adelante en &lt;code&gt;nums2&lt;/code&gt;. Avanzamos &lt;code&gt;p1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Si &lt;code&gt;nums1[p1] &amp;gt; nums2[p2]&lt;/code&gt;, misma lógica pero al revés. Avanzamos &lt;code&gt;p2&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cuando alguno de los dos punteros llega al final de su array, el loop termina. Ya no puede haber más intersecciones.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Veamos con &lt;code&gt;nums1 = [4, 9, 5]&lt;/code&gt;, &lt;code&gt;nums2 = [9, 4, 9, 8, 4]&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbm7ndbv01ljj53pjttd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbm7ndbv01ljj53pjttd.png" alt="Ejemplo de parallel pointers encontrando la intersección de dos arrays" width="800" height="1362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Ves cómo cada puntero solo avanza hacia adelante? Nunca retroceden. El recorrido en sí es O(n + m), pero el ordenamiento inicial domina: O(n log n + m log m) en total.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Complejidad: O(n log n + m log m) en tiempo por el ordenamiento. O(n) en espacio para el resultado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Resumen
&lt;/h2&gt;

&lt;p&gt;Estas tres técnicas son variantes de un mismo concepto: usar dos punteros para recorrer arrays o strings de forma eficiente.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Técnica&lt;/th&gt;
&lt;th&gt;Movimiento de punteros&lt;/th&gt;
&lt;th&gt;Problema resuelto&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Opposite direction&lt;/td&gt;
&lt;td&gt;De los extremos al centro&lt;/td&gt;
&lt;td&gt;Valid Palindrome&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fast and slow&lt;/td&gt;
&lt;td&gt;Uno explora, otro referencia&lt;/td&gt;
&lt;td&gt;Remove Duplicates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parallel pointers&lt;/td&gt;
&lt;td&gt;Cada uno en su array&lt;/td&gt;
&lt;td&gt;Intersection of Two Arrays&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzino3kb155ixt357afde.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzino3kb155ixt357afde.png" alt="Árbol de decisión para elegir la variante de two pointers" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La clave no es memorizar las soluciones. Es reconocer el patrón en el enunciado y saber qué técnica aplicar. Con práctica, vas a leer un problema y saber qué variante de two pointers usar antes de escribir una línea de código.&lt;/p&gt;

&lt;p&gt;Si quieres seguir practicando, aquí te dejo más problemas de LeetCode:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/problems/valid-anagram/description/" rel="noopener noreferrer"&gt;Valid Anagram&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/explore/learn/card/fun-with-arrays/527/searching-for-items-in-an-array/3250/" rel="noopener noreferrer"&gt;Check If N and Its Double Exist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://leetcode.com/explore/learn/card/fun-with-arrays/511/searching-for-items-in-an-array/3157/" rel="noopener noreferrer"&gt;Move Zeroes&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;¿Cuál técnica te costó más entender? ¿Hay algún problema que quieras que resolvamos juntos? Déjamelo en los comentarios. 🙌🏻&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>algorithms</category>
      <category>beginners</category>
      <category>spanish</category>
    </item>
    <item>
      <title>No olvides revisar estos consejos para disminuir la probabilidad de infectar tu computadora con un troyano al instalar un paquete de npm.</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Thu, 16 Apr 2026 18:03:35 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/no-olvides-revisar-estos-consejos-para-disminuir-la-probabilidad-de-infectar-tu-computadora-con-un-2k6h</link>
      <guid>https://dev.to/fromchiapasdev/no-olvides-revisar-estos-consejos-para-disminuir-la-probabilidad-de-infectar-tu-computadora-con-un-2k6h</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea" class="crayons-story__hidden-navigation-link"&gt;npm install puede infectar tu máquina: cómo protegerte&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/fromchiapasdev" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F186583%2F9cef57b1-206b-4316-9880-0fe5907f987f.jpeg" alt="fromchiapasdev profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/fromchiapasdev" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Axel Espinosa
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Axel Espinosa
                
              
              &lt;div id="story-author-preview-content-3452405" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/fromchiapasdev" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F186583%2F9cef57b1-206b-4316-9880-0fe5907f987f.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Axel Espinosa&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 4&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea" id="article-link-3452405"&gt;
          npm install puede infectar tu máquina: cómo protegerte
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag crayons-tag--filled  " href="/t/discuss"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;discuss&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/npm"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;npm&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/node"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;node&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              1&lt;span class="hidden s:inline"&gt; comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>🙌🏻</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Wed, 15 Apr 2026 16:25:01 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/-2ai7</link>
      <guid>https://dev.to/fromchiapasdev/-2ai7</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/aws/como-crear-un-agente-de-ia-desde-cero-open-source-local-y-gratis-k6d" class="crayons-story__hidden-navigation-link"&gt;Cómo crear un agente de IA desde cero. Open source, local y gratis.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/aws"&gt;
            &lt;img alt="AWS logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1726%2F2a73f1e6-7995-4348-ae37-44b064274c59.png" class="crayons-logo__image" width="320" height="320"&gt;
          &lt;/a&gt;

          &lt;a href="/hsaenzg" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F852908%2Fa3a10986-307b-4a35-8adf-eeb9a583e6a9.jpg" alt="hsaenzg profile" class="crayons-avatar__image" width="800" height="1067"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/hsaenzg" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Hazel Saenz
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Hazel Saenz
                
              
              &lt;div id="story-author-preview-content-3506071" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/hsaenzg" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F852908%2Fa3a10986-307b-4a35-8adf-eeb9a583e6a9.jpg" class="crayons-avatar__image" alt="" width="800" height="1067"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Hazel Saenz&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/aws" class="crayons-story__secondary fw-medium"&gt;AWS&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/aws/como-crear-un-agente-de-ia-desde-cero-open-source-local-y-gratis-k6d" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 15&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/aws/como-crear-un-agente-de-ia-desde-cero-open-source-local-y-gratis-k6d" id="article-link-3506071"&gt;
          Cómo crear un agente de IA desde cero. Open source, local y gratis.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/agents"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;agents&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/aws/como-crear-un-agente-de-ia-desde-cero-open-source-local-y-gratis-k6d" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt; reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/aws/como-crear-un-agente-de-ia-desde-cero-open-source-local-y-gratis-k6d#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            14 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>¿Qué es un String y para qué sirven?</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Mon, 13 Apr 2026 21:19:53 +0000</pubDate>
      <link>https://dev.to/aws/strings-en-programacion-mas-que-un-simple-array-de-caracteres-1knd</link>
      <guid>https://dev.to/aws/strings-en-programacion-mas-que-un-simple-array-de-caracteres-1knd</guid>
      <description>&lt;p&gt;Los strings son probablemente la estructura de datos que más usas sin pensar. Pero, ¿sabes cómo se almacenan en memoria? ¿Por qué no puedes modificarlos directamente? ¿Cuánto cuesta concatenarlos en un loop?&lt;/p&gt;

&lt;p&gt;En el &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;artículo anterior&lt;/a&gt; vimos cómo funcionan los arrays por debajo: memoria contigua, acceso por índice, operaciones y sus costos. Si aún no lo has leído, te recomiendo empezar por ahí. Hoy toca hablar de sus primos: los strings.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En estos ejemplos usaremos JavaScript como lenguaje principal. Si usas otro lenguaje, te invito a buscar los métodos equivalentes. Los conceptos son los mismos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lo que encontrarás en este artículo:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Qué es un string y cómo se almacena en memoria&lt;/li&gt;
&lt;li&gt;Qué significa que sean inmutables&lt;/li&gt;
&lt;li&gt;En qué se parecen y en qué se diferencian de los arrays&lt;/li&gt;
&lt;li&gt;Operaciones comunes con strings y cuánto cuestan (Big O)&lt;/li&gt;
&lt;li&gt;Una tabla de complejidad para que la tengas de referencia&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  1. ¿Qué es un string?
&lt;/h2&gt;

&lt;p&gt;Un string (o cadena de caracteres) es una secuencia de caracteres almacenados de forma contigua en memoria. Suena familiar, ¿verdad? Es básicamente lo que vimos con los &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;arrays&lt;/a&gt;, pero en lugar de números o emojis, almacenamos caracteres.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Índice:    0   1   2   3   4
         ┌───┬───┬───┬───┬───┐
String:  │ H │ o │ l │ a │ ! │
         └───┴───┴───┴───┴───┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para empezar, puedes pensar en un string como un array de caracteres — es un buen modelo mental. Más adelante verás que los motores modernos implementan strings con estructuras más sofisticadas, pero conceptualmente esta idea te va a servir para entender cómo se comportan.&lt;/p&gt;

&lt;p&gt;Pero aquí viene el detalle: ¿qué es realmente un "carácter" para la computadora? No es una letra. Es un número. La "H" es el 72, la "o" es el 111. Cada carácter tiene un código numérico asignado por un estándar (como ASCII o Unicode), y un encoding (como UTF-8) convierte ese código a bits. Así que cuando digo "array de caracteres", por debajo es un array de números.&lt;/p&gt;

&lt;p&gt;Si quieres entender a fondo cómo funciona eso, lo cubrimos en el &lt;a href="https://dev.to/fromchiapasdev/encodings-por-que-importan-mas-de-lo-que-crees-41a5"&gt;artículo de encodings&lt;/a&gt;. Ahí explicamos por qué un emoji ocupa 4 bytes y una letra solo 1. 😉&lt;/p&gt;

&lt;p&gt;Cada carácter ocupa una posición y tiene un índice, exactamente como en un array. Y al igual que con los &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;arrays&lt;/a&gt;, acceder a un carácter por su índice es instantáneo: O(1).&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saludo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saludo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// "H"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saludo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// "!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Una advertencia importante:&lt;/strong&gt; este modelo funciona perfectamente con caracteres del alfabeto latino básico, pero se complica con emojis y algunos caracteres especiales. En JavaScript, un emoji como 😀 ocupa &lt;strong&gt;dos posiciones&lt;/strong&gt; en el string, no una:&lt;/p&gt;


&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;😀&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 2, no 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Esto es por cómo JavaScript representa internamente el texto (UTF-16). Lo vemos a detalle en el &lt;a href="https://dev.to/fromchiapasdev/encodings-por-que-importan-mas-de-lo-que-crees-41a5"&gt;artículo de encodings&lt;/a&gt;. Por ahora, si trabajas con caracteres simples, el modelo de "array de caracteres" te sirve bien.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. ¿Por qué los strings son inmutables?
&lt;/h2&gt;

&lt;p&gt;Porque una vez que creas un string, su contenido no puede cambiar. Si necesitas una versión diferente, se crea uno nuevo en memoria. Esto aplica en JavaScript, Python y la mayoría de lenguajes modernos. Aquí es donde los strings empiezan a diferenciarse de los arrays.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué significa inmutable?
&lt;/h3&gt;

&lt;p&gt;Inmutable quiere decir que algo no puede cambiar después de creado. En programación, cuando decimos que un valor es inmutable, significa que no puedes modificar su contenido directamente. Si necesitas una versión diferente, tienes que crear una nueva.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Qué pasa cuando modificas un string?
&lt;/h3&gt;

&lt;p&gt;En lenguajes como JavaScript y Python, los strings son inmutables. Esto quiere decir que cuando "modificas" un string, en realidad se está creando uno nuevo en memoria. El original no se toca.&lt;/p&gt;

&lt;p&gt;Veamos un ejemplo:&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;palabra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;palabra&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;J&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Intentamos cambiar la "H" por "J"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;palabra&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "Hola" — no cambió nada&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿Ves? JavaScript simplemente ignora el intento. No lanza un error, pero tampoco hace el cambio.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Si tu código está en strict mode (lo cual pasa automáticamente dentro de módulos ES y clases), este intento sí lanza un &lt;code&gt;TypeError&lt;/code&gt;. Es el comportamiento más común en código moderno.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En Python es más explícito:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;palabra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hola&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;palabra&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;J&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# TypeError: 'str' object does not support item assignment
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python directamente te dice: "no puedes hacer eso".&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cuánto cuesta concatenar strings?
&lt;/h3&gt;

&lt;p&gt;Cuando concatenas strings con &lt;code&gt;+=&lt;/code&gt;, no estás "agregando" al final como harías con &lt;code&gt;push()&lt;/code&gt; en un array. Conceptualmente, se crea un string nuevo que contiene todo el contenido anterior más lo que agregaste.&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Se crea un nuevo string "Hola"&lt;/span&gt;
&lt;span class="nx"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Se crea un nuevo string "Hola "&lt;/span&gt;
&lt;span class="nx"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Mundo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Se crea un nuevo string "Hola Mundo"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Construir un string de tamaño N con concatenaciones repetidas tiene un costo total de O(N) — el tamaño del resultado final.&lt;/p&gt;

&lt;p&gt;Los motores de JavaScript modernos optimizan este caso con estructuras internas que evitan copiar el string completo en cada paso, así que en la práctica &lt;code&gt;+=&lt;/code&gt; en un loop es bastante eficiente. Pero la regla general sigue siendo útil: si vas a construir texto pieza por pieza, piensa en el tamaño del resultado final, no solo en cuántas piezas tienes.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. ¿Cuál es la diferencia entre strings y arrays?
&lt;/h2&gt;

&lt;p&gt;Ambos son secuencias contiguas con acceso por índice O(1), pero los arrays son mutables y los strings no. Esa diferencia cambia todo: los arrays tienen &lt;code&gt;push&lt;/code&gt; y &lt;code&gt;pop&lt;/code&gt;, los strings tienen métodos de texto como &lt;code&gt;slice&lt;/code&gt;, &lt;code&gt;split&lt;/code&gt; y &lt;code&gt;replace&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Primos, no gemelos. Los arrays te permiten modificar su contenido directamente: cambiar un elemento por índice, agregar al final, quitar del inicio. Los strings no. Son inmutables, así que no puedes hacer &lt;code&gt;push&lt;/code&gt; o &lt;code&gt;pop&lt;/code&gt; sobre un string.&lt;/p&gt;

&lt;p&gt;Lo que sí tienen los strings son métodos especializados para operaciones comunes con texto: buscar, acortar, dividir, reemplazar. Implementar estos métodos de strings manualmente sería tedioso (y propenso a errores). Por eso los lenguajes nos dan estos métodos listos para usar.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Característica&lt;/th&gt;
&lt;th&gt;Array (dinámico)&lt;/th&gt;
&lt;th&gt;String&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Secuencia contigua&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Acceso por índice&lt;/td&gt;
&lt;td&gt;✅ O(1)&lt;/td&gt;
&lt;td&gt;✅ O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mutable&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;push / pop&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Métodos de texto&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ (search, slice, split, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redimensionable&lt;/td&gt;
&lt;td&gt;✅ (crece automáticamente)&lt;/td&gt;
&lt;td&gt;❌ (se crea uno nuevo)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  4. Operaciones comunes con strings y su complejidad
&lt;/h2&gt;

&lt;p&gt;Vamos a las operaciones que más vas a usar con strings. Cada una con un ejemplo en JavaScript y su complejidad.&lt;/p&gt;

&lt;h3&gt;
  
  
  Obtener longitud
&lt;/h3&gt;

&lt;p&gt;Igual que con los arrays, podemos saber cuántos caracteres tiene un string con &lt;code&gt;.length&lt;/code&gt;.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;texto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola Mundo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(1)&lt;/strong&gt; — el acceso es inmediato&lt;/p&gt;

&lt;h3&gt;
  
  
  Acceso por índice
&lt;/h3&gt;

&lt;p&gt;Ya lo vimos, pero vale la pena repetirlo: puedes acceder a cualquier carácter directamente por su posición.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;texto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JavaScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// "J"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// "S"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(1)&lt;/strong&gt; — acceso directo, como el elevador del artículo de arrays.&lt;/p&gt;

&lt;h3&gt;
  
  
  Buscar dentro de un string
&lt;/h3&gt;

&lt;p&gt;Podemos verificar si un string contiene cierto texto con &lt;code&gt;includes()&lt;/code&gt;, o encontrar la posición exacta con &lt;code&gt;indexOf()&lt;/code&gt;.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;frase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Los arrays son geniales&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arrays&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arrays&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 4&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;strings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// -1 (no lo encontró)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(n·m) en el peor caso&lt;/strong&gt; — donde &lt;code&gt;n&lt;/code&gt; es la longitud del string y &lt;code&gt;m&lt;/code&gt; la longitud del texto que buscas. En la práctica, los motores modernos usan algoritmos de búsqueda optimizados que son mucho más rápidos en la mayoría de los casos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extraer una porción (slice / substring)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;slice()&lt;/code&gt; te permite extraer una parte del string sin modificar el original (recuerda: inmutabilidad).&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;texto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JavaScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "Java"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "Script"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;texto&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// string original&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(n) en el peor caso&lt;/strong&gt; — donde &lt;code&gt;n&lt;/code&gt; es el tamaño de la porción extraída. Algunos motores optimizan esta operación para evitar copiar cuando es posible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dividir un string (split)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;split()&lt;/code&gt; divide un string en un array de substrings usando un separador.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;csv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nombre,edad,ciudad&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;campos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;campos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ["nombre", "edad", "ciudad"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(n)&lt;/strong&gt; — recorre todo el string para encontrar los separadores y crear los substrings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Concatenar strings
&lt;/h3&gt;

&lt;p&gt;Ya hablamos de esto, pero aquí va el resumen con código:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nombre&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hola&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;saludo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nombre&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; Mundo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saludo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "Hola Mundo"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complejidad: O(n)&lt;/strong&gt; — donde &lt;code&gt;n&lt;/code&gt; es el tamaño del resultado final. Recuerda que los motores modernos optimizan esta operación por debajo.&lt;/p&gt;

&lt;p&gt;Si quieres explorar todos los métodos de strings disponibles en JavaScript, la &lt;a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/String" rel="noopener noreferrer"&gt;referencia de String en MDN&lt;/a&gt; es un excelente recurso.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. ¿Cuál es la complejidad Big O de las operaciones con strings?
&lt;/h2&gt;

&lt;p&gt;Aquí te dejo la tabla de complejidad, en el mismo formato que usamos en el artículo de arrays para que puedas compararlas:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operación&lt;/th&gt;
&lt;th&gt;Complejidad&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Acceso por índice&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Obtener longitud&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Buscar un substring&lt;/td&gt;
&lt;td&gt;O(n·m)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concatenar (resultado total)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Slice / Substring&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Split&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Nota:&lt;/strong&gt; las complejidades de búsqueda y concatenación representan el &lt;strong&gt;peor caso&lt;/strong&gt;. Los motores modernos de JavaScript implementan optimizaciones que hacen que en la práctica sean más rápidas de lo que sugiere la teoría.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Compara esta tabla con la del &lt;a href="https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf"&gt;artículo de arrays&lt;/a&gt;. Vas a notar que el acceso por índice es igual de rápido en ambos. La diferencia está en que los strings no tienen operaciones como &lt;code&gt;push&lt;/code&gt; o &lt;code&gt;pop&lt;/code&gt; porque son inmutables. Cada vez que necesitas un string "modificado", estás pagando el costo de crear uno nuevo.&lt;/p&gt;

&lt;p&gt;Algo importante: en esta tabla y a lo largo del artículo usamos Big O para describir el costo de las operaciones. Big O es una notación que nos dice cómo crece el tiempo de una operación conforme crece el tamaño de la entrada. O(1) significa tiempo constante (siempre tarda lo mismo sin importar el tamaño), y O(n) significa tiempo lineal (entre más grande la entrada, más tarda, proporcionalmente).&lt;/p&gt;

&lt;p&gt;No es el foco de este artículo, pero es importante que tengas el contexto. Si quieres que hagamos un artículo dedicado a Big O, dime en los comentarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Los strings son como los primos de los arrays: comparten la misma base (secuencia contigua, acceso por índice) pero juegan con reglas diferentes gracias a la inmutabilidad. Eso los hace predecibles y seguros, pero también significa que operaciones que parecen simples, como concatenar en un loop, pueden ser más costosas de lo que esperabas.&lt;/p&gt;

&lt;p&gt;Si leíste con atención, quizá notaste que dije varias veces "en el peor caso". Eso es porque los motores de JavaScript modernos hacen optimizaciones que a veces rompen el modelo mental simple que vimos aquí.&lt;/p&gt;

&lt;p&gt;En el siguiente artículo de la serie vamos a poner en práctica todo lo que hemos visto de arrays y strings con problemas y patrones comunes de entrevistas técnicas. Ahí es donde todo se conecta. 💪&lt;/p&gt;

&lt;p&gt;Si quieres avanzar con el siguiente tema intenta resolver esto: &lt;em&gt;dado un string, ¿cómo lo invertirías sin usar &lt;code&gt;.reverse()&lt;/code&gt;? Piensa en lo que vimos de inmutabilidad&lt;/em&gt;. En el siguiente artículo vamos a resolver este tipo de problemas.&lt;/p&gt;

&lt;p&gt;Gracias por llegar hasta el final. Estaré pendiente de tus comentarios 🙌🏻&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>algorithms</category>
      <category>beginners</category>
      <category>español</category>
    </item>
    <item>
      <title>npm install puede infectar tu máquina: cómo protegerte</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Sat, 04 Apr 2026 05:57:09 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea</link>
      <guid>https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea</guid>
      <description>&lt;p&gt;Haces &lt;code&gt;npm install&lt;/code&gt;, confías en que todo está bien, y sin saberlo un script malicioso ya se ejecutó en tu máquina. Así funcionan los ataques de supply chain en npm: infectan paquetes populares (o sus dependencias) y usan los lifecycle scripts para correr código antes de que te des cuenta.&lt;/p&gt;

&lt;p&gt;Este tipo de ataque se viene hablando desde el 2022 pero los atacantes lo han utilizado con mayor frecuencia debido al alcance que logran tener en el ecosistema de npm. Un ejemplo reciente: &lt;a href="https://www.microsoft.com/en-us/security/blog/2025/12/09/shai-hulud-2-0-guidance-for-detecting-investigating-and-defending-against-the-supply-chain-attack/" rel="noopener noreferrer"&gt;Shai Hulud&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En este post te explico cómo funcionan estos ataques y qué configuraciones puedes aplicar hoy para proteger tus proyectos.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es un "supply chain attack" o ataque a la cadena de suministro?
&lt;/h2&gt;

&lt;p&gt;Este tipo de ataque se caracteriza por infectar alguna parte del ciclo de entrega del software.&lt;br&gt;
Muchos proyectos tienen este ciclo de vida:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Escribir el código&lt;/li&gt;
&lt;li&gt;Instalar paquetes&lt;/li&gt;
&lt;li&gt;Mandar a un ambiente de CI/CD&lt;/li&gt;
&lt;li&gt;Enviar proyecto a producción&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Los ataques de supply chain se insertan en uno de estos pasos comprometiendo toda la cadena de pasos siguientes.&lt;/p&gt;
&lt;h2&gt;
  
  
  ¿Cómo se infecta una librería?
&lt;/h2&gt;

&lt;p&gt;Los atacantes no siempre comprometen el paquete popular directamente. Muchas veces infectan una dependencia interna de ese paquete.&lt;/p&gt;

&lt;p&gt;Tu al instalar el paquete popular, sin saberlo estás instalando también el código de la dependencia infectada.&lt;/p&gt;
&lt;h2&gt;
  
  
  ¿Cómo funcionan los lifecycle scripts en npm?
&lt;/h2&gt;

&lt;p&gt;Los ataques recientes han utilizado una funcionalidad del gestor de paquetes de npm: la capacidad de ejecutar scripts antes o después de la instalación de un paquete.&lt;/p&gt;

&lt;p&gt;A esto se le llaman "lifecycle scripts". Muchos paquetes los usan de manera legítima para preparar pasos previos a la instalación, como la compilación de paquetes nativos. Aunque la documentación de npm recomienda evitarlos, algunos paquetes los necesitan, y es precisamente esa característica la que los paquetes infectados utilizan.&lt;/p&gt;

&lt;p&gt;Como esto es un proceso que sucede antes de que se instale el paquete, nosotros no nos percatamos de lo que se ejecuta. Los paquetes con malware ejecutan todos los pasos que necesitan para infectar tu equipo, robar información y después dejar todo limpio como si nada hubiera pasado. Eso es lo más crítico.&lt;/p&gt;
&lt;h2&gt;
  
  
  ¿Cómo proteger tu proyecto de paquetes maliciosos en npm?
&lt;/h2&gt;

&lt;p&gt;Hay varias medidas que podemos tomar. Vamos una por una.&lt;/p&gt;
&lt;h3&gt;
  
  
  No actualices versiones a lo loco
&lt;/h3&gt;

&lt;p&gt;Es muy común utilizar herramientas como &lt;a href="https://www.npmjs.com/package/npm-check-updates" rel="noopener noreferrer"&gt;npm-check-updates&lt;/a&gt; para actualizar dependencias automáticamente. Siempre queremos tener lo último y pensamos que eso es lo correcto, pero realmente introducimos un vector de ataque.&lt;/p&gt;

&lt;p&gt;La última versión puede traer malware. Mejor revisa qué se publicó, qué cambió en el changelog y si hay reportes antes de actualizar.&lt;/p&gt;
&lt;h3&gt;
  
  
  Bloquea los lifecycle scripts
&lt;/h3&gt;

&lt;p&gt;Como vimos, es por estos scripts que muchos de los ataques suceden. Podemos desactivarlos al instalar una dependencia.&lt;/p&gt;

&lt;p&gt;De manera individual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--ignore-scripts&lt;/span&gt; &amp;lt;pkg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De manera global:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm config &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; ignore-scripts &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O por proyecto con el archivo &lt;code&gt;.npmrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ignore-scripts&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto se agregó en la versión v11 de npm.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bloquea instalaciones desde Git
&lt;/h3&gt;

&lt;p&gt;Adicional a esto necesitas configurar el flag de &lt;code&gt;allow-git&lt;/code&gt; para evitar que se instalen paquetes desde algún repositorio de Git en vez del registro de npm.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--ignore-scripts&lt;/span&gt; &lt;span class="nt"&gt;--allow-git&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;none &amp;lt;pkg&amp;gt;

&lt;span class="c"&gt;# global&lt;/span&gt;
npm config &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; allow-git none

&lt;span class="c"&gt;# .npmrc&lt;/span&gt;
ignore-scripts&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;allow-git&lt;span class="o"&gt;=&lt;/span&gt;none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fija la versión de tus dependencias
&lt;/h3&gt;

&lt;p&gt;Algo que yo particularmente no sabía es que fijar las versiones es una buena práctica. Estamos acostumbrados a instalar con &lt;code&gt;npm install&lt;/code&gt; y asumir que el símbolo &lt;code&gt;^&lt;/code&gt; al inicio de la versión en &lt;code&gt;package.json&lt;/code&gt; está bien.&lt;/p&gt;

&lt;p&gt;Pero ese &lt;code&gt;^&lt;/code&gt; significa que al actualizar puedes descargar cualquier versión del paquete que no haga un salto de major version (el primer número). Es decir, si tienes la versión &lt;code&gt;1.x.x&lt;/code&gt;, npm puede instalar cualquier &lt;code&gt;1.y.z&lt;/code&gt; sin preguntarte.&lt;/p&gt;

&lt;p&gt;Para fijar la versión exacta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-exact&lt;/span&gt; &amp;lt;pkg&amp;gt;

&lt;span class="c"&gt;# global&lt;/span&gt;
npm config &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; save-exact &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# .npmrc&lt;/span&gt;
save-exact&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  No instales la versión más reciente
&lt;/h3&gt;

&lt;p&gt;Otra precaución: evita instalar el paquete más reciente que existe. Esto puede pasar cuando haces un &lt;code&gt;npm update&lt;/code&gt; o instalas el paquete por primera vez.&lt;/p&gt;

&lt;p&gt;Muchos de los infectados en los ataques fue porque se publicó una versión nueva y muchas personas la instalaron de inmediato. Al paso de unas horas los contribuidores del paquete se dieron cuenta de que el paquete había sido comprometido.&lt;/p&gt;

&lt;p&gt;Para evitar esto existe &lt;code&gt;min-release-age&lt;/code&gt;: configuras cuánto tiempo debe haber pasado desde que se publicó un paquete para que npm lo instale.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--min-release-age&lt;/span&gt; 3 &amp;lt;pkg&amp;gt;

&lt;span class="c"&gt;# .npmrc&lt;/span&gt;
min-release-age&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="c"&gt;# 3 dias (npm usa días)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta configuración está disponible a partir de la versión v11 de npm.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tu &lt;code&gt;.npmrc&lt;/code&gt; defensivo mínimo
&lt;/h3&gt;

&lt;p&gt;Así queda el &lt;code&gt;.npmrc&lt;/code&gt; mínimo para tus proyectos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;save-exact&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;ignore-scripts&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;min-release-age&lt;span class="o"&gt;=&lt;/span&gt;3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y en CI, siempre &lt;code&gt;npm ci --ignore-scripts&lt;/code&gt;, nunca &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerar pnpm
&lt;/h2&gt;

&lt;p&gt;pnpm es una alternativa a npm que bloquea los lifecycle scripts por defecto. Personalmente lo estoy usando para mis proyectos porque reduce el consumo de espacio (optimiza los &lt;code&gt;node_modules&lt;/code&gt;) y porque trae estas protecciones incluidas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bloqueo de dependencias y builds
&lt;/h3&gt;

&lt;p&gt;Por defecto, pnpm bloquea los scripts de pre/post instalación. Si algún paquete legítimo los necesita (como &lt;code&gt;esbuild&lt;/code&gt; o &lt;code&gt;next&lt;/code&gt;), puedes permitirlo explícitamente en el &lt;code&gt;pnpm-workspace.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Permitir dependencias que sí pueden usar los lifecycle scripts (pnpm 10+)&lt;/span&gt;
&lt;span class="na"&gt;allowBuilds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;esbuild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;strictDepBuilds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Muestra error si alguna dependencia no listada hace uso de lifecycle scripts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tiempo de antigüedad
&lt;/h3&gt;

&lt;p&gt;Como en npm, puedes configurar el tiempo mínimo que debe haber pasado para instalar un paquete:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;allowBuilds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;esbuild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;strictDepBuilds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;minimumReleaseAge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1440&lt;/span&gt; &lt;span class="c1"&gt;# mínimo 24 hrs (pnpm usa minutos)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Snyk recomienda que usemos al menos 21 días como periodo para instalar una nueva dependencia.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Cómo funciona &lt;code&gt;trustPolicy&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;pnpm asigna un &lt;strong&gt;nivel de confianza&lt;/strong&gt; a cada versión publicada de un paquete, basado en cómo fue publicada. Los niveles de mayor a menor son:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Trusted Publisher&lt;/strong&gt;: publicado vía GitHub Actions con OIDC (el CI firma criptográficamente que el paquete viene de un workflow específico en un repo específico)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provenance&lt;/strong&gt;: tiene una prueba verificable de npm que confirma dónde y cómo se construyó el paquete&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signatures&lt;/strong&gt;: tiene firma del registry de npm&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sin evidencia&lt;/strong&gt;: publicado sin ninguna señal de confianza&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Si configuras &lt;code&gt;trustPolicy: no-downgrade&lt;/code&gt;, pnpm compara el nivel de confianza de la versión que vas a instalar con el de versiones anteriores del mismo paquete. Si la confianza baja (por ejemplo, un paquete que siempre se publicó desde CI de repente aparece publicado sin ninguna evidencia), pnpm aborta la instalación.&lt;/p&gt;

&lt;h2&gt;
  
  
  Revisar antes de instalar
&lt;/h2&gt;

&lt;p&gt;No instales paquetes de manera ciega. Existen herramientas que te ayudan a revisarlos antes.&lt;/p&gt;

&lt;h3&gt;
  
  
  npq
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/lirantal/npq" rel="noopener noreferrer"&gt;npq&lt;/a&gt; te ayuda a revisar lo que piensas instalar antes de siquiera instalarlo. Te advierte de posibles vulnerabilidades.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx npq &lt;span class="nb"&gt;install &lt;/span&gt;express &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A partir de lo que veas puedes decidir si instalas la última versión o te esperas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Socket Firewall
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://socket.dev/blog/introducing-socket-firewall" rel="noopener noreferrer"&gt;Socket Firewall&lt;/a&gt; es similar a npq pero además te permite usarlo con el manejador de paquetes de Python (uv). Personalmente no lo he utilizado, pero lo mencionan en las buenas prácticas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Medidas adicionales
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Evitar el uso de .env con información sensible
&lt;/h3&gt;

&lt;p&gt;No tengas tus claves de producción, tokens o lo que sea importante en tu &lt;code&gt;.env&lt;/code&gt; de manera plana como solíamos hacerlo. Si bien no subimos esta información a GitHub, en los ataques de supply chain los paquetes maliciosos tienen acceso al entorno donde se ejecutan. Esto quiere decir: tus accesos están expuestos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.nodejs-security.com/blog/do-not-use-secrets-in-environment-variables-and-here-is-how-to-do-it-better" rel="noopener noreferrer"&gt;Una alternativa es usar secretos. En su blog, Liran te explica cómo hacerlo.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Usa devcontainers
&lt;/h3&gt;

&lt;p&gt;Personalmente ya sabía que existían pero no suelo trabajar con ellos. En las &lt;a href="https://github.com/lirantal/npm-security-best-practices?tab=readme-ov-file#8-work-in-dev-containers" rel="noopener noreferrer"&gt;buenas prácticas de seguridad de Node.js mencionan&lt;/a&gt; la opción de usarlos para aislar los ataques y reducir el área de ataque a únicamente ese contenedor.&lt;/p&gt;

&lt;p&gt;Si te gustaría un tutorial, déjame un comentario.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verifica tu ambiente
&lt;/h3&gt;

&lt;p&gt;Para verificar si tu ambiente ya bloquea los pre/post scripts puedes probar &lt;a href="https://www.npmjs.com/package/@lavamoat/preinstall-always-fail" rel="noopener noreferrer"&gt;este paquete creado específicamente para eso&lt;/a&gt;. Si la instalación falla, significa que tus protecciones están funcionando.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  npm &lt;span class="nb"&gt;install&lt;/span&gt; @lavamoat/preinstall-always-fail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  No estamos 100% seguros
&lt;/h2&gt;

&lt;p&gt;Con estas prácticas reducimos el área de ataque, pero lo importante es mantenernos atentos a las noticias de seguridad y reducir el número de paquetes instalados si es posible.&lt;/p&gt;

&lt;p&gt;Entre menos paquetes tengas, menos área de ataque y menos dependencias que vigilar. JavaScript ha evolucionado tanto que muchas cosas que antes necesitaban una librería hoy son triviales de hacer de forma nativa, o la librería estándar de Node.js ya las incluye.&lt;/p&gt;

&lt;p&gt;Con un &lt;code&gt;.npmrc&lt;/code&gt; bien configurado ya reduces la mayoría de los vectores de ataque. Recuerda revisar tus paquetes con npq o algún otra herramienta antes de instalarlos.&lt;/p&gt;

&lt;p&gt;¿Ya tenías alguna de estas configuraciones? ¿Usas alguna otra medida? ¿Hay algo que no sea correcto? Deja tus comentarios.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: no soy experto en seguridad. Esto es información recopilada para mi propio uso y para ayudar a los demás.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>security</category>
      <category>npm</category>
      <category>node</category>
    </item>
    <item>
      <title>npm install tips para la seguridad</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Tue, 31 Mar 2026 19:10:23 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/npm-install-tips-para-la-seguridad-3lm9</link>
      <guid>https://dev.to/fromchiapasdev/npm-install-tips-para-la-seguridad-3lm9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Actualización: Escribí un &lt;a href="https://dev.to/fromchiapasdev/como-proteger-tu-proyecto-de-paquetes-maliciosos-en-npm-gea"&gt;artículo&lt;/a&gt; sobre lo minimo que debes hacer para protegerte&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwcvjhlyzj5i6k9tj5rj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwcvjhlyzj5i6k9tj5rj.gif" alt="Gif espantado por el ataque de NPM hoy" width="334" height="480"&gt;&lt;/a&gt;&lt;br&gt;
Hay un nuevo ataque en el ecosistema de npm y con esto crece la duda de cómo prevenir infectarse.&lt;/p&gt;

&lt;p&gt;Compartamos los mejores consejos para evitar infectarse en los comentarios para mantenernos seguros.&lt;/p&gt;

&lt;p&gt;Empiezo ⬇️&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>npm</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>¿Qué son los arrays y para qué sirven? Explicación sencilla</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Fri, 20 Mar 2026 18:40:05 +0000</pubDate>
      <link>https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf</link>
      <guid>https://dev.to/aws/arrays-los-bloques-fundamentales-de-la-programacion-3jmf</guid>
      <description>&lt;p&gt;Bienvenido a esta serie de artículos donde cubrimos temas fundamentales de computación. Hoy platicaremos sobre arrays, una de las estructuras de datos más utilizadas en cualquier lenguaje de programación.&lt;/p&gt;

&lt;p&gt;Pero antes de entrar de lleno, necesitamos hablar sobre la memoria. Específicamente, la memoria RAM.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En estos ejemplos usaremos JavaScript como lenguaje principal y algunos ejemplos básicos de C. No necesitas ser experto en ninguno de los dos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Cómo funciona la RAM
&lt;/h2&gt;

&lt;p&gt;Todas las computadoras utilizan memoria para funcionar. En particular, hablamos de la memoria RAM, la cual almacena información temporal sobre los programas que estás ejecutando. Cuando digo temporal es porque, cuando la computadora se apaga, toda esa información se pierde y, al encender, la memoria vuelve a estar limpia. Es como si la RAM tuviera mala memoria.&lt;/p&gt;

&lt;p&gt;Al hablar de memoria RAM, es inevitable hablar de direcciones y sé lo que estás pensando. ¿Cómo que direcciones?&lt;/p&gt;

&lt;p&gt;Déjame darte un ejemplo que me ayudó a entender este concepto:&lt;/p&gt;

&lt;p&gt;Imagina un elevador en un edificio. Cada piso tiene un número: 0, 1, 2, 3... y en cada piso hay exactamente una oficina con información. Cuando presionas el botón del piso 42, el elevador no necesita detenerse en cada piso antes. No importa si es el piso 1 o el 99, el tiempo de llegada es prácticamente el mismo. Así funciona la RAM: cada posición de memoria tiene una dirección numérica y tu computadora accede a cualquiera de forma instantánea, sin recorrer las anteriores.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finhnrgftlyqrubqx45lw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finhnrgftlyqrubqx45lw.png" alt="Edificio analogía" width="800" height="1509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es un array?
&lt;/h2&gt;

&lt;p&gt;Ahora imagina que una empresa renta 5 pisos consecutivos para sus 5 departamentos, todos del mismo tamaño. Eso es un array: una secuencia de datos del mismo tipo, almacenados en posiciones contiguas de memoria. Si sabes en qué piso empieza la empresa y cuánto ocupa cada departamento, puedes llegar a cualquiera de ellos con el elevador sin recorrer los demás.&lt;/p&gt;

&lt;p&gt;La contigüidad importa porque, como vimos en la analogía, podemos acceder de manera directa a cualquier elemento sin necesidad de recorrer los anteriores. Tu computadora calcula la dirección exacta del elemento que necesitas y va directo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8qvvxor1v4szs4tgc5q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd8qvvxor1v4szs4tgc5q.png" alt="Ejemplo de memoria" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En un momento vamos a ver cómo lucen los arrays en código. Por ahora, quédate conmigo para hablar de los tipos de arrays que existen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Arrays estáticos
&lt;/h2&gt;

&lt;p&gt;Los arrays en su forma original son un bloque de memoria contigua con un tamaño fijo. No pueden crecer ni reducirse después de creados. Este tipo de arrays lo vemos en lenguajes como C, donde tú tienes que decirle explícitamente al lenguaje cuántos espacios debe reservarte en la memoria.&lt;/p&gt;

&lt;p&gt;Volviendo a la analogía: la empresa rentó exactamente 5 pisos. Si después necesita un sexto, no hay forma de crecer en el mismo lugar.&lt;/p&gt;

&lt;p&gt;Ventajas: predecible en memoria, sin costo adicional de redimensionamiento.&lt;br&gt;
Limitaciones: Si necesitas más espacio, no puedes agregarlo.&lt;/p&gt;

&lt;p&gt;Este es un ejemplo de cómo se ve un array estático en C:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;my_array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aquí le estamos diciendo a C: "Reserva espacio para exactamente 10 números enteros". Ni más ni menos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Arrays dinámicos
&lt;/h2&gt;

&lt;p&gt;Los arrays dinámicos resuelven la limitación principal de los estáticos: no necesitas saber de antemano cuántos elementos vas a almacenar. Crecen conforme vas insertando elementos.&lt;/p&gt;

&lt;p&gt;¿Cómo funciona esto por debajo? Cuando el array se llena, el lenguaje crea uno nuevo más grande en otra parte de la memoria y copia todos los elementos. Siguiendo la analogía: cuando la empresa necesita más pisos, se muda a un edificio más grande y lleva todo consigo.&lt;/p&gt;

&lt;p&gt;Ventajas: flexibilidad, no necesitas definir un tamaño desde el inicio.&lt;br&gt;
Desventajas: la cantidad de memoria no es predecible y la "mudanza" tiene un costo.&lt;/p&gt;

&lt;p&gt;En lenguajes como JavaScript y Python, los arrays dinámicos vienen integrados por defecto:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En JavaScript no necesitas preocuparte por declarar el tamaño. El lenguaje se encarga de todo por debajo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkbhcu93gm6188ddy0ov7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkbhcu93gm6188ddy0ov7.png" alt="Arrays dinámicos" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Estáticos vs. Dinámicos
&lt;/h2&gt;

&lt;p&gt;Ahora que conoces ambos tipos, aquí va una comparación directa:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Característica&lt;/th&gt;
&lt;th&gt;Array estático&lt;/th&gt;
&lt;th&gt;Array dinámico&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tamaño&lt;/td&gt;
&lt;td&gt;Fijo, definido al crear&lt;/td&gt;
&lt;td&gt;Crece automáticamente&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flexibilidad&lt;/td&gt;
&lt;td&gt;Baja&lt;/td&gt;
&lt;td&gt;Alta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uso de memoria&lt;/td&gt;
&lt;td&gt;Predecible&lt;/td&gt;
&lt;td&gt;Variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Costo de inserción&lt;/td&gt;
&lt;td&gt;No aplica (tamaño fijo)&lt;/td&gt;
&lt;td&gt;O(1) amortizado, O(n) al crecer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lenguajes comunes&lt;/td&gt;
&lt;td&gt;C, C++&lt;/td&gt;
&lt;td&gt;JavaScript, Python, Java (ArrayList)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;En la práctica, la mayoría de lenguajes modernos usan arrays dinámicos por defecto. Pero entender los estáticos te da una mejor perspectiva de lo que sucede por debajo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operaciones comunes
&lt;/h2&gt;

&lt;p&gt;Vamos a platicar sobre lo que puedes hacer con los arrays. Todos los ejemplos están en JavaScript.&lt;/p&gt;

&lt;h3&gt;
  
  
  Acceso por índice
&lt;/h3&gt;

&lt;p&gt;El acceso por índice nos permite seleccionar un elemento a partir de su posición. Como en el elevador: tú sabes directamente a qué piso vas.&lt;/p&gt;

&lt;p&gt;Los arrays tienen una forma particular de numerar sus elementos. Se empieza a contar a partir del 0.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🥸&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;☺️&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👻&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐆&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👾&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐶&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// nos devuelve "🥸"&lt;/span&gt;
&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// nos devuelve "☺️"&lt;/span&gt;
&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// nos devuelve "🐶"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Insertar al final
&lt;/h3&gt;

&lt;p&gt;Podemos insertar elementos al final del array utilizando el método &lt;code&gt;push()&lt;/code&gt;.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🥸&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;☺️&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👻&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐆&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👾&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐶&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👏🏻&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// resultado: ["🥸", "☺️", "👻", "🐆", "👾", "🐶", "👏🏻"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Eliminar el último elemento
&lt;/h3&gt;

&lt;p&gt;Podemos eliminar el último elemento del array con &lt;code&gt;pop()&lt;/code&gt;. Este método además te devuelve el elemento que eliminó.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🥸&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;☺️&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👻&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐆&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👾&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐶&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;eliminado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eliminado&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "🐶"&lt;/span&gt;
&lt;span class="c1"&gt;// resultado: ["🥸", "☺️", "👻", "🐆", "👾"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Obtener longitud
&lt;/h3&gt;

&lt;p&gt;Podemos obtener la longitud de nuestro array con la propiedad &lt;code&gt;length&lt;/code&gt;. Esto nos dice cuántos elementos contiene.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🥸&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;☺️&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👻&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐆&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👾&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐶&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Recorrer los elementos
&lt;/h3&gt;

&lt;p&gt;Algo muy utilizado en los programas es recorrer un array, ya sea para mostrar qué elementos hay dentro o para buscar algún elemento. En JavaScript puedes hacer este recorrido con &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;forEach&lt;/code&gt; o &lt;code&gt;map&lt;/code&gt;.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🥸&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;☺️&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👻&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐆&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👾&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐶&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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;Si te das cuenta, aquí acabamos de utilizar lo que aprendimos en los conceptos anteriores. Usamos el acceso por índice con &lt;code&gt;array[i]&lt;/code&gt;. El &lt;code&gt;for&lt;/code&gt; nos ayuda a repetir algo muchas veces y en nuestro ejemplo, vamos aumentando el valor del índice para ir de izquierda a derecha. Y también usamos &lt;code&gt;.length&lt;/code&gt; para saber cuántos elementos tiene el array.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modificar el inicio del array
&lt;/h3&gt;

&lt;p&gt;Podemos hacer modificaciones al inicio del array o en el medio. El detalle es que estas operaciones requieren pasos adicionales. Déjame explicarte.&lt;/p&gt;

&lt;p&gt;Cuando tienes un array, hablamos de posiciones contiguas en memoria.&lt;/p&gt;

&lt;p&gt;Si insertamos un elemento al inicio, necesitamos desplazar todos los elementos una posición a la derecha para hacer espacio. Primero se mueven los elementos y luego se inserta el nuevo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy5r5appthk1yty38jfph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy5r5appthk1yty38jfph.png" alt="Insertar al inicio" width="800" height="939"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Y al contrario, si eliminamos un elemento del inicio, tenemos que mover todos los elementos que le seguían una posición hacia la izquierda para llenar el hueco.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwttf6mp0perdjoq4q8ni.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwttf6mp0perdjoq4q8ni.png" alt="Eliminar al inicio" width="800" height="752"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esto hace que sea más costoso que insertar o eliminar al final. En JavaScript podemos hacer estas operaciones con &lt;code&gt;unshift()&lt;/code&gt; para insertar al inicio y &lt;code&gt;shift()&lt;/code&gt; para eliminar del inicio.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;☺️&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👻&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐆&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Insertar al inicio&lt;/span&gt;
&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🥸&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// resultado: ["🥸", "☺️", "👻", "🐆"]&lt;/span&gt;

&lt;span class="c1"&gt;// Eliminar del inicio&lt;/span&gt;
&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// resultado: ["☺️", "👻", "🐆"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Costo de las operaciones
&lt;/h2&gt;

&lt;p&gt;Pero no todo es miel sobre hojuelas. Como vimos, es muy fácil trabajar con los arrays pero las operaciones tienen un costo. El costo de las operaciones nos lo indica Big O, una notación matemática que nos ayuda a conocer cuánto tarda una operación a medida que el array crece. Nos ayuda a identificar la mejor estructura de datos para lo que necesitamos.&lt;/p&gt;

&lt;p&gt;En esta tabla te dejo el costo de las operaciones que vimos:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operación&lt;/th&gt;
&lt;th&gt;Complejidad&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Acceso por índice&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Buscar un elemento&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insertar al final&lt;/td&gt;
&lt;td&gt;O(1)*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insertar al inicio&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Eliminar al final&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Eliminar al inicio&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* Amortizado. Ocasionalmente O(n) cuando el array dinámico necesita crecer.&lt;/p&gt;

&lt;p&gt;Las operaciones &lt;code&gt;O(1)&lt;/code&gt; indican que toman tiempo constante. No importa cuántos elementos haya en el array, el tiempo va a ser el mismo. Por eso acceder por índice es tan rápido: tu computadora calcula la dirección exacta y va directo, como el elevador.&lt;/p&gt;

&lt;p&gt;Las operaciones &lt;code&gt;O(n)&lt;/code&gt; quieren decir que toman un tiempo lineal: entre más elementos haya, más tiempo tarda. Por eso insertar al inicio es costoso: hay que mover todos los elementos una posición.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Si quieres saber más sobre Big O y complejidad algorítmica, dime en los comentarios y preparo un artículo dedicado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Construye tu propia implementación de un array
&lt;/h2&gt;

&lt;p&gt;Vamos a construir tu propia implementación de un array. Para este ejercicio debemos asumir que no tenemos los métodos especiales que vimos anteriormente. Vamos a utilizar el acceso por índices para todo.&lt;/p&gt;

&lt;p&gt;Implementaremos los métodos: &lt;code&gt;get(index)&lt;/code&gt;, &lt;code&gt;push(item)&lt;/code&gt;, &lt;code&gt;pop()&lt;/code&gt; y &lt;code&gt;delete(index)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El objetivo es que entiendas qué pasa por debajo cuando usas un array y los métodos que los lenguajes de alto nivel nos proporcionan.&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyArray&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Índice inválido&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;El array está vacío&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;lastItem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Índice inválido&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_shiftItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;_shiftItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="o"&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;Probemos nuestra implementación:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;miArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;miArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🥸&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;miArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;☺️&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;miArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;👻&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;miArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;🐆&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;miArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "🥸"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;miArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "👻"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;miArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// "🐆"&lt;/span&gt;
&lt;span class="nx"&gt;miArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;miArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// "👻"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este código puedes probarlo en &lt;a href="https://runjs.app/play" rel="noopener noreferrer"&gt;RunJS&lt;/a&gt; o de una forma visual en &lt;a href="https://pythontutor.com/visualize.html#mode=edit" rel="noopener noreferrer"&gt;PythonTutor&lt;/a&gt; que tiene soporte para JavaScript y te muestra el paso a paso.&lt;/p&gt;

&lt;p&gt;Fíjate en el método &lt;code&gt;_shiftItems&lt;/code&gt;: ahí puedes ver exactamente por qué eliminar un elemento del inicio o del medio es O(n). Tenemos que recorrer todos los elementos que están después del índice eliminado y moverlos una posición.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Te reto a que implementes el método &lt;code&gt;unshift(item)&lt;/code&gt; para agregar elementos al inicio. Comparte tu solución en los comentarios&lt;/em&gt;. 💪&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Entender los arrays al principio puede ser intimidante. Recuerdo que yo no entendía cómo recorrer un array con &lt;code&gt;for&lt;/code&gt;, pero con la práctica puedes dominarlo.&lt;/p&gt;

&lt;p&gt;Vimos cómo funciona la memoria RAM con la analogía del elevador, los arrays estáticos y los arrays dinámicos. Recuerda que los arrays dinámicos vienen en los lenguajes de alto nivel como Python o JavaScript, así que no debes preocuparte por declarar los elementos que necesitas de antemano. Pero aun así es bueno tener el entendimiento de lo que sucede por debajo. Eso nos da un mayor panorama.&lt;/p&gt;

&lt;p&gt;En el siguiente artículo vamos a cubrir strings como estructura de datos. Y después de eso, vamos a ver patrones de entrevista con arrays y strings.&lt;/p&gt;

&lt;p&gt;Espero que el artículo te sirva. Coméntame si te gustaría que aborde algún tema con mayor profundidad. Gracias por leer. 🙌🏻&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>algorithms</category>
      <category>beginners</category>
      <category>coding</category>
    </item>
    <item>
      <title>Cómo construir un videojuego usando Kiro</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Sat, 14 Mar 2026 02:00:17 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/cavernicolas-dinosaurios-y-codigo-como-construi-un-videojuego-usando-kiro-3ifo</link>
      <guid>https://dev.to/fromchiapasdev/cavernicolas-dinosaurios-y-codigo-como-construi-un-videojuego-usando-kiro-3ifo</guid>
      <description>&lt;p&gt;Quería hacer un videojuego, pero no sabía por dónde empezar. No tenía experiencia en desarrollo de juegos y tampoco estaba familiarizado con los conceptos necesarios. Usé &lt;a href="https://kiro.dev/" rel="noopener noreferrer"&gt;Kiro&lt;/a&gt; y terminé construyendo un clon del dinosaurio de Chrome con un cavernícola huyendo de un T-Rex.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En este artículo te cuento cómo lo hice: los problemas que aparecieron, cómo los resolví y los prompts que usé por si quieres replicarlo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Vibecoding
&lt;/h2&gt;

&lt;p&gt;¿Cómo construyes un juego sin saber hacer juegos? Con vibecoding.&lt;/p&gt;

&lt;p&gt;El vibecoding es una forma de prototipar y darle vida a tus ideas sin seguir una metodología formal. Tú describes lo que quieres y la IA lo construye. No es para producción, pero funciona perfecto para algo que quieres probar rápido.&lt;/p&gt;

&lt;p&gt;El juego lo creé con Kiro, un editor que convierte tus ideas en código. Mi rol fue simple: supervisar que los resultados me gustaran. Yo dirigía; Kiro ejecutaba.&lt;/p&gt;

&lt;h2&gt;
  
  
  La idea
&lt;/h2&gt;

&lt;p&gt;Quería construir una versión del clásico dinosaurio de Chrome. Pero en vez de un dinosaurio saltando cactus, quería un cavernícola huyendo de un T-Rex. Algo con personalidad propia.&lt;/p&gt;

&lt;p&gt;La mecánica:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un cavernícola corre de izquierda a derecha&lt;/li&gt;
&lt;li&gt;Un T-Rex lo persigue desde atrás&lt;/li&gt;
&lt;li&gt;Aparecen obstáculos: cactus que hay que saltar, pterodáctilos que hay que esquivar agachándose&lt;/li&gt;
&lt;li&gt;Cada colisión atrasa al cavernícola y el dinosaurio se acerca&lt;/li&gt;
&lt;li&gt;Si el dinosaurio te alcanza, game over 💀&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conceptos rápidos
&lt;/h2&gt;

&lt;p&gt;Antes de contarte el proceso, quiero repasar tres conceptos para que tengas contexto de lo que hace el código por debajo. Si ya los conoces, salta directo a "El proceso".&lt;/p&gt;

&lt;h3&gt;
  
  
  POO (Programación Orientada a Objetos)
&lt;/h3&gt;

&lt;p&gt;¿Recuerdas esa clase donde veías diagramas UML y hablaban de herencia (lamentablemente no monetaria)? Pues ese paradigma finalmente se usa en algo divertido.&lt;/p&gt;

&lt;p&gt;En los videojuegos, la POO es clave porque cada elemento del juego (el cavernícola, el dinosaurio, los obstáculos) es un objeto con su propio estado y comportamiento. Eso facilita mucho el modelo mental cuando tienes decenas de cosas moviéndose en pantalla. Si quieres un &lt;a href="https://es.wikipedia.org/wiki/Programaci%C3%B3n_orientada_a_objetos" rel="noopener noreferrer"&gt;repaso completo, aquí tienes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Por si no recuerdas, una clase se ve así:&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dino-chase&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;h3&gt;
  
  
  FPS (Frames Per Second)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2kqsj3iyfh9fu1jcl4y.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2kqsj3iyfh9fu1jcl4y.jpeg" alt="FPS ejemplo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Concepto sencillo pero poco entendido. Los FPS son el número de imágenes que tu computadora logra mostrar en un segundo.&lt;/p&gt;

&lt;p&gt;Imagina un cuaderno donde dibujas en cada hoja una secuencia de una persona moviéndose. Cuando pasas las hojas rápido, el dibujo parece cobrar vida. Eso son los FPS.&lt;/p&gt;

&lt;p&gt;Lo más común es 30, 60 y 120 FPS. Cuantos más FPS, más fluidos se sienten los movimientos. Y eso depende mucho del hardware donde se ejecuta el juego.&lt;/p&gt;

&lt;h3&gt;
  
  
  Game Loop
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpwnl9be0jz4t6i392vo9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpwnl9be0jz4t6i392vo9.png" alt="Gameloop diagrama"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El game loop es el corazón de cualquier videojuego. Es un bucle que se repite continuamente y hace tres cosas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Recibe los eventos del usuario (presionar una tecla, mover el mouse)&lt;/li&gt;
&lt;li&gt;Actualiza el estado interno de los personajes y el mapa (por eso necesitamos POO)&lt;/li&gt;
&lt;li&gt;Redibuja la pantalla con las nuevas posiciones, vidas, puntajes, etc.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Este ciclo se repite hasta que el juego termina.&lt;/p&gt;

&lt;h2&gt;
  
  
  El proceso
&lt;/h2&gt;

&lt;p&gt;Aquí es donde se pone interesante. El juego no salió bien a la primera. Ni a la segunda. Fueron varias iteraciones, cada una resolviendo algo que solo descubrí jugando.&lt;/p&gt;

&lt;p&gt;Si quieres replicar lo que hice, puedes usar Kiro. &lt;a href="https://builder.aws.com/content/34X2JujaGkTJed5N2KeMYt1Mz9m/como-comenzar-con-kiro-tu-guia-de-primeros-pasos" rel="noopener noreferrer"&gt;En este tutorial&lt;/a&gt; aprendes a instalar Kiro y, si te registras, obtienes créditos gratis para poder replicar lo que hice. No te vas a gastar ni la mitad de créditos haciendo este juego.&lt;/p&gt;

&lt;h3&gt;
  
  
  0. Preparar el proyecto
&lt;/h3&gt;

&lt;p&gt;Antes del primer prompt necesitas un proyecto de Vite y unos sonidos. Abre tu terminal y corre esto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm create vite@latest game-with-kiro &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--template&lt;/span&gt; vanilla
&lt;span class="nb"&gt;cd &lt;/span&gt;game-with-kiro
pnpm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Después crea la carpeta &lt;code&gt;public/game-assets/audio/&lt;/code&gt; y agrega 3 archivos &lt;code&gt;.wav&lt;/code&gt;. El juego los va a usar para reproducir efectos de sonido cuando el cavernícola salte, choque con un obstáculo o agarre un power-up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;jump.wav&lt;/code&gt; para el sonido de salto&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hitHurt.wav&lt;/code&gt; para cuando te golpeas con algo&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;powerUp.wav&lt;/code&gt; para futuros power-ups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Los sonidos los puedes encontrar en mi &lt;a href="https://github.com/AxelDavid45/building-games-with-kiro" rel="noopener noreferrer"&gt;repositorio&lt;/a&gt;. O puedes generar los tuyos en &lt;a href="https://sfxr.me/" rel="noopener noreferrer"&gt;sfxr.me&lt;/a&gt; en 2 minutos. Es importante que los tengas listos antes de empezar porque en el primer prompt le vamos a decir a Kiro que los use.&lt;/p&gt;

&lt;p&gt;Con eso listo, ya puedes empezar con los prompts.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. El prompt inicial
&lt;/h3&gt;

&lt;p&gt;Este fue el prompt más importante. Le expliqué a Kiro exactamente qué quería construir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Quiero crear un videojuego en el navegador. El juego se trata de un clon del juego que tiene Chrome cuando te quedas sin internet.

Quiero hacer mi versión inspirada en ese juego. Quiero que el dinosaurio persiga a un cavernícola y que con cada obstáculo que no logre esquivar, el cavernícola se retrase por milisegundos para que al dinosaurio le dé tiempo de atraparlo.

Conforme vayas avanzando los obstáculos deben acercarse a ti más rápido pero siempre permitiéndole al jugador esquivarlos.

El diseño del juego es pixel art minimalista, usando solo tonos de gris. El juego usa la tecla espaciadora o las flechas del teclado.
Los obstáculos son infinitos: cactus en el suelo y pterodáctilos volando donde el cavernícola tenga que agacharse o saltarlos.

Consideraciones:
- Utiliza los sonidos que tengo en la carpeta public/game-assets/audio/
- Todo el trabajo debe ser hecho en la carpeta src/
- Utilizamos Vite
- Utilizamos pnpm
- Los sprites deben ser dibujados con canvas no usar imágenes externas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kiro creó todo el proyecto. Corrí &lt;code&gt;pnpm dev&lt;/code&gt;, abrí &lt;code&gt;http://localhost:5173&lt;/code&gt; y ya había algo funcionando.&lt;/p&gt;

&lt;p&gt;¿Pero fue suficiente? No del todo.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Simplificar el fondo
&lt;/h3&gt;

&lt;p&gt;El primer problema que encontré: el fondo tenía demasiados elementos. Volcanes, gradientes, parallax. Se veía laggeado y no se sentía como el juego original.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;El fondo se ve laggeado con cada actualización. Mantenlo minimalista como el juego original de Chrome: fondo gris claro sólido, nubes simples, una línea de suelo. Sin volcanes ni parallax complejo.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Los obstáculos tardaban mucho en aparecer
&lt;/h3&gt;

&lt;p&gt;El juego se sentía aburrido. Pasaban segundos sin que apareciera nada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Necesito que los obstáculos no tarden tanto en aparecer. Que a veces haya que saltar obstáculos seguidos o agacharse para que sea un poco más difícil.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con eso ya se sentía como un juego de verdad.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Obstáculos imposibles de esquivar
&lt;/h3&gt;

&lt;p&gt;A veces aparecían dos obstáculos encimados, o uno aparecía justo cuando estaba cayendo de un salto. Imposible esquivarlos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tenemos un bug: cuando el cavernícola salta, a veces aparece un obstáculo tan cerca que ya no me permite saltar de nuevo y me cuenta como un golpe. Además dos obstáculos aparecen al mismo tiempo. Necesito que eso se arregle.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kiro cambió el sistema de spawn para usar distancia mínima entre obstáculos en vez de tiempo. Mucho mejor.&lt;/p&gt;

&lt;p&gt;Pero algo seguía sintiéndose raro. 🤔&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Mejorar la respuesta de los controles
&lt;/h3&gt;

&lt;p&gt;Este fue un momento clave. Presionaba saltar en el momento correcto, pero el juego no respondía porque el cavernícola todavía estaba en el aire del salto anterior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Implementa un input buffer porque cuando aparecen combos parece que no logra saltar los obstáculos aunque yo le aplaste la tecla en el tiempo adecuado.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kiro implementó dos técnicas clásicas de platformers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input Buffer (150ms): Si presionas saltar mientras estás en el aire, el juego recuerda ese input y salta automáticamente cuando aterrices.&lt;/li&gt;
&lt;li&gt;Coyote Time (80ms): Tienes una ventana pequeña para saltar incluso después de empezar a caer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esto hizo que el juego se sintiera responsivo. Los combos de obstáculos ahora sí se podían esquivar.&lt;/p&gt;

&lt;p&gt;Perfecto. La mecánica básica ya funcionaba. Pero faltaba algo para competir con amigos.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. El contador y high score
&lt;/h3&gt;

&lt;p&gt;Sin puntaje no hay competencia.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Implementa el counter del juego con high score guardado en localStorage. El formato debe ser de 5 dígitos como el juego original de Chrome.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora sí podía retar a mis amigos.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. El efecto dominó
&lt;/h3&gt;

&lt;p&gt;Este fue el bug más difícil. Me tomó varias iteraciones resolverlo.&lt;/p&gt;

&lt;p&gt;El problema era un ciclo vicioso:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Chocas con un obstáculo → el cavernícola se atrasa&lt;/li&gt;
&lt;li&gt;Al atrasarte, el siguiente obstáculo ya está encima tuyo&lt;/li&gt;
&lt;li&gt;Chocas de nuevo → te atrasas más&lt;/li&gt;
&lt;li&gt;Se repite hasta game over&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Era injugable. Le pedí esto a Kiro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Si choco varias veces es imposible sortear los objetos siguientes porque queda muy cerca de ellos. Necesito que al colisionar se limpien los obstáculos cercanos y haya un periodo de inmunidad para recuperarse.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La solución combinó varias técnicas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inmunidad de 500ms después de cada colisión&lt;/li&gt;
&lt;li&gt;Limpieza de obstáculos en un radio de 250px al colisionar&lt;/li&gt;
&lt;li&gt;Recuperación de posición más rápida, proporcional a la velocidad del juego&lt;/li&gt;
&lt;li&gt;Spawn basado en la posición del jugador, no del borde del canvas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ahora tocaba preocuparme del dinosaurio.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Balancear al dinosaurio
&lt;/h3&gt;

&lt;p&gt;El T-Rex alcanzaba al cavernícola demasiado rápido, incluso sin colisiones. La presión tenía que venir de mis errores, no del paso del tiempo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;El dinosaurio alcanza al cavernícola muy rápido. Haz que empiece más atrás y avance más lento. La presión debe venir de las colisiones, no del avance natural del dinosaurio.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kiro redujo la velocidad de avance del dinosaurio de &lt;code&gt;0.2&lt;/code&gt; a &lt;code&gt;0.08&lt;/code&gt;. Ahora la tensión viene de tus errores, no del reloj.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Pterodáctilos a dos alturas
&lt;/h3&gt;

&lt;p&gt;Para darle más variedad, agregué pterodáctilos a diferentes alturas. Unos que hay que saltar y otros donde hay que agacharse.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Quiero que haya pterodáctilos a dos alturas: altos donde hay que agacharse y bajos donde hay que saltar. Asegúrate de que las figuras estén bien calibradas para que ambas acciones funcionen a cualquier velocidad del juego.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Estructura final del proyecto
&lt;/h2&gt;

&lt;p&gt;Después de todas las iteraciones, la estructura quedó así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;├── src/&lt;/span&gt;
&lt;span class="s"&gt;│   ├── main.js&lt;/span&gt;          &lt;span class="c1"&gt;# Entry point, pantallas inicio/game over&lt;/span&gt;
&lt;span class="s"&gt;│   ├── game.js&lt;/span&gt;          &lt;span class="c1"&gt;# Game loop, colisiones, score, renderizado&lt;/span&gt;
&lt;span class="s"&gt;│   ├── caveman.js&lt;/span&gt;       &lt;span class="c1"&gt;# Jugador: salto, agacharse, input buffer, inmunidad&lt;/span&gt;
&lt;span class="s"&gt;│   ├── dinosaur.js&lt;/span&gt;      &lt;span class="c1"&gt;# Enemigo perseguidor&lt;/span&gt;
&lt;span class="s"&gt;│   ├── obstacles.js&lt;/span&gt;     &lt;span class="c1"&gt;# Manager + CactusSmall, CactusBig, Pterodactyl&lt;/span&gt;
&lt;span class="s"&gt;│   ├── background.js&lt;/span&gt;    &lt;span class="c1"&gt;# Nubes y decoraciones del suelo&lt;/span&gt;
&lt;span class="s"&gt;│   ├── audio.js&lt;/span&gt;         &lt;span class="c1"&gt;# Gestión de sonidos&lt;/span&gt;
&lt;span class="s"&gt;│   └── style.css&lt;/span&gt;        &lt;span class="c1"&gt;# Estilos de UI&lt;/span&gt;
&lt;span class="s"&gt;├── public/game-assets/&lt;/span&gt;
&lt;span class="s"&gt;│   └── audio/&lt;/span&gt;           &lt;span class="c1"&gt;# Archivos .wav&lt;/span&gt;
&lt;span class="s"&gt;├── index.html&lt;/span&gt;
&lt;span class="s"&gt;└── package.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Lo que aprendí
&lt;/h2&gt;

&lt;p&gt;No sabía hacer un videojuego. No sabía qué conceptos necesitaba ni por dónde empezar. Con ayuda de la IA logré construir algo que de otra forma me hubiera tomado semanas de investigación, y probablemente lo hubiera abandonado por frustración.&lt;/p&gt;

&lt;p&gt;Pero aquí viene el detalle: la IA no lo hizo sola. Fueron 9 iteraciones. Cada una requirió que yo jugara, identificara problemas y supiera explicar qué estaba mal. La IA ejecuta, pero tú diriges.&lt;/p&gt;

&lt;p&gt;Si estás estudiando programación y sientes que la IA viene a dejarte sin oportunidades, no pienses eso. Aprende a usarla. Empodérate con ella. Ahora puedes crear ideas más rápido y dedicarle tiempo a lo que realmente importa: entender los fundamentos.&lt;/p&gt;

&lt;p&gt;Ojo, es importante que, aunque la IA escriba el código, tú seas capaz de leerlo y modificarlo cuando algo salga mal. Porque todavía no es perfecta.&lt;/p&gt;

&lt;p&gt;Sigue aprendiendo y no le tengas miedo a la IA. Úsala como lo que es: una herramienta que amplifica lo que ya sabes y una aliada para aprender construyendo.&lt;/p&gt;




&lt;p&gt;Si te animas a hacer tu propia versión, déjame el link a tu repositorio en los comentarios o puedes escribirme en &lt;a href="https://www.linkedin.com/in/axelespinosa/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; si tienes alguna duda.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;También te dejo el link al repositorio de mi juego 👉 &lt;a href="https://github.com/AxelDavid45/building-games-with-kiro" rel="noopener noreferrer"&gt;Repositorio con juego&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>kiro</category>
      <category>ai</category>
      <category>programming</category>
      <category>español</category>
    </item>
    <item>
      <title>¿Qué es un encoding? Explicación sencilla: ASCII, UTF-8 y Unicode</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Thu, 19 Feb 2026 20:58:11 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/encodings-por-que-importan-mas-de-lo-que-crees-41a5</link>
      <guid>https://dev.to/fromchiapasdev/encodings-por-que-importan-mas-de-lo-que-crees-41a5</guid>
      <description>&lt;p&gt;La forma en que nos comunicamos digitalmente ha cambiado muchísimo. Hoy nos comunicamos hasta con stickers, pero ¿alguna vez te has preguntado cómo llegamos hasta aquí?&lt;/p&gt;

&lt;p&gt;Seguramente navegando por internet te has encontrado con textos que muestran caracteres extraños como este: &lt;code&gt;M�xico&lt;/code&gt;&lt;br&gt;
Eso tiene un nombre: &lt;a href="https://en.wikipedia.org/wiki/Mojibake" rel="noopener noreferrer"&gt;Mojibake&lt;/a&gt;. Así se le llama al fenómeno de ver caracteres raros cuando hay un error en la codificación del texto. &lt;/p&gt;

&lt;p&gt;En este artículo te explico a detalle qué es la codificación, con ejemplos claros y sencillos.&lt;/p&gt;
&lt;h2&gt;
  
  
  Encodings
&lt;/h2&gt;

&lt;p&gt;El encoding (o en español, codificación) es el proceso de transformar la información de una representación a otra siguiendo reglas específicas. En este contexto, nos enfocaremos en la codificación de caracteres: cómo se representan letras, números y símbolos en formato digital.&lt;/p&gt;

&lt;p&gt;Me imagino que has escuchado que las computadoras solamente entienden &lt;a href="https://es.wikipedia.org/wiki/Sistema_binario" rel="noopener noreferrer"&gt;números binarios: 0 y 1&lt;/a&gt;. Esto es cierto, pero imagina si tuviéramos que usar únicamente esos números para comunicarnos con ellas todos los días. Por eso, los investigadores desarrollaron sistemas que nos facilitan esta comunicación. &lt;/p&gt;

&lt;p&gt;Te muestro un ejemplo con mi nombre. Sería impráctico tener que escribirlo usando solo ceros y unos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhwj04xoc2z6qmojd26x.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhwj04xoc2z6qmojd26x.jpg" alt="Mi nombre en binario" width="800" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Son demasiados números, ¿cierto? ¿Cómo pasamos de letras a un montón de números?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preguntas muy buenas, ser, joven Padawan&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Retrocedamos un paso. Entendamos primero de dónde salieron esos números. Te presento a ASCII.&lt;/p&gt;
&lt;h2&gt;
  
  
  ASCII
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/ASCII" rel="noopener noreferrer"&gt;ASCII&lt;/a&gt; son las siglas de &lt;strong&gt;American Standard Code for Information Interchange&lt;/strong&gt;. Es un estándar que nos dice cómo deben representarse las letras como números para que las computadoras lo entiendan y nosotros también podamos entenderlo. &lt;/p&gt;

&lt;p&gt;La primera versión de este estándar fue creada en 1963 y hasta hoy en día sigue siendo importante conocer que existe, porque es fácil de usar y los fabricantes de computadoras se encargan de que todas las PCs entiendan este formato.&lt;/p&gt;

&lt;p&gt;Podemos encontrar la tabla ASCII que muestra cada letra del idioma inglés con un valor en decimal, hexadecimal y binario. Es por eso que pude transformar mi nombre a números binarios: porque cada letra cuenta con un valor que las computadoras pueden entender. &lt;/p&gt;

&lt;p&gt;Te dejo los caracteres que usé:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvduapin1dhvgno8uuxn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvduapin1dhvgno8uuxn.jpg" alt="ASCII Códigos" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La codificación ASCII solo nos provee de 127 caracteres, lo que equivale a 7 bits (2^7). &lt;strong&gt;Esto es importante porque la computadora utiliza 1 byte (8 bits) para poder almacenar un carácter, es decir, que se está desperdiciando un bit.&lt;/strong&gt; &lt;strong&gt;Y precisamente de eso se dieron cuenta los investigadores, así que después decidieron extender esta tabla de caracteres a 256. Ahora un carácter podía utilizar hasta 8 bits, o lo que es igual a 1 byte completo.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Esta expansión fue clave para que otros países con idiomas y alfabetos diferentes al inglés pudieran usar la codificación sin problemas de compatibilidad.&lt;/p&gt;

&lt;p&gt;Pero aquí viene el detalle: 256 caracteres no son suficientes cuando tienes que representar chino, árabe, cirílico y todos los demás alfabetos del mundo. Cada fabricante empezó a inventar su propia solución, y ahí es donde empezó el problema de &lt;code&gt;M├®xico&lt;/code&gt; que viste arriba. La solución a este caos fue Unicode. &lt;/p&gt;
&lt;h2&gt;
  
  
  Unicode
&lt;/h2&gt;

&lt;p&gt;Unicode se creó en los años 80 y se convirtió en un estándar hoy en día que define más de 1.1 millones de caracteres. Este estándar asigna a cada carácter un código que después, con ayuda de un encoding, se transforma a bits (lo que realmente la computadora entiende). Y no solamente se trata de letras: los emojis también están dentro de Unicode y por eso podemos utilizarlos en cualquier idioma. &lt;/p&gt;

&lt;p&gt;La idea principal de Unicode es evitar que cada fabricante de hardware cree su propio encoding incompatible con los demás. Así, un fabricante en Europa que usa caracteres distintos al inglés puede compartir información con alguien en Asia o en América, evitando el caos de &lt;code&gt;M├®xico&lt;/code&gt; que vimos antes.&lt;/p&gt;

&lt;p&gt;Los códigos Unicode están definidos con un formato hexadecimal y se ven así:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsxsxg7v84x8dquyv7b4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzsxsxg7v84x8dquyv7b4.jpg" alt="Unicode codes" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si ves esto y no sabes qué es hexadecimal, te dejo un link a un artículo: &lt;a href="https://en.wikipedia.org/wiki/Hexadecimal" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Hexadecimal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Listo. Ya conocemos Unicode y por qué es importante, pero esto solo nos da una pequeña porción del panorama completo. Recuerda que la computadora solo entiende bits, entonces, ¿cómo pasamos de estos códigos hexadecimales a bits? Aquí es donde entra UTF-8 🙌🏻&lt;/p&gt;
&lt;h2&gt;
  
  
  UTF-8 👾
&lt;/h2&gt;

&lt;p&gt;UTF-8 es un encoding creado por el consorcio Unicode (los mismos que crearon el estándar Unicode) y se encarga de transformar los códigos hexadecimales a bits que la computadora pueda entender. &lt;/p&gt;

&lt;p&gt;Algo muy inteligente de UTF-8 es que fue diseñado desde el inicio para ser compatible con ASCII. Los primeros 128 códigos tienen una traducción idéntica, es decir, se conservan los códigos ASCII. Por ejemplo, la letra &lt;code&gt;A&lt;/code&gt; en ASCII es 65 (en decimal) y en UTF-8 también es 65. &lt;/p&gt;

&lt;p&gt;Esto permitió que programas que ya usaban ASCII funcionaran automáticamente con UTF-8, lo que mejoró la adopción y ahora UTF-8 sea el encoding más popular en la web. &lt;/p&gt;

&lt;p&gt;UTF-8 utiliza una transformación dinámica a bits: caracteres simples ocupan solo 1 byte, mientras que caracteres más complejos —con múltiples formas, diacríticos, etc.— pueden ocupar hasta 4 bytes.&lt;/p&gt;

&lt;p&gt;Por ejemplo, este emoji 👾 ocupa 4 bytes completos, mientras que la letra &lt;code&gt;A&lt;/code&gt; solo necesita 1 byte:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvcbcmli0y3t37j6abk7s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvcbcmli0y3t37j6abk7s.jpg" alt="Tamaño de emoji" width="554" height="182"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Charset y Encoding
&lt;/h2&gt;

&lt;p&gt;Perfecto. Ya sabes cómo funcionan ASCII, Unicode y UTF-8. Pero hay una distinción importante que te ayudará a entender todo el panorama: &lt;strong&gt;charset vs encoding.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cuando trabajas con bases de datos o creas un documento HTML, seguro has visto una etiqueta o configuración llamada &lt;strong&gt;charset&lt;/strong&gt;. Esto se refiere al &lt;strong&gt;catálogo de caracteres&lt;/strong&gt; que puedes usar en ese documento y que se mostrarán correctamente en pantalla. Es decir, qué caracteres están “permitidos” o “disponibles”. &lt;/p&gt;

&lt;p&gt;El &lt;strong&gt;encoding,&lt;/strong&gt; por otro lado, es la forma en que esos caracteres se transforman a bits para ser almacenados o transmitidos. &lt;/p&gt;
&lt;h3&gt;
  
  
  ¿Por qué importa?
&lt;/h3&gt;

&lt;p&gt;Si no trabajas con el mismo charset en documentos compartidos, terminas con el problema que vimos antes: caracteres rotos, símbolos raros y texto ilegible. &lt;/p&gt;
&lt;h2&gt;
  
  
  Ejemplo práctico
&lt;/h2&gt;

&lt;p&gt;Imagina que creas un archivo de texto con este contenido:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;México
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creamos el archivo en nuestra computadora y verificamos su encoding con el comando &lt;a href="https://man7.org/linux/man-pages/man1/file.1.html" rel="noopener noreferrer"&gt;file&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"México"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; test.txt
~ file &lt;span class="nt"&gt;-I&lt;/span&gt; test.txt
test.txt: text/plain&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;utf-8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfecto, está en UTF-8. Ahora intentemos convertirlo a un encoding que no soporte acentos, como &lt;code&gt;ISO-8859-10&lt;/code&gt; (diseñado para idiomas nórdicos: sueco, noruego, danés).&lt;/p&gt;

&lt;p&gt;Usamos la herramienta &lt;a href="https://man7.org/linux/man-pages/man1/iconv.1.html" rel="noopener noreferrer"&gt;&lt;code&gt;iconv&lt;/code&gt;&lt;/a&gt; para transformar el encoding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ iconv &lt;span class="nt"&gt;-f&lt;/span&gt; UTF-8 &lt;span class="nt"&gt;-t&lt;/span&gt; ISO-8859-10 test.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; converted.txt

~ &lt;span class="nb"&gt;cat &lt;/span&gt;converted.txt
M�xico
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¿Qué pasó? 😳 El archivo ahora contiene caracteres raros donde debería estar la “é”. La terminal no puede mostrarlo bien, pero un editor de texto sí revela el problema:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pc3zjet3e62i3fsj4ad.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pc3zjet3e62i3fsj4ad.jpg" alt="Transformación erronea" width="568" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nuestro archivo original estaba en UTF-8, donde la “é” tiene un código específico. Al convertirlo en ISO-8859-10, &lt;code&gt;iconv&lt;/code&gt; intentó encontrar un equivalente... pero no es lo mismo, por eso se ve raro.&lt;/p&gt;

&lt;p&gt;Ahora, si intentamos convertirlo a ASCII (que en teoría es compatible con UTF-8), vemos que directamente no puede manejar el acento porque en el charset ASCII no existen letras con acento como sí existen en Unicode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ iconv &lt;span class="nt"&gt;-f&lt;/span&gt; UTF-8 &lt;span class="nt"&gt;-t&lt;/span&gt; ASCII &lt;span class="nt"&gt;-c&lt;/span&gt;  test.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; converted.txt
iconv: warning: invalid characters: 1
~ &lt;span class="nb"&gt;cat &lt;/span&gt;converted.txt
Mxico
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Incluso si abres el editor, verás que no se logró transformar la segunda letra:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54vvk8tmwe55iswg4msi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54vvk8tmwe55iswg4msi.jpg" alt="Transformación: elimina una letra" width="516" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La letra “é” simplemente desapareció. Para verificar que el nuevo archivo tiene otro encoding, ejecutamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~ file &lt;span class="nt"&gt;-I&lt;/span&gt; converted.txt
converted.txt: text/plain&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-ascii
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahí está: ahora es &lt;code&gt;us-ascii&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ejemplo en programación
&lt;/h2&gt;

&lt;p&gt;Listo. Ya entendemos la diferencia entre charset y encoding. ¿Pero cómo nos ayuda esto al programar?&lt;br&gt;
Imagina este problema:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Valida si una cadena de texto contiene únicamente caracteres A-Z y dígitos 0-9"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Para resolverlo, vamos a asumir que la cadena de texto es pequeña y trabajaremos con los códigos ASCII:&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;containsOnlyLettersAndNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Evaluating s[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]= &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt; charcode=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;122&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;57&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;97&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;containsOnlyLettersAndNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AUDID3222&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// TRUE&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;containsOnlyLettersAndNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;D444E##RUURUJ&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// FALSE&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;containsOnlyLettersAndNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;asbueu3$&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// FALSE&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;containsOnlyLettersAndNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;asbueu3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// TRUE&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este código puedes probarlo con herramientas como &lt;a href="https://runjs.app/play" rel="noopener noreferrer"&gt;RunJS&lt;/a&gt; o de una forma visual con un editor que te muestra el paso a paso que tiene soporte para Javascript: &lt;a href="https://pythontutor.com/visualize.html#mode=edit" rel="noopener noreferrer"&gt;PythonTutor&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Y así llegamos al final. En este artículo vimos cómo funcionan los encodings, por qué un emoji puede ocupar 4 bytes y ejemplos prácticos de transformaciones entre charsets.&lt;/p&gt;

&lt;p&gt;Reacciona:&lt;br&gt;
❤️ Sí, ya lo conocías&lt;br&gt;
🔥 Si te sorprendió algo&lt;br&gt;
💬 Y cuéntame qué fue lo que más te llamó la atención&lt;/p&gt;

&lt;p&gt;Si crees que me faltó algo importante, déjamelo en los comentarios. Te estaré leyendo. 👇&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Write better unit tests</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Wed, 28 May 2025 18:31:11 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/10x-improvement-in-unit-tests-4g5j</link>
      <guid>https://dev.to/fromchiapasdev/10x-improvement-in-unit-tests-4g5j</guid>
      <description>&lt;p&gt;Hello, welcome to a new post!&lt;/p&gt;

&lt;p&gt;Today I want to talk about a very important topic that should never be missing in serious software development: unit tests.&lt;/p&gt;

&lt;p&gt;Unit tests are code we write to validate the logic of our program. These tests are characterized by evaluating small parts of the code, such as a function or a class.&lt;/p&gt;

&lt;p&gt;Additionally, unit tests are very useful when refactoring code in the future, as they help ensure that what previously worked correctly continues to do so.&lt;/p&gt;

&lt;p&gt;And really, I think we've all worked on a project where the team is afraid to change certain parts of the code, because we don't know if the changes will affect previously implemented business rules, causing strange behavior and those dreaded bugs.&lt;/p&gt;

&lt;p&gt;The goal of these tests is to give you confidence in what you write and help you deliver as few bugs as possible. However, sometimes projects already have unit tests—maybe even an extensive suite—but simply having them doesn't guarantee you're covered. This happens when tests are outdated or have just been patched with each change, written only to make them pass and keep the CI process quiet, allowing work to continue without interruption.&lt;/p&gt;

&lt;p&gt;This is a clear symptom that your unit tests have become a burden, and the whole team sees them that way. Writing tests becomes a tedious task with no reward. And in these cases, it's true: the tests just slow down development.&lt;/p&gt;

&lt;p&gt;We can avoid this situation by changing our perspective: unit tests are a part of the system and must be treated with the same care as the main codebase.&lt;/p&gt;

&lt;p&gt;Just because they don’t run in production doesn’t mean they should be forgotten after being written once. They must be maintained attentively, updated consciously—not just to keep the report green. For example, if you delete a method or class, you should remove the related tests. If a business rule changes, it's normal for tests to fail at first—but they must be updated to reflect the new logic. Don’t hide the real problem with hacks to make the test pass, and definitely don’t comment it out or delete it.&lt;/p&gt;

&lt;p&gt;Since unit tests are so important, here are some tips I've learned that can help you improve them and feel more confident in your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer: Unit tests alone don’t cover the whole system. It’s important to complement them with other types of tests like E2E, manual QA tests (if you have a QA team), and more. Still, unit tests are our first line of defense when making changes.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Tools&lt;/li&gt;
&lt;li&gt;How to name your subject under test&lt;/li&gt;
&lt;li&gt;Write a clear message for your test&lt;/li&gt;
&lt;li&gt;How to avoid test fragility&lt;/li&gt;
&lt;li&gt;What are mocks and when to use them&lt;/li&gt;
&lt;li&gt;How much code coverage should I aim for?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tools
&lt;/h2&gt;

&lt;p&gt;In these examples, I'll use &lt;strong&gt;JavaScript&lt;/strong&gt;, but the concepts are language-agnostic. JavaScript is just a tool to communicate the ideas.&lt;/p&gt;

&lt;p&gt;JavaScript has popular libraries you can use to create tests. But first, it’s important to understand the difference between a &lt;strong&gt;Test Runner&lt;/strong&gt; and an &lt;strong&gt;Assertion Library&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Test Runner&lt;/strong&gt; provides the infrastructure to execute tests in isolation (sometimes even in parallel), along with debugging utilities and more. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Jest&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mocha&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Assertion Libraries&lt;/strong&gt; may be included with the test runner (as with Jest) or installed separately. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chai&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assert Module&lt;/strong&gt; (built-in with Node.js ≥ v18)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tools give you functions to validate whatever you need: an object’s content, a date, a string, etc.&lt;/p&gt;

&lt;p&gt;Here’s an example:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;node:assert/strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deepEqual&lt;/span&gt;&lt;span class="p"&gt;([[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="c1"&gt;// AssertionError: Expected inputs to be strictly deep-equal:&lt;/span&gt;
&lt;span class="c1"&gt;// + actual - expected ...&lt;/span&gt;
&lt;span class="c1"&gt;// +     3&lt;/span&gt;
&lt;span class="c1"&gt;// -     '3'&lt;/span&gt;
&lt;span class="c1"&gt;// Example from Nodejs Docs https://nodejs.org/docs/latest-v22.x/api/assert.html#assert&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we expect both arrays to have the same elements.&lt;/p&gt;

&lt;p&gt;You might ask, "Do I really need these libraries if I can do it manually?" And the answer is: yes and no. You could write your own validation methods, or you could save time by using a library that works out of the box.&lt;/p&gt;

&lt;p&gt;To get started, you’ll need to know how to configure these tools. It’s not difficult—the documentation is usually more than enough. Personally, I use &lt;strong&gt;Jest&lt;/strong&gt; in my projects because it comes by default with &lt;strong&gt;NestJS&lt;/strong&gt;, and it includes an assertion library.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Name Your Subject Under Test
&lt;/h2&gt;

&lt;p&gt;The subject under test is often referred to as the &lt;strong&gt;SUT&lt;/strong&gt; (&lt;em&gt;System Under Test&lt;/em&gt;). I liked this naming convention when I read about it in the book &lt;em&gt;Unit Testing&lt;/em&gt;, and I’ve adopted it ever since. It makes it clear what component is being tested and avoids confusion with other variables in the test.&lt;/p&gt;

&lt;p&gt;Of course, this is just a personal preference. You’re free to name it however you like, but always try to make it obvious which part of the system you’re testing.&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;// sum.js&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&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;span class="c1"&gt;// sum.spec.js&lt;/span&gt;
&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Calculator&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;SUT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// System Under Test&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&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;SUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;afterEach&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Write a Clear Message for Your Test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// validations&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&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;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EmailSender&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;SUT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;beforeEach&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;SUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;afterEach&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="c1"&gt;// ❌ Not descriptive&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test method send()&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

  &lt;span class="c1"&gt;// ✅ Clear descriptions&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;send(): fails with invalid email&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;send(): fails with invalid content&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="o"&gt;=&amp;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;In the example above, we see that we can name our tests however we want, but in the end, we’re the ones affected by poorly described messages—either us or our teammates.&lt;/p&gt;

&lt;p&gt;Imagine someone new joins the project, changes the &lt;code&gt;EmailSender&lt;/code&gt; class, and a test fails. The only message shown is: &lt;code&gt;test method send()&lt;/code&gt;. You’d pull your hair out trying to understand what it does and how to fix it.&lt;/p&gt;

&lt;p&gt;On the other hand, if tests are clearly described—as in the later examples—you quickly get an idea of what might have failed, making the debugging experience much more pleasant.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Avoid Fragility in Your Tests
&lt;/h2&gt;

&lt;p&gt;There’s an approach that can greatly improve your tests and help avoid fragility, false positives, and difficulties when refactoring.&lt;/p&gt;

&lt;p&gt;Often, writing tests reveals how well we’ve applied best practices. This is because when we test our code, we should aim to isolate that unit as much as possible from the rest of the system.&lt;/p&gt;

&lt;p&gt;What this means is: if your function or class relies on external resources like APIs or other classes—and you depend on concrete implementations instead of abstractions—you’re introducing fragility. Any updates to those dependencies might cause your tests to fail for reasons unrelated to the logic you’re actually testing. These false positives, if not addressed, make tests unsustainable.&lt;/p&gt;

&lt;p&gt;If you depend on abstractions instead, testing a component with dependencies becomes much simpler. You can replace those dependencies easily and focus on what really matters: your business rules, algorithms, and logic.&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;// BAD: Depends on a concrete class&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SNSAWSService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// concrete class dependency&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// validations&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SNSServiceAws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&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;span class="c1"&gt;// GOOD: Uses dependency inversion, easier to test&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// abstraction&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// validations&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&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;We can solve this by using &lt;strong&gt;dependency injection&lt;/strong&gt; and applying the SOLID principle of &lt;strong&gt;Dependency Inversion&lt;/strong&gt;, which tells us to depend on abstractions—in this case, an interface.&lt;/p&gt;

&lt;p&gt;Another thing that helped me a lot is shifting my perspective: I now focus on &lt;strong&gt;testing what I want the code to do&lt;/strong&gt;, the &lt;strong&gt;outcome&lt;/strong&gt;, instead of worrying about &lt;strong&gt;how&lt;/strong&gt; it’s done.&lt;/p&gt;

&lt;p&gt;This change makes a big difference. It allows you to ignore implementation details (like exact algorithm steps) and focus on verifying that the &lt;strong&gt;desired result&lt;/strong&gt; is correct. When you reflect that in your tests, you achieve greater &lt;strong&gt;robustness&lt;/strong&gt; and &lt;strong&gt;resilience to change&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Don’t waste time testing implementation details that may change. Your goal is to ensure the system behaves as expected from a functional perspective. This leads to more stable and meaningful tests in the long term.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Mocks and When to Use Them?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Mocks&lt;/em&gt; are, colloquially, functions or classes that replace real dependencies in our tests. Their purpose is to help isolate the code and prevent the use of real services.&lt;/p&gt;

&lt;p&gt;Imagine you need to send an email, an SMS, etc. A good practice would be to &lt;strong&gt;avoid using the real services&lt;/strong&gt; for several reasons: cost, accidentally notifying real users, and because it’s much easier to replace them to have full control over what happens in your code.&lt;/p&gt;

&lt;p&gt;Without &lt;em&gt;mocks&lt;/em&gt;, tests would be too unpredictable, since they would depend on external components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jest&lt;/strong&gt; provides built-in methods to create &lt;em&gt;mocks&lt;/em&gt; and &lt;em&gt;spies&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The difference between them is that &lt;em&gt;spies&lt;/em&gt; allow you to track calls made to the &lt;em&gt;mock&lt;/em&gt;—you can check what arguments were passed, how many times it was called, in what order, and so on.&lt;/p&gt;

&lt;h3&gt;
  
  
  One Important Note Before the Example:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;You don’t always need to make assertions on your mocks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is because, in many cases, it's not relevant to the logic you're testing. Also, making unnecessary assertions can introduce fragility into your tests, since &lt;em&gt;mocks&lt;/em&gt; simulate external dependencies that may change over time.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;it does make sense to assert on mocks when they are relevant to business rules&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example: if your application must send an email when a user is created, it's important to verify that the email service was called—and with the correct data.&lt;/p&gt;

&lt;p&gt;This helps you confirm that your code is truly executing the key actions that matter to your business.&lt;/p&gt;

&lt;p&gt;Now, let’s look at an example:&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;// notification.test.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;emailService&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./emailService.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;notifyNewUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./notification.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;beforeEach&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="c1"&gt;// Restore original behavior&lt;/span&gt;
  &lt;span class="nx"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mockRestore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notifyNewUser: sends a welcome email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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="c1"&gt;// Spy on sendEmail and prevent real call&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sendEmail&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="nf"&gt;mockResolvedValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spy-ok&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;user&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;u@e.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Axel&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;SUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;notifyNewUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Verify parameters and return value&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;u@e.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Welcome!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hi Axel, thanks for joining.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spy-ok&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Code Coverage
&lt;/h2&gt;

&lt;p&gt;Lastly, when it comes to code coverage, I believe having a test suite that covers around &lt;strong&gt;80% of your code&lt;/strong&gt; is a very good goal.&lt;/p&gt;

&lt;p&gt;But we must keep in mind that setting a number shouldn't distract us from what truly matters: &lt;strong&gt;taking care of the quality of our tests&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's not about hitting or exceeding a specific percentage—it's about &lt;strong&gt;writing meaningful tests&lt;/strong&gt;. And as a natural consequence of doing so, you'll likely hit that coverage mark anyway, or get very close to it.&lt;/p&gt;

&lt;p&gt;It’s also important to listen to the team, understand their perspective, and find a way for everyone to feel comfortable. Because when a strict percentage is enforced, the team may focus solely on reaching it, writing tests that add little to no value.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you’ve made it this far, I hope you’ve taken something useful that you can start applying right away.&lt;/p&gt;

&lt;p&gt;Writing good unit tests takes &lt;strong&gt;practice and consistency&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Personally, I’m still learning how to improve my own tests, but applying the principles I shared here has definitely helped me improve the quality of my code and avoid many false positives.&lt;/p&gt;

&lt;p&gt;If you have any feedback or want to connect, feel free to reach out on &lt;a href="https://www.linkedin.com/in/axelespinosa/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://x.com/im_not_ajscoder" rel="noopener noreferrer"&gt;X (Twitter)&lt;/a&gt; as &lt;a href="https://x.com/im_not_ajscoder" rel="noopener noreferrer"&gt;@im_not_ajscoder&lt;/a&gt; or in the comments 🙌🏻&lt;/p&gt;

</description>
      <category>testing</category>
      <category>discuss</category>
      <category>javascript</category>
      <category>learning</category>
    </item>
    <item>
      <title>Mejora tus pruebas unitarias 10x</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Tue, 27 May 2025 22:20:06 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/mejora-tus-pruebas-unitarias-10x-44ff</link>
      <guid>https://dev.to/fromchiapasdev/mejora-tus-pruebas-unitarias-10x-44ff</guid>
      <description>&lt;p&gt;Hola, bienvenido a un nuevo post!&lt;/p&gt;

&lt;p&gt;Hoy quiero hablar de un tema muy importante, que no puede faltar en un desarrollo serio de software: las pruebas unitarias.&lt;/p&gt;

&lt;p&gt;Las pruebas unitarias son código que escribimos para validar la lógica de nuestro programa. Estas pruebas se caracterizan por evaluar partes pequeñas del código, como una función o una clase.&lt;/p&gt;

&lt;p&gt;Además, las pruebas unitarias son muy útiles para realizar refactorizaciones a futuro sin temor a que, durante este proceso, deje de funcionar lo que ya teníamos correctamente.&lt;/p&gt;

&lt;p&gt;Y es que, en realidad, creo que todos hemos trabajado en algún proyecto donde el equipo tiene miedo de modificar ciertas partes del código, porque no sabemos si lo que vamos a cambiar afectará reglas de negocio ya implementadas, provocando comportamientos extraños y los temidos bugs.&lt;/p&gt;

&lt;p&gt;El objetivo de estas pruebas es que tengas confianza en lo que escribes y que entregues la menor cantidad posible de errores. Sin embargo, a veces los proyectos ya cuentan con pruebas unitarias, e incluso con una suite extensa, pero el simple hecho de tenerlas no garantiza que estés cubierto. Esto sucede porque las pruebas están desactualizadas o solo se han ido “parcheando” con cada cambio, buscando que pasen sin fallar y que el proceso de CI no se queje, lo que permite seguir con el flujo de trabajo sin más.&lt;/p&gt;

&lt;p&gt;Esto es un claro síntoma de que tus pruebas unitarias se han convertido en una carga, y todo el equipo las percibe de esa manera. Hacer pruebas se ve como una tarea ardua sin recompensa. Y en estos casos, es cierto: las pruebas solo ralentizan el desarrollo.&lt;/p&gt;

&lt;p&gt;Podemos evitar esta situación cambiando nuestra perspectiva: las pruebas unitarias son una parte más del sistema y deben recibir el mismo cuidado que el código principal.&lt;/p&gt;

&lt;p&gt;El hecho de que no se ejecuten en producción no significa que deban quedar olvidadas después de haberlas escrito una vez. Deben mantenerse con atención, actualizarse de forma consciente y no solo para que el reporte salga “en verde”. Por ejemplo, si eliminamos un método o clase, hay que eliminar las pruebas relacionadas; si cambia una regla de negocio, es normal que las pruebas fallen al principio, pero debemos corregirlas según la nueva lógica. No debemos ocultar el problema real con trucos para que las pruebas pasen, o peor aún, borrarlas o comentarlas.&lt;/p&gt;

&lt;p&gt;Y como las pruebas unitarias son importantes, aquí tengo algunos consejos que he aprendido y que pueden ayudarte a mejorarlas y a sentirte más seguro con tu código.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer: Las pruebas unitarias por sí solas no prueban todo el sistema. Es importante complementar con otros métodos de prueba, como pruebas E2E, pruebas manuales con el equipo de QA (si cuentas con uno), entre otros. Sin embargo, las pruebas unitarias siempre serán nuestra primera red de protección ante los cambios.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Herramientas&lt;/li&gt;
&lt;li&gt;¿Como nombrar nuestro sujeto de prueba?&lt;/li&gt;
&lt;li&gt;Escribe un buen mensaje para tu prueba&lt;/li&gt;
&lt;li&gt;¿Como evitar fragilidad en nuestros tests?&lt;/li&gt;
&lt;li&gt;¿Que son los mocks y cuando usarlos?&lt;/li&gt;
&lt;li&gt;¿Que porcentaje de cobertura debe tener mi código?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Herramientas
&lt;/h2&gt;

&lt;p&gt;En estos ejemplos voy a utilizar &lt;strong&gt;JavaScript&lt;/strong&gt;, pero los conceptos son agnósticos, ya que JavaScript es solo una herramienta para comunicar las ideas.&lt;/p&gt;

&lt;p&gt;En JavaScript existen librerías populares con las que puedes crear pruebas para tu código. Sin embargo, es importante hacer una distinción entre un &lt;strong&gt;Test Runner&lt;/strong&gt; y una &lt;strong&gt;Assertion Library&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Un &lt;strong&gt;Test Runner&lt;/strong&gt; proporciona la infraestructura necesaria para ejecutar las pruebas de manera aislada, algunas incluso en paralelo. También incluye utilidades para hacer &lt;em&gt;debugging&lt;/em&gt;, entre otras características. Algunos ejemplos son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Jest&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mocha&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por otro lado, las &lt;strong&gt;librerías de assertions&lt;/strong&gt; pueden venir integradas dentro del &lt;em&gt;test runner&lt;/em&gt; (como ocurre con Jest) o ser externas, en cuyo caso deberás instalarlas por separado. Algunos ejemplos de estas son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chai&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assert Module&lt;/strong&gt; (incluido en Node.js ≥ v18)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estas herramientas te ofrecen un conjunto de funciones para validar lo que necesites: el contenido de un objeto, una fecha, una cadena de texto, etc.&lt;/p&gt;

&lt;p&gt;Te dejo un ejemplo de código:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;node:assert/strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deepEqual&lt;/span&gt;&lt;span class="p"&gt;([[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="c1"&gt;// AssertionError: Expected inputs to be strictly deep-equal:&lt;/span&gt;
&lt;span class="c1"&gt;// + actual - expected ... Lines skipped&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;//   [&lt;/span&gt;
&lt;span class="c1"&gt;//     [&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="c1"&gt;//       2,&lt;/span&gt;
&lt;span class="c1"&gt;// +     3&lt;/span&gt;
&lt;span class="c1"&gt;// -     '3'&lt;/span&gt;
&lt;span class="c1"&gt;//     ],&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="c1"&gt;//     5&lt;/span&gt;
&lt;span class="c1"&gt;//   ]&lt;/span&gt;
&lt;span class="cm"&gt;/* Código tomado de la documentación de Nodejs https://nodejs.org/docs/latest-v22.x/api/assert.html#assert*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En este ejemplo esperamos que el array de la izquierda tenga los mismos elementos que el de la derecha. &lt;/p&gt;

&lt;p&gt;Y te preguntarás, realmente necesito estas librerías si puedo realizarlo manualmente. Y la respuesta es que si y no, podrías hacer tus propios métodos para validar inputs, etc. O ahorrar tiempo y tener algo que funciona con una librería.&lt;/p&gt;

&lt;p&gt;Entonces, para iniciar necesitas conocer como configurar estas herramientas. No es difícil, con la  documentación es más que suficiente para guiarte. Yo utilizó Jest en los proyectos que realizo porque es el que viene por defecto en NestJS y ya no tienes que instalar librerías de assertion. &lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo nombrar nuestro sujeto de prueba?
&lt;/h2&gt;

&lt;p&gt;Al sujeto de prueba también podemos llamarlo &lt;strong&gt;SUT&lt;/strong&gt; (&lt;em&gt;System Under Test&lt;/em&gt;). Es una forma de referirse a él que me gustó cuando leí el libro &lt;em&gt;Unit Testing&lt;/em&gt;, y desde entonces la adopté. Me parece que así queda claro quién está siendo probado y se evita confusión con otros nombres que puedan surgir en el test.&lt;/p&gt;

&lt;p&gt;Claro, esto es solo una preferencia personal. Tú eres libre de nombrarlo como prefieras, pero siempre trata de que sea evidente qué parte del sistema estás probando.&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;// sum.js&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&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;span class="c1"&gt;// sum.spec.js&lt;/span&gt;
&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Calculator&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;SUT&lt;/span&gt; &lt;span class="c1"&gt;// System under test&lt;/span&gt;

    &lt;span class="nf"&gt;beforeEach&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;SUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nf"&gt;afterEach&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Escribe un buen mensaje para tu prueba
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// validations&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&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;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EmailSender&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;SUT&lt;/span&gt; &lt;span class="c1"&gt;// System under test&lt;/span&gt;

    &lt;span class="nf"&gt;beforeEach&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;SUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nf"&gt;afterEach&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="c1"&gt;// ❌ no muy descriptivo.&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test method send()&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;

    &lt;span class="c1"&gt;// ✅ Buena descripción&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;send(): falla por email invalido&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;send(): falla por contenido invalido&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="o"&gt;=&amp;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;En el ejemplo anterior nos damos cuenta de que podemos nombrar nuestros tests de cualquier manera, pero al final, quienes terminamos afectados por mensajes con descripciones pobres somos nosotros o nuestros compañeros.&lt;/p&gt;

&lt;p&gt;Imagina que alguien externo llega a trabajar en el proyecto y, al modificar la clase &lt;code&gt;EmailSender&lt;/code&gt;, algo falla. Entonces aparece en la terminal un test con un mensaje como: &lt;code&gt;test method send()&lt;/code&gt;. Yo me arrancaría el cabello tratando de entender, primero, para qué sirve ese test y, segundo, cómo arreglarlo.&lt;/p&gt;

&lt;p&gt;En cambio, si los tests tienen una buena descripción —como en los ejemplos que siguen— te das una idea rápida de qué pudo haber fallado, y haces que la experiencia de &lt;em&gt;debugging&lt;/em&gt; sea mucho más agradable.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Cómo evitar la fragilidad en nuestros tests?
&lt;/h2&gt;

&lt;p&gt;Existe un enfoque que te ayudará a mejorar mucho tus pruebas y a evitar que estas sean frágiles, que aparezcan falsos positivos o que sea difícil hacer refactorizaciones.&lt;/p&gt;

&lt;p&gt;Muchas veces, al escribir tests, nos damos cuenta de qué tan bien hemos aplicado buenas prácticas. Esto sucede porque, al probar nuestro código, debemos tratar de aislar lo más posible esa unidad de código del resto del sistema.&lt;/p&gt;

&lt;p&gt;Con esto me refiero a que, si nuestra función o clase utiliza recursos externos como APIs u otras clases, y no dependemos de abstracciones sino de clases concretas, estaremos agregando fragilidad a las pruebas. En cualquier momento en que se actualicen esas dependencias, los tests pueden fallar por razones que no corresponden al alcance de la prueba unitaria. Esto introduce falsos positivos que, si no se abordan a tiempo, hacen que las pruebas se vuelvan insostenibles.&lt;/p&gt;

&lt;p&gt;Cuando dependemos de abstracciones, escribir una prueba para un componente con dependencias se vuelve mucho más sencillo: podemos reemplazarlas fácilmente y enfocarnos en probar lo que realmente importa, como las reglas de negocio, la lógica o el algoritmo.&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;// EJEMPLO: Depende de clase concreta&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SNSAWSService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// depende de clase concreta&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// validations&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SNSServiceAws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&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;span class="c1"&gt;// EJEMPLO: Utiliza Principio SOLID, facil testear&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EmailProviderInterface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// validations&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&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;Este detalle lo podemos resolver mediante &lt;strong&gt;inyección de dependencias&lt;/strong&gt; y aplicando el principio SOLID de &lt;strong&gt;Inversión de Dependencias&lt;/strong&gt;, el cual nos indica que debemos depender de abstracciones. En este caso, eso se traduce en utilizar una interfaz.&lt;/p&gt;

&lt;p&gt;Además, algo que me ha servido mucho es cambiar la perspectiva de cómo escribo mis pruebas. Ahora me enfoco en &lt;strong&gt;probar lo que quiero que haga&lt;/strong&gt;, en el &lt;strong&gt;resultado&lt;/strong&gt;, y ya no me preocupo tanto por &lt;strong&gt;cómo&lt;/strong&gt; tiene que hacerlo.&lt;/p&gt;

&lt;p&gt;Existe una gran diferencia en este enfoque: al cambiar la perspectiva, dejamos de lado el detalle de la implementación —los pasos exactos del algoritmo— y nos centramos en que el &lt;strong&gt;resultado deseado sea correcto&lt;/strong&gt;. Al reflejar esto en nuestras pruebas, logramos una mayor &lt;strong&gt;robustez&lt;/strong&gt; y &lt;strong&gt;resistencia ante cambios&lt;/strong&gt; en el código.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✅ No pierdas tiempo probando detalles de implementación que podrían cambiar con el tiempo. Tu objetivo debe ser asegurarte de que el sistema haga lo que se espera que haga desde el punto de vista funcional. Esto te permitirá mantener pruebas más estables y significativas a largo plazo.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Que son los mocks y cuando usarlos?
&lt;/h2&gt;

&lt;p&gt;Los &lt;em&gt;mocks&lt;/em&gt; son, de forma coloquial, funciones o clases que reemplazan las dependencias reales en nuestras pruebas. Su propósito es ayudar a aislar el código y evitar que se utilicen los servicios reales.&lt;/p&gt;

&lt;p&gt;Imagina que necesitas enviar un correo electrónico, un SMS, etc. Una buena práctica sería &lt;strong&gt;no usar los servicios reales&lt;/strong&gt; por varios motivos: costos, usuarios notificados erróneamente, y porque es mucho más sencillo reemplazarlos para tener control sobre lo que sucede con nuestro código.&lt;/p&gt;

&lt;p&gt;Sin &lt;em&gt;mocks&lt;/em&gt;, los tests serían demasiado impredecibles, ya que estarían dependiendo de componentes externos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jest&lt;/strong&gt; cuenta con sus propios métodos para crear &lt;em&gt;mocks&lt;/em&gt; y &lt;em&gt;spies&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;La diferencia entre ellos es que, con los &lt;em&gt;spies&lt;/em&gt;, puedes hacer un seguimiento de las llamadas al &lt;em&gt;mock&lt;/em&gt;: ver con qué datos se llamó, cuántas veces, en qué orden, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Un detalle importante antes de pasar al ejemplo:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;No siempre necesitas hacer asserts sobre los mocks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Esto se debe a que, en muchos casos, no es relevante para la lógica que estás probando. Además, hacer asserts innecesarios puede introducir fragilidad en tus pruebas, ya que los &lt;em&gt;mocks&lt;/em&gt; simulan dependencias externas que pueden cambiar con el tiempo.&lt;/p&gt;

&lt;p&gt;Sin embargo, &lt;strong&gt;sí tiene sentido hacer asserts sobre los mocks cuando son relevantes para las reglas de negocio&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Por ejemplo: si tu aplicación debe enviar un correo electrónico cuando se crea un usuario, es importante verificar que el servicio de email se haya llamado, y con los datos correctos.&lt;/p&gt;

&lt;p&gt;Esto te ayuda a confirmar que tu código realmente ejecuta las acciones clave para tu negocio.&lt;/p&gt;

&lt;p&gt;Ahora sí, vamos con el ejemplo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// notification.test.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;emailService&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./emailService.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;notifyNewUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./notification.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;beforeEach&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="c1"&gt;// Restauramos el comportamiento original&lt;/span&gt;
  &lt;span class="nx"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mockRestore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notifyNewUser: envia un correo de bienvenida&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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="c1"&gt;// Espiamos sendEmail y evitamos la llamada real&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spyOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sendEmail&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="nf"&gt;mockResolvedValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spy-ok&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;user&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;u@e.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Axel&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;notifyNewUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Verificamos parámetros y valor de retorno&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spy&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;u@e.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;¡Bienvenido!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hola Axel, gracias por unirte.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spy-ok&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cobertura de código
&lt;/h2&gt;

&lt;p&gt;Por último, en cuanto a temas de cobertura de código, considero que tener una &lt;em&gt;suite&lt;/em&gt; que cubra alrededor del 80 % del código es algo muy bueno.&lt;/p&gt;

&lt;p&gt;Pero hay que tener en cuenta que, al imponer un número, no debemos olvidar lo más importante: &lt;strong&gt;cuidar la calidad de nuestros tests&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No se trata de apuntar a un porcentaje específico o de superarlo, sino de &lt;strong&gt;enfocarnos en tener buenas pruebas&lt;/strong&gt;. Y como consecuencia de eso, de forma casi accidental, terminaremos alcanzando ese porcentaje o quedando muy cerca.&lt;/p&gt;

&lt;p&gt;Siempre es importante escuchar al equipo, conocer su opinión y buscar una forma en la que todos se sientan cómodos. Porque puede suceder que, al imponer un porcentaje mínimo, el equipo empiece a enfocarse únicamente en cumplirlo, escribiendo pruebas que no aportan valor real.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Espero que, si llegaste hasta aquí, te hayas llevado algo útil que puedas poner en práctica de inmediato.&lt;/p&gt;

&lt;p&gt;Crear buenas pruebas unitarias requiere práctica y constancia.&lt;/p&gt;

&lt;p&gt;Yo mismo puedo decir que todavía sigo aprendiendo a mejorar las mías, pero aplicar estos puntos sin duda me ha ayudado a mejorar muchísimo la calidad de mis tests y a evitar muchos falsos positivos.&lt;/p&gt;

&lt;p&gt;Si tienes algún comentario, con gusto podemos conectar en &lt;a href="https://www.linkedin.com/in/tu-perfil" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; o en &lt;a href="https://x.com/im_not_ajscoder" rel="noopener noreferrer"&gt;X (Twitter)&lt;/a&gt; como &lt;a href="https://x.com/im_not_ajscoder" rel="noopener noreferrer"&gt;@im_not_ajscoder&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devtip</category>
      <category>testing</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Type the '_id' Field in TypeScript with Mongoose</title>
      <dc:creator>Axel Espinosa</dc:creator>
      <pubDate>Tue, 29 Apr 2025 03:13:54 +0000</pubDate>
      <link>https://dev.to/fromchiapasdev/how-to-type-the-id-field-in-typescript-with-mongoose-5dib</link>
      <guid>https://dev.to/fromchiapasdev/how-to-type-the-id-field-in-typescript-with-mongoose-5dib</guid>
      <description>&lt;p&gt;Hi everyone, let me start by thanking you for reading this post.&lt;/p&gt;

&lt;p&gt;I started this to practice my writing skills in English and to overcome my procrastination. Writing posts like this helps me gain a better understanding of things I'm learning. Let's dive into it.&lt;/p&gt;

&lt;p&gt;I encountered an issue while writing code in typescript using the popular Mongoose library when I tried to convert the field _id to a string.&lt;/p&gt;

&lt;p&gt;I have some example code here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Prop&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Prop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Prop&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Prop&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;stock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&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;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProductModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// example of instance&lt;/span&gt;

&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// trying to convert my _id to a string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm using Nestjs and its Mongoose integration. Instead of writing plain schemas like we traditionally  do, this library allow us to define models and their properties using Decorators (&lt;a class="mentioned-user" href="https://dev.to/prop"&gt;@prop&lt;/a&gt;) in a class, all within the same file. This class also serves as our model.&lt;/p&gt;

&lt;p&gt;There are 2 lines I want us to focus on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProductModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Specifically to the second line where we call &lt;code&gt;.toString()&lt;/code&gt;. It turns out that the way we declared the &lt;code&gt;_id&lt;/code&gt; property in our class causes incorrect typing. &lt;/p&gt;

&lt;p&gt;The library defines two types for &lt;code&gt;ObjectId&lt;/code&gt;: the first is implemented under &lt;code&gt;mongoose.Schema.Types.ObjectId&lt;/code&gt; , and the other is &lt;code&gt;mongoose.Types.ObjectId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The difference between these types is that they aren't interchangeable, the latter is the declaration of an object which has serializable methods like &lt;code&gt;toString()&lt;/code&gt;, while the former doesn't.&lt;/p&gt;

&lt;p&gt;So I'll show you the error from the typescript linter if you use the former.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb1e69zi4ohlem7dy6xhg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb1e69zi4ohlem7dy6xhg.png" alt="Image of Visual Studio Code showing an error when trying to convert an ObjectId to a string" width="800" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of writing something like this to silence the linter: (product._id as ObjectId).toString()&lt;/p&gt;

&lt;p&gt;Try using the correct type for your class, which is &lt;code&gt;mongoose.Types.ObjectId&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ObjectId&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;It doesn't matter if you are not using NestJS and Decorators. The type you need to import is the same. The example below use an interface and plain Mongoose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Product&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ObjectId&lt;/span&gt;&lt;span class="p"&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;myProductModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Schema&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// props })&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bye
&lt;/h2&gt;

&lt;p&gt;Well, that's a short post, just in case someone else needs this, and for me because after one week without using Mongoose, I forget it XD. I think it would be interesting to investigate more about these 2 types and why they are written in that way, under different objects. &lt;/p&gt;

&lt;p&gt;In summary, we need to make sure we're typing our properties with the correct type before trying to bypass the Typescript compiler using type coercion or some other trick.  &lt;/p&gt;

&lt;p&gt;Thank you for reading ❤️&lt;/p&gt;

</description>
      <category>node</category>
      <category>mongodb</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
