<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>pcollaog&#39;s blog</title>
  
  <subtitle>Java Developer</subtitle>
  <link href="https://blog.pcollaog.cl/atom.xml" rel="self"/>
  
  <link href="https://blog.pcollaog.cl/"/>
  <updated>2025-11-14T00:39:56.952Z</updated>
  <id>https://blog.pcollaog.cl/</id>
  
  <author>
    <name>Francisco Collao</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Optional en Java</title>
    <link href="https://blog.pcollaog.cl/2025/11/13/Optional-en-Java/"/>
    <id>https://blog.pcollaog.cl/2025/11/13/Optional-en-Java/</id>
    <published>2025-11-14T00:25:45.000Z</published>
    <updated>2025-11-14T00:39:56.952Z</updated>
    
    <content type="html"><![CDATA[<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">  ___       _   _               _    _________</span><br><span class="line"> / _ \ _ __| |_(_)___ _ _  __ _| |  / /_   _\ \</span><br><span class="line">| (_) | &#x27;_ \  _| / _ \ &#x27; \/ _` | | &lt; &lt;  | |  &gt; &gt;</span><br><span class="line"> \___/| .__/\__|_\___/_||_\__,_|_|  \_\ |_| /_/</span><br><span class="line">      |_|</span><br></pre></td></tr></table></figure><p>Desde que programo en Java, una de las excepciones más recurrentes y, por qué no decirlo, molestas, ha sido la infame <code>NullPointerException</code>. Durante años, la forma de evitarla era anidar bloques <code>if</code> por todo el código, lo que no solo lo hacía más verboso, sino también más difícil de leer y mantener. Siempre quedaba la otra opción (la vieja confiable): meter un <code>try/catch</code> a todo el bloque sospechoso, pero esto, claramente, no mejora la legibilidad y abre otros problemas, como saber <strong>qué</strong> hacer cuando ocurre la <code>NullPointerException</code>.</p><p>A partir de Java 8, se introdujo una nueva herramienta en el lenguaje para lidiar con este problema de una manera más elegante y funcional: la clase <code>Optional&lt;T&gt;</code>.</p><h2 id="¿Desde-cuando-esta-disponible"><a href="#¿Desde-cuando-esta-disponible" class="headerlink" title="¿Desde cuándo está disponible?"></a>¿Desde cuándo está disponible?</h2><p><code>Optional</code> fue una de las adiciones más destacadas del <strong>JDK 8</strong>, lanzado en marzo de 2014. Nació como parte del esfuerzo por modernizar el lenguaje e introducir paradigmas de programación funcional, junto con las expresiones <strong>Lambda</strong> y la <strong>API de Streams</strong>.</p><h2 id="¿Cual-es-su-objetivo-principal"><a href="#¿Cual-es-su-objetivo-principal" class="headerlink" title="¿Cuál es su objetivo principal?"></a>¿Cuál es su objetivo principal?</h2><p>El propósito fundamental de <code>Optional</code> es proporcionar un <strong>contenedor</strong> que puede o no tener un valor no nulo. En lugar de devolver <code>null</code> para indicar la ausencia de un resultado, un método puede devolver un <code>Optional</code> que esté “vacío”.</p><p>Esto tiene una ventaja semántica enorme: la firma de un método que devuelve <code>Optional&lt;String&gt;</code> comunica explícitamente al programador que el valor podría no estar presente. Obliga a quien llama al método a “desenvolver” el <code>Optional</code> y manejar conscientemente el caso de ausencia, eliminando la ambigüedad de un <code>null</code> que podría ser un valor esperado o un error no controlado.</p><h2 id="Beneficios-de-usar-Optional"><a href="#Beneficios-de-usar-Optional" class="headerlink" title="Beneficios de usar Optional"></a>Beneficios de usar Optional</h2><p>Adoptar <code>Optional</code> en tu código trae varias ventajas:</p><ol><li><strong>Claridad en el diseño de APIs</strong>: Como mencioné, si un método devuelve <code>Optional&lt;T&gt;</code>, sabes de inmediato que debes prepararte para un resultado vacío. Se acabaron las sorpresas con valores nulos inesperados.</li><li><strong>Reducción de <code>NullPointerException</code></strong>: Al forzar un manejo explícito de la ausencia de valor, el código se vuelve más robusto y menos propenso a errores en tiempo de ejecución.</li><li><strong>Código más expresivo y funcional</strong>: <code>Optional</code> viene con una serie de métodos de estilo funcional (<code>map</code>, <code>flatMap</code>, <code>filter</code>, <code>ifPresent</code>) que permiten encadenar operaciones de una manera fluida y legible, evitando la necesidad de bloques <code>if-else</code> anidados.</li></ol><h2 id="Ejemplos-practicos"><a href="#Ejemplos-practicos" class="headerlink" title="Ejemplos prácticos"></a>Ejemplos prácticos</h2><p>Veamos cómo trabajar con <code>Optional</code>.</p><h3 id="Creacion-de-un-Optional"><a href="#Creacion-de-un-Optional" class="headerlink" title="Creación de un Optional"></a>Creación de un Optional</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Ejemplos de creación de un Optional</span></span><br><span class="line"><span class="comment">// 1. Optional con un valor no nulo </span></span><br><span class="line"><span class="comment">// (si &#x27;valor&#x27; es null, lanza NullPointerException)</span></span><br><span class="line">Optional&lt;String&gt; optionalConValor = Optional.of(<span class="string">&quot;Hola Mundo&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 2. Optional que permite valores nulos</span></span><br><span class="line"><span class="comment">//  (si &#x27;valorNulo&#x27; es null, crea un Optional vacío)</span></span><br><span class="line"><span class="type">String</span> <span class="variable">valorNulo</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">Optional&lt;String&gt; optionalVacio = Optional.ofNullable(valorNulo);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 3. Creación explícita de un Optional vacío</span></span><br><span class="line">Optional&lt;String&gt; vacio = Optional.empty();</span><br></pre></td></tr></table></figure><h3 id="Comprobando-si-hay-un-valor"><a href="#Comprobando-si-hay-un-valor" class="headerlink" title="Comprobando si hay un valor"></a>Comprobando si hay un valor</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Ejemplos de comprobación de valor</span></span><br><span class="line"><span class="keyword">if</span> (optionalConValor.isPresent()) &#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;El optional tiene un valor: &quot;</span> </span><br><span class="line">        + optionalConValor.get());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// A partir de Java 11, puedes usar isEmpty()</span></span><br><span class="line"><span class="keyword">if</span> (vacio.isEmpty()) &#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;El optional está vacío.&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Ejecutando-acciones-si-hay-un-valor"><a href="#Ejecutando-acciones-si-hay-un-valor" class="headerlink" title="Ejecutando acciones si hay un valor"></a>Ejecutando acciones si hay un valor</h3><p>Una forma muy común y limpia de usar <code>Optional</code> es con <code>ifPresent</code>.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Ejemplo de uso de ifPresent con una expresión lambda</span></span><br><span class="line">optionalConValor.ifPresent(valor -&gt; &#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;El valor es: &quot;</span> + valor);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="Obteniendo-el-valor-de-forma-segura"><a href="#Obteniendo-el-valor-de-forma-segura" class="headerlink" title="Obteniendo el valor de forma segura"></a>Obteniendo el valor de forma segura</h3><p>El método <code>.get()</code> es peligroso porque lanzará una <strong>NoSuchElementException</strong> si el <code>Optional</code> está vacío. Es mucho mejor usar alternativas que proveen un valor por defecto.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Formas seguras de obtener el valor</span></span><br><span class="line"><span class="comment">// Si el optional está vacío, devuelve &quot;default&quot;</span></span><br><span class="line"><span class="type">String</span> <span class="variable">resultado1</span> <span class="operator">=</span> optionalVacio.orElse(<span class="string">&quot;default&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Similar a orElse, pero el valor por defecto se genera a </span></span><br><span class="line"><span class="comment">// través de un Supplier. Esto es más eficiente si la generación</span></span><br><span class="line"><span class="comment">//  del valor por defecto es costosa.</span></span><br><span class="line"><span class="type">String</span> <span class="variable">resultado2</span> <span class="operator">=</span> optionalVacio.orElseGet(() -&gt; <span class="string">&quot;valor generado&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Si el optional está vacío, lanza una excepción.</span></span><br><span class="line"><span class="type">String</span> <span class="variable">resultado3</span> <span class="operator">=</span> optionalVacio.orElseThrow(() -&gt; </span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">IllegalStateException</span>(<span class="string">&quot;No se encontró el valor&quot;</span>)</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h3 id="Transformando-valores-con-map-y-flatMap"><a href="#Transformando-valores-con-map-y-flatMap" class="headerlink" title="Transformando valores con map y flatMap"></a>Transformando valores con <code>map</code> y <code>flatMap</code></h3><p>Aquí es donde <code>Optional</code> realmente brilla, permitiendo un estilo de programación funcional.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Transformando el valor con map y flatMap</span></span><br><span class="line">Optional&lt;String&gt; optionalString = Optional.of(<span class="string">&quot;  texto con espacios  &quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Usamos map para transformar el valor interno de forma segura</span></span><br><span class="line">Optional&lt;String&gt; sinEspacios = optionalString.map(String::trim);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Imprime &quot;&#x27;texto con espacios&#x27;&quot;</span></span><br><span class="line">sinEspacios.ifPresent(s -&gt; System.out.println(<span class="string">&quot;&#x27;&quot;</span> + s + <span class="string">&quot;&#x27;&quot;</span>)); </span><br><span class="line"></span><br><span class="line"><span class="comment">// flatMap se usa cuando la función map devuelve otro Optional,</span></span><br><span class="line"><span class="comment">// para evitar tener un Optional&lt;Optional&lt;T&gt;&gt;.</span></span><br><span class="line">Optional&lt;Optional&lt;String&gt;&gt; anidado = sinEspacios.map(s -&gt; </span><br><span class="line">    Optional.of(s.toUpperCase()) <span class="comment">// ¡No hagas esto!</span></span><br><span class="line">); </span><br><span class="line"></span><br><span class="line">Optional&lt;String&gt; enMayusculas = sinEspacios.flatMap(s -&gt; </span><br><span class="line">    Optional.of(s.toUpperCase())  <span class="comment">// ¡Esta es la forma correcta!</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Imprime &quot;TEXTO CON ESPACIOS&quot;</span></span><br><span class="line">enMayusculas.ifPresent(System.out::println); </span><br></pre></td></tr></table></figure><p>Sin lugar a dudas, lo que <strong>más</strong> uso de <code>Optional</code> es en conjunto con <strong>Spring Data</strong>, específicamente en los repositorios. Funcionalmente, el patrón es algo como esto: obtengo la entidad que busco y, si no existe, lanzo una excepción <code>ExampleNotFoundException</code> (que hereda de <code>RuntimeException</code>) que luego es capturada por un <code>GlobalExceptionHandler</code> para devolver un código de estado HTTP 404. Te invito a revisar mi artículo sobre <a href="/2024/03/16/SpringBoot-Exception-Handling/">Manejo de excepciones en Spring Boot</a>.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Ejemplo con un repositorio de Spring Data</span></span><br><span class="line"><span class="keyword">public</span> ExampleModel <span class="title function_">findById</span><span class="params">(String id)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">this</span>.exampleRepository.findById(id)</span><br><span class="line">        .orElseThrow(() -&gt; <span class="keyword">new</span> <span class="title class_">ExampleNotFoundException</span>(id));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Palabras-al-cierre"><a href="#Palabras-al-cierre" class="headerlink" title="Palabras al cierre"></a>Palabras al cierre</h2><p><code>Optional</code> no es una solución mágica para todos los problemas de <code>null</code>, pero es una herramienta poderosa para diseñar APIs más claras y escribir código más seguro y expresivo. Al principio puede costar acostumbrarse a su enfoque funcional, pero una vez que lo dominas, te preguntarás cómo pudiste vivir sin él.</p><hr><h2 id="Para-seguir-leyendo"><a href="#Para-seguir-leyendo" class="headerlink" title="Para seguir leyendo"></a>Para seguir leyendo</h2><p>Si quieres profundizar más en el uso y las buenas prácticas de <code>Optional</code>, te recomiendo los siguientes recursos:</p><ul><li><a href="https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html"><strong>Documentación Oficial de Oracle (en inglés)</strong></a>: La fuente principal de información. Imprescindible para entender todos los detalles de la clase.</li><li><a href="https://www.baeldung.com/java-optional"><strong>A Guide to Java 8 Optional (en inglés)</strong></a>: Baeldung es un referente en tutoriales de Java. Este artículo es una guía muy completa y con excelentes ejemplos.</li><li><a href="https://www.arquitecturajava.com/java-optional-y-nullpointerexception/"><strong>Java Optional y NullPointerException</strong></a>: Un buen artículo en español que explica el propósito de <code>Optional</code> y cómo ayuda a evitar los <code>NullPointerException</code>.</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;  ___       _   _               _    _________&lt;/span</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    <category term="Java" scheme="https://blog.pcollaog.cl/categories/Programming/Java/"/>
    
    
    <category term="java" scheme="https://blog.pcollaog.cl/tags/java/"/>
    
    <category term="optional" scheme="https://blog.pcollaog.cl/tags/optional/"/>
    
    <category term="jdk8" scheme="https://blog.pcollaog.cl/tags/jdk8/"/>
    
  </entry>
  
  <entry>
    <title>Test Unitarios con Deno</title>
    <link href="https://blog.pcollaog.cl/2025/10/31/Test-Unitarios-con-Deno/"/>
    <id>https://blog.pcollaog.cl/2025/10/31/Test-Unitarios-con-Deno/</id>
    <published>2025-10-31T15:14:49.000Z</published>
    <updated>2025-11-01T19:36:46.064Z</updated>
    
    <content type="html"><![CDATA[<h2 id="¿Que-es-BDD"><a href="#¿Que-es-BDD" class="headerlink" title="¿Qué es BDD?"></a>¿Qué es BDD?</h2><p><strong>BDD (Behavior-Driven Development)</strong> es una metodología de desarrollo que coloca el comportamiento del software en el centro del proceso. A diferencia del testing unitario tradicional que se enfoca en “¿qué hace esta función?”, BDD se pregunta “¿cuál es el comportamiento que espera el usuario o el negocio?”.</p><p>En BDD, los tests se escriben usando una estructura clara y legible:</p><ul><li><strong>Given</strong> (Dado): El contexto o estado inicial.</li><li><strong>When</strong> (Cuando): La acción que realizamos.</li><li><strong>Then</strong> (Entonces): El resultado esperado.</li></ul><p>Esta estructura hace que los tests sean <strong>casi documentación viva</strong> del sistema. No solo validan que el código funciona, sino que también comunican <em>por qué</em> y <em>cómo</em> debe comportarse.</p><h3 id="Fortalezas-de-BDD"><a href="#Fortalezas-de-BDD" class="headerlink" title="Fortalezas de BDD"></a>Fortalezas de BDD</h3><ol><li><strong>Claridad</strong>: Los tests se leen como especificaciones. Cualquiera (técnico o no) puede entender qué se está probando.</li><li><strong>Documentación actualizada</strong>: El comportamiento del código siempre está documentado en los tests; no se queda obsoleto como un README abandonado.</li><li><strong>Colaboración efectiva</strong>: Diseñadores, QA y desarrolladores pueden discutir el comportamiento esperado usando el mismo lenguaje.</li><li><strong>Menos bugs por ambigüedad</strong>: Al escribir primero el comportamiento esperado, se reducen las interpretaciones erróneas.</li><li><strong>Refactoring seguro</strong>: Con tests BDD claros, puedes modificar la implementación sin miedo a romper el comportamiento.</li></ol><h3 id="Por-que-BDD-en-Deno"><a href="#Por-que-BDD-en-Deno" class="headerlink" title="Por qué BDD en Deno"></a>Por qué BDD en Deno</h3><p><strong>Deno</strong> nació con premisas fuertes en <strong>seguridad, modernidad y simplicidad</strong>. No sorprende que su sistema de testing incorpore características que se alinean perfectamente con BDD:</p><ul><li>Sistema de testing <strong>built-in</strong> sin dependencias externas (no necesitas instalar nada adicional).</li><li>Sintaxis moderna con <code>describe()</code> e <code>it()</code> para expresar comportamiento.</li><li>Seguridad de permisos por defecto (los tests se ejecutan en un sandbox; solo permites lo que necesitas).</li><li>TypeScript <strong>out-of-the-box</strong> sin configuración.</li></ul><p>Esto convierte a Deno en una plataforma ideal para practicar BDD sin fricción.</p><h2 id="Iniciemos-un-proyecto-de-prueba"><a href="#Iniciemos-un-proyecto-de-prueba" class="headerlink" title="Iniciemos un proyecto de prueba"></a>Iniciemos un proyecto de prueba</h2><p>Crearemos esta estructura de directorios para ir creando los archivos necesarios para una prueba simple.</p><figure class="highlight plaintext"><figcaption><span>Estructura de directorios</span></figcaption><table><tr><td class="code"><pre><span class="line">calc-project/</span><br><span class="line">├── src/</span><br><span class="line">│   └── Calc.ts</span><br><span class="line">├── test/</span><br><span class="line">│   └── Calc.test.ts</span><br><span class="line">└── deno.json</span><br></pre></td></tr></table></figure><p>El contenido del archivo <code>deno.json</code> es el siguiente. Recuerda que en este archivo es donde se declaran las dependencias y las tareas ejecutables.</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;imports&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;@std/assert&quot;</span><span class="punctuation">:</span> <span class="string">&quot;jsr:@std/assert@^1.0.15&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;@std/expect&quot;</span><span class="punctuation">:</span> <span class="string">&quot;jsr:@std/expect@^1.0.17&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;@std/testing&quot;</span><span class="punctuation">:</span> <span class="string">&quot;jsr:@std/testing@^1.0.16&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>Ahora revisemos el contenido de los archivos del proyecto. El primero es una clase con 3 operaciones matemáticas simples: suma, resta y división.</p><figure class="highlight ts"><figcaption><span>Calc.ts</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Simple calculator utilities used in examples and tests.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Esta clase es intencionalmente pequeña y tiene métodos básicos</span></span><br><span class="line"><span class="comment"> * para demostrar pruebas unitarias en estilo BDD con Deno.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">Calc</span> &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Suma dos números.</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> <span class="variable">a</span> - primer sumando</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> <span class="variable">b</span> - segundo sumando</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@returns</span> la suma de `a` y `b`</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">sum</span>(<span class="attr">a</span>: <span class="built_in">number</span>, <span class="attr">b</span>: <span class="built_in">number</span>): <span class="built_in">number</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> a + b;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Resta dos números (a - b).</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> <span class="variable">a</span> - minuendo</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> <span class="variable">b</span> - sustraendo</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@returns</span> la resta de `a` menos `b`</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">subtract</span>(<span class="attr">a</span>: <span class="built_in">number</span>, <span class="attr">b</span>: <span class="built_in">number</span>): <span class="built_in">number</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> a - b;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Divide dos números (a / b).</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * Lanza un error cuando `b` es 0 o no es un número válido (NaN),</span></span><br><span class="line"><span class="comment">     * para evitar divisiones inválidas.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> <span class="variable">a</span> - dividendo</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> <span class="variable">b</span> - divisor (no debe ser 0 ni NaN)</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@returns</span> el resultado de `a / b`</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@throws</span> &#123;<span class="type">Error</span>&#125; si `b` es 0 o NaN</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">div</span>(<span class="attr">a</span>: <span class="built_in">number</span>, <span class="attr">b</span>: <span class="built_in">number</span>): <span class="built_in">number</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (b === <span class="number">0</span> || <span class="title class_">Number</span>.<span class="built_in">isNaN</span>(b)) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&quot;No se puede dividir por 0&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> a / b;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>A continuación, veremos cómo se implementan los tests unitarios sobre la clase <code>Calc</code> usando el estilo BDD que nos ofrece Deno y las dependencias de <code>@std/testing</code> y <code>@std/expect</code>.</p><figure class="highlight ts"><figcaption><span>Test unitarios sobre la clase Calc</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; expect &#125; <span class="keyword">from</span> <span class="string">&quot;@std/expect/expect&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; describe, it &#125; <span class="keyword">from</span> <span class="string">&quot;@std/testing/bdd&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Calc</span> &#125; <span class="keyword">from</span> <span class="string">&quot;../src/Calc.ts&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="title function_">describe</span>(<span class="string">&quot;Test unitarios sobre la clase Calc&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="title function_">describe</span>(<span class="string">&quot;sum - casos adicionales (BDD)&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">it</span>(<span class="string">&quot;suma números positivos&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">const</span> calc = <span class="keyword">new</span> <span class="title class_">Calc</span>();</span><br><span class="line">            <span class="title function_">expect</span>(calc.<span class="title function_">sum</span>(<span class="number">2</span>, <span class="number">3</span>)).<span class="title function_">toEqual</span>(<span class="number">5</span>);</span><br><span class="line">            <span class="title function_">expect</span>(calc.<span class="title function_">sum</span>(<span class="number">10</span>, <span class="number">20</span>)).<span class="title function_">toEqual</span>(<span class="number">30</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">describe</span>(<span class="string">&quot;subtract - casos adicionales (BDD)&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">it</span>(<span class="string">&quot;resta números positivos&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">const</span> calc = <span class="keyword">new</span> <span class="title class_">Calc</span>();</span><br><span class="line">            <span class="title function_">expect</span>(calc.<span class="title function_">subtract</span>(<span class="number">5</span>, <span class="number">3</span>)).<span class="title function_">toEqual</span>(<span class="number">2</span>);</span><br><span class="line">            <span class="title function_">expect</span>(calc.<span class="title function_">subtract</span>(<span class="number">20</span>, <span class="number">10</span>)).<span class="title function_">toEqual</span>(<span class="number">10</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">describe</span>(<span class="string">&quot;div - validaciones&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">it</span>(<span class="string">&quot;debería fallar dividiendo por 0&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">const</span> calc = <span class="keyword">new</span> <span class="title class_">Calc</span>();</span><br><span class="line">            <span class="comment">// Capturar el error de ejecución</span></span><br><span class="line">            <span class="title function_">expect</span>(<span class="function">() =&gt;</span> calc.<span class="title function_">div</span>(<span class="number">1</span>, <span class="number">0</span>)).<span class="title function_">toThrow</span>(<span class="string">&quot;No se puede dividir por 0&quot;</span>);</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="title function_">it</span>(<span class="string">&quot;debería dividir correctamente 8/2=4&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">const</span> calc = <span class="keyword">new</span> <span class="title class_">Calc</span>();</span><br><span class="line">            <span class="keyword">const</span> result = calc.<span class="title function_">div</span>(<span class="number">8</span>, <span class="number">2</span>);</span><br><span class="line">            <span class="title function_">expect</span>(result).<span class="title function_">toEqual</span>(<span class="number">4</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>Para ejecutar todos los tests, usamos el comando <code>deno test</code>. Este buscará y correrá todos los archivos de test en el proyecto, generando una salida similar a la siguiente:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">running 4 tests from ./test/Calc.test.ts</span><br><span class="line">Test unitarios sobre la clase Calc ...</span><br><span class="line">  sum - casos adicionales (BDD) ...</span><br><span class="line">    suma números positivos ... ok (1ms)</span><br><span class="line">  sum - casos adicionales (BDD) ... ok (1ms)</span><br><span class="line">  subtract - casos adicionales (BDD) ...</span><br><span class="line">    resta números positivos ... ok (0ms)</span><br><span class="line">  subtract - casos adicionales (BDD) ... ok (0ms)</span><br><span class="line">  div - validaciones ...</span><br><span class="line">    debería fallar dividiendo por 0 ... ok (1ms)</span><br><span class="line">    debería dividir correctamente 8/2=4 ... ok (0ms)</span><br><span class="line">  div - validaciones ... ok (1ms)</span><br><span class="line">Test unitarios sobre la clase Calc ... ok (2ms)</span><br><span class="line"></span><br><span class="line">ok | 4 passed | 0 failed (10ms)</span><br></pre></td></tr></table></figure><p>En este bloque de código, estamos definiendo la estructura de nuestros tests utilizando el estilo BDD que nos proporciona Deno:</p><ol><li><p><strong><code>describe(&quot;Test unitarios sobre la clase Calc&quot;, ...)</code></strong>: Este es el bloque principal que agrupa todos los tests relacionados con nuestra clase <code>Calc</code>. Funciona como un contenedor o una suite de pruebas.</p></li><li><p><strong><code>describe(&quot;sum - casos adicionales (BDD)&quot;, ...)</code></strong>: Dentro de la suite principal, creamos un sub-grupo específico para las pruebas del método <code>sum</code>. Esto ayuda a organizar y contextualizar los tests.</p></li><li><p><strong><code>it(&quot;suma números positivos&quot;, ...)</code></strong>: Aquí definimos un caso de prueba concreto. La descripción <code>&quot;suma números positivos&quot;</code> deja claro cuál es el comportamiento que estamos validando.</p><ul><li>Dentro del <code>it</code>, creamos una instancia de <code>Calc</code>.</li><li>Usamos <code>expect(calc.sum(2, 3)).toEqual(5);</code> para afirmar que el resultado de llamar a <code>sum(2, 3)</code> es igual a <code>5</code>. La función <code>expect</code> viene de la librería <code>@std/expect</code> y nos ofrece una forma legible y expresiva de hacer aserciones.</li></ul></li><li><p><strong><code>describe(&quot;subtract - casos adicionales (BDD)&quot;, ...)</code></strong>: De manera similar, creamos otro sub-grupo para el método <code>subtract</code>, manteniendo nuestros tests bien organizados.</p></li><li><p><strong><code>describe(&quot;div - validaciones&quot;, ...)</code></strong>: Finalmente, un grupo para el método <code>div</code>. Aquí se incluyen dos casos de prueba interesantes:</p><ul><li><strong><code>it(&quot;debería fallar dividiendo por 0&quot;, ...)</code></strong>: Este test verifica que el código maneja los errores correctamente. Usamos <code>expect(() =&gt; calc.div(1, 0)).toThrow(...)</code> para asegurar que, al intentar dividir por cero, se lance un error con el mensaje esperado. Nota que la llamada a la función que debe fallar se envuelve en una función flecha <code>() =&gt; ...</code>.</li><li><strong><code>it(&quot;debería dividir correctamente 8/2=4&quot;, ...)</code></strong>: Un test para el “camino feliz” o el caso de uso normal, asegurando que la división funciona como se espera.</li></ul></li></ol><p>Esta estructura jerárquica con <code>describe</code> e <code>it</code> no solo ejecuta el código, sino que también lo documenta de una manera que es fácil de leer y entender para cualquier persona en el equipo.</p><p>Ahora, profundicemos en cómo se estructuran y ejecutan los tests. La función <code>describe</code> es fundamental, ya que actúa como un <strong>agrupador</strong> que define un ámbito o <em>scope</em> para un conjunto de pruebas relacionadas. Dentro de este ámbito, podemos usar “hooks” (funciones especiales) para controlar el ciclo de vida de nuestros tests.</p><p>Estos son los hooks principales:</p><ul><li><strong><code>beforeAll</code></strong>: Se ejecuta <strong>una sola vez</strong> antes de que comiencen todos los tests dentro de su <code>describe</code>. Es ideal para preparar un estado inicial que no cambiará, como levantar un servidor o conectar a una base de datos de prueba.</li><li><strong><code>beforeEach</code></strong>: Se ejecuta <strong>antes de cada test (<code>it</code>)</strong> dentro de su <code>describe</code>. Perfecto para resetear el estado entre pruebas, como limpiar una tabla de la base de datos o crear una nueva instancia de una clase.</li><li><strong><code>afterEach</code></strong>: Se ejecuta <strong>después de cada test (<code>it</code>)</strong>. Se usa para tareas de limpieza que deben ocurrir después de cada prueba, como borrar archivos temporales o cerrar una conexión.</li><li><strong><code>afterAll</code></strong>: Se ejecuta <strong>una sola vez</strong> después de que todos los tests dentro de su <code>describe</code> hayan finalizado. Ideal para la limpieza final, como detener el servidor o cerrar la conexión a la base de datos.</li></ul><p>La magia ocurre cuando anidamos bloques <code>describe</code>, ya que los hooks del ámbito exterior también se aplican a los ámbitos interiores.</p><p>Para ilustrar esto, veamos el siguiente código de ejemplo:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; afterAll, afterEach, beforeAll, beforeEach, describe, it &#125; <span class="keyword">from</span> <span class="string">&quot;@std/testing/bdd&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="title function_">describe</span>(<span class="string">&quot;Test - scope y hooks&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="title function_">beforeAll</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Before All 1 (Scope Padre)&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">afterAll</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;After All 1 (Scope Padre)&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">beforeEach</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Before Each 1 (Scope Padre)&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">afterEach</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;After Each 1 (Scope Padre)&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">it</span>(<span class="string">&quot;should test 1&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Test 1&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">describe</span>(<span class="string">&quot;Test - Scope Anidado&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">beforeAll</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;------&gt; Before All 2 (Scope Anidado)&quot;</span>);</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="title function_">afterAll</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;------&gt; After All 2 (Scope Anidado)&quot;</span>);</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="title function_">beforeEach</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;------&gt; Before Each 2 (Scope Anidado)&quot;</span>);</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="title function_">afterEach</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;------&gt; After Each 2 (Scope Anidado)&quot;</span>);</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="title function_">it</span>(<span class="string">&quot;should test 2&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;------&gt; Test 2&quot;</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>La salida de esta ejecución revela el orden exacto en que Deno ejecuta cada bloque. Desglosemos lo que sucedió:</p><figure class="highlight plaintext"><figcaption><span>Salida: Orden de Ejecución</span></figcaption><table><tr><td class="code"><pre><span class="line">Test - scope y hooks ...</span><br><span class="line">------- output -------</span><br><span class="line">Before All 1 (Scope Padre)</span><br><span class="line">----- output end -----</span><br><span class="line">  should test 1 ...</span><br><span class="line">------- output -------</span><br><span class="line">Before Each 1 (Scope Padre)</span><br><span class="line">Test 1</span><br><span class="line">After Each 1 (Scope Padre)</span><br><span class="line">----- output end -----</span><br><span class="line">  should test 1 ... ok (0ms)</span><br><span class="line">  Test - Scope Anidado ...</span><br><span class="line">------- output -------</span><br><span class="line">------&gt; Before All 2 (Scope Anidado)</span><br><span class="line">----- output end -----</span><br><span class="line">    should test 2 ...</span><br><span class="line">------- output -------</span><br><span class="line">Before Each 1 (Scope Padre)</span><br><span class="line">------&gt; Before Each 2 (Scope Anidado)</span><br><span class="line">------&gt; Test 2</span><br><span class="line">------&gt; After Each 2 (Scope Anidado)</span><br><span class="line">After Each 1 (Scope Padre)</span><br><span class="line">----- output end -----</span><br><span class="line">    should test 2 ... ok (0ms)</span><br><span class="line">------- output -------</span><br><span class="line">------&gt; After All 2 (Scope Anidado)</span><br><span class="line">----- output end -----</span><br><span class="line">  Test - Scope Anidado ... ok (0ms)</span><br><span class="line">------- output -------</span><br><span class="line">After All 1 (Scope Padre)</span><br><span class="line">----- output end -----</span><br><span class="line">Test - scope y hooks ... ok (1ms)</span><br><span class="line"></span><br><span class="line">ok | 1 passed (3 steps) | 0 failed (3ms)</span><br></pre></td></tr></table></figure><ol><li><strong>Inicio del Scope Padre</strong>: Se ejecuta <code>beforeAll</code> del scope padre (<code>Before All 1</code>).</li><li><strong>Ejecución del primer test</strong>:<ul><li>Se ejecuta <code>beforeEach</code> del padre (<code>Before Each 1</code>).</li><li>Se ejecuta el cuerpo del <code>Test 1</code>.</li><li>Se ejecuta <code>afterEach</code> del padre (<code>After Each 1</code>).</li></ul></li><li><strong>Inicio del Scope Anidado</strong>:<ul><li>Se ejecuta el <code>beforeAll</code> del scope anidado (<code>Before All 2</code>).</li></ul></li><li><strong>Ejecución del segundo test (anidado)</strong>:<ul><li>Se ejecuta <code>beforeEach</code> del padre (<code>Before Each 1</code>), porque el test anidado está dentro de su ámbito.</li><li>Se ejecuta <code>beforeEach</code> del scope anidado (<code>Before Each 2</code>).</li><li>Se ejecuta el cuerpo del <code>Test 2</code>.</li><li>Se ejecuta <code>afterEach</code> del scope anidado (<code>After Each 2</code>).</li><li>Se ejecuta <code>afterEach</code> del padre (<code>After Each 1</code>).</li></ul></li><li><strong>Fin del Scope Anidado</strong>: Se ejecuta <code>afterAll</code> del scope anidado (<code>After All 2</code>).</li><li><strong>Fin del Scope Padre</strong>: Se ejecuta <code>afterAll</code> del scope padre (<code>After All 1</code>).</li></ol><p>Como puedes ver, la función <code>describe</code> no solo agrupa tests, sino que crea una jerarquía. Los hooks del <code>describe</code> padre “envuelven” a los hooks y tests de los <code>describe</code> hijos, permitiendo crear configuraciones y limpiezas complejas y ordenadas. Esto es clave para escribir tests mantenibles y escalables.</p><h2 id="Palabras-al-Cierre"><a href="#Palabras-al-Cierre" class="headerlink" title="Palabras al Cierre"></a>Palabras al Cierre</h2><p>Espero que esta guía te haya dado una buena base para empezar a escribir tests unitarios robustos y expresivos en <strong>Deno</strong> usando <strong>BDD</strong>. Esta metodología no solo mejora la calidad de tu código, sino que también ayuda a que otros desarrolladores entiendan rápidamente el objetivo de cada test y lo que se busca lograr.</p><p>Si hay algún otro tema sobre Deno o testing que te gustaría que explorara, ¡déjamelo saber en los comentarios!</p><hr><h2 id="Referencias"><a href="#Referencias" class="headerlink" title="Referencias"></a>Referencias</h2><p>Aquí tienes algunos enlaces para profundizar en los conceptos que hemos cubierto:</p><ul><li><strong><a href="https://docs.deno.com/runtime/manual/testing">Deno Manual - Testing</a>:</strong> La documentación oficial de Deno sobre cómo escribir y ejecutar tests.</li><li><strong><a href="https://jsr.io/@std/testing/doc/bdd">Deno Standard Library - BDD</a>:</strong> La documentación del módulo de BDD que permite usar la sintaxis <code>describe</code> e <code>it</code>.</li><li><strong><a href="https://jsr.io/@std/expect">Deno Standard Library - Expect</a>:</strong> Documentación de la librería de aserciones <code>expect</code>, para validaciones de estilo Jest.</li><li><strong><a href="https://cucumber.io/docs/bdd/">¿Qué es BDD? (Cucumber.io)</a>:</strong> Una excelente introducción a los principios y prácticas de Behavior-Driven Development por parte de uno de los referentes en el área.</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;¿Que-es-BDD&quot;&gt;&lt;a href=&quot;#¿Que-es-BDD&quot; class=&quot;headerlink&quot; title=&quot;¿Qué es BDD?&quot;&gt;&lt;/a&gt;¿Qué es BDD?&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;BDD (Behavior-Driven Dev</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    <category term="TypeScript" scheme="https://blog.pcollaog.cl/categories/Programming/TypeScript/"/>
    
    
    <category term="unit test" scheme="https://blog.pcollaog.cl/tags/unit-test/"/>
    
    <category term="typescript" scheme="https://blog.pcollaog.cl/tags/typescript/"/>
    
    <category term="deno" scheme="https://blog.pcollaog.cl/tags/deno/"/>
    
    <category term="bdd" scheme="https://blog.pcollaog.cl/tags/bdd/"/>
    
  </entry>
  
  <entry>
    <title>Hono: Framework para aplicaciones web</title>
    <link href="https://blog.pcollaog.cl/2025/10/28/Hono-Framework-para-aplicaciones-web/"/>
    <id>https://blog.pcollaog.cl/2025/10/28/Hono-Framework-para-aplicaciones-web/</id>
    <published>2025-10-28T11:55:18.000Z</published>
    <updated>2025-11-01T19:36:46.064Z</updated>
    
    <content type="html"><![CDATA[<img src="/images/2025/hono_logo.png" class="" title="Hono Logo"><p>Cuando me enfrento a un nuevo proyecto, ya sea una API para una aplicación móvil o un backend para un sitio web, siempre busco herramientas que me hagan la vida más simple y fácil. No quiero mantener configuraciones complejas ni enfocar esfuerzos a optimizar código con un framework pesado que consuma más recursos de los necesarios. Mis prioridades son simples: quiero que sea <strong>rápido</strong>, <strong>ligero</strong> y que se integre sin problemas con <a href="/tags/deno/"><strong>Deno</strong></a>, que es el entorno de ejecución de <a href="/tags/typescript/"><strong>TypeScript</strong></a> que he adoptado para casi todo.</p><p>Y ahí es donde entra <strong>Hono</strong>.</p><p>Descubrí <strong>Hono</strong> buscando una alternativa moderna a Express.js (un framework que usé durante años en el mundo de Node.js). Aunque Express es casi de facto el framework web para node.js, sentía que se estaba quedando desactualizado no encajaba del todo con la simplicidad y seguridad que me ofrecía <strong>Deno</strong>. Necesitaba algo que se sintiera más nativo, más ágil y moderno.</p><p>Lo que me convenció de <strong>Hono</strong> fue precisamente eso. Es increíblemente <strong>liviano</strong>, casi no añade <em>overhead</em> a mi aplicación, y su rendimiento es espectacular. Pero la verdadera joya de la corona, para mí, es su <strong>versatilidad</strong>. Aunque mi ecosistema principal es <strong>Deno</strong>, <strong>Hono</strong> me da la tranquilidad de saber que mi código es portable. Si el día de mañana decido mover una API a Cloudflare Workers para que corra en el <em>edge</em> (más cerca de los usuarios), o si un cliente me pide desplegarla en un servidor tradicional con Node.js, puedo hacerlo con cambios mínimos. Esa libertad es algo que valoro muchísimo.</p><p>Como vengo del mundo de Express, empezar con <strong>Hono</strong> fue muy sencillo. La forma de definir rutas, gestionar peticiones (<code>req</code>) y respuestas (<code>res</code>) y usar middlewares es tan intuitiva y familiar que no sentí que hiciera un esfuerzo adicional, es decir, si vienes del mundo Express, la curva de aprendizaje es rápida.</p><p>En este post quiero contarte, desde mi experiencia, por qué <strong>Hono</strong> se ha convertido en mi framework de cabecera para casi cualquier proyecto web que involucre un backend.</p><h2 id="Manos-a-la-Obra-Tu-Primer-Proyecto-con-Hono-y-Deno"><a href="#Manos-a-la-Obra-Tu-Primer-Proyecto-con-Hono-y-Deno" class="headerlink" title="Manos a la Obra: Tu Primer Proyecto con Hono y Deno"></a>Manos a la Obra: Tu Primer Proyecto con Hono y Deno</h2><p>Ya te conté por qué me gusta <strong>Hono</strong>, ahora vamos a la práctica para que veas lo rápido que es empezar.</p><p>Primero, abre tu terminal, crea una carpeta para el proyecto y entra en ella:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> mi-proyecto-hono &amp;&amp; <span class="built_in">cd</span> mi-proyecto-hono</span><br></pre></td></tr></table></figure><p><strong>Deno</strong> tiene un comando muy práctico para inicializar proyectos que nos ahorra bastante trabajo. Usaremos el siguiente:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">deno init</span><br></pre></td></tr></table></figure><p>Este comando te creará una estructura básica con un <code>main.ts</code> y un <code>deno.json</code>. Ahora, para instalar <strong>Hono</strong>, agregamos la dependencia en el archivo <code>deno.json</code> y luego simplemente lo importamos en nuestro <code>main.ts</code>. <strong>Deno</strong> lo descargará y cacheará la primera vez que ejecutes el código.</p><p>Puedes agregar <strong>Hono</strong> como dependencia usando <strong>JSR</strong> de la siguiente forma, pero debes editar el archivo <code>deno.json</code> para corregir el alias en el import.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">deno add jsr:@hono/hono</span><br></pre></td></tr></table></figure><h2 id="El-corazon-de-tu-proyecto-deno-json"><a href="#El-corazon-de-tu-proyecto-deno-json" class="headerlink" title="El corazón de tu proyecto - deno.json"></a>El corazón de tu proyecto - <code>deno.json</code></h2><p>Antes de ver el código, echemos un vistazo al <code>deno.json</code>. Aquí es donde <strong>Deno</strong> gestiona las dependencias y tareas. Para usar <strong>Hono</strong>, podemos añadirlo a la sección <code>imports</code> o usar la línea de comandos de <code>deno</code> para agregar la dependencia:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;imports&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">   <span class="attr">&quot;hono&quot;</span><span class="punctuation">:</span> <span class="string">&quot;jsr:@hono/hono@^4.10.3&quot;</span> <span class="comment">// &lt;-- ojo con el alias</span></span><br><span class="line">  <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;tasks&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;start&quot;</span><span class="punctuation">:</span> <span class="string">&quot;deno run --allow-net main.ts&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>Un detalle importante es que, como ves, <strong>Hono</strong> está disponible en <strong>JSR</strong> (el nuevo registro de paquetes de JavaScript), lo que hace que manejar las versiones sea muy limpio.</p><h2 id="Primer-controlador"><a href="#Primer-controlador" class="headerlink" title="Primer controlador"></a>Primer controlador</h2><p>Ahora sí, el código de <code>main.ts</code>. Es tan simple y elegante como esto:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Hono</span> &#125; <span class="keyword">from</span> <span class="string">&quot;hono&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = <span class="keyword">new</span> <span class="title class_">Hono</span>();</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&quot;/&quot;</span>, <span class="function">(<span class="params">c</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> c.<span class="title function_">text</span>(<span class="string">&quot;Hello Hono!&quot;</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="title class_">Deno</span>.<span class="title function_">serve</span>(app.<span class="property">fetch</span>);</span><br></pre></td></tr></table></figure><p>¿Qué hace este código?</p><ol><li>Importa <code>Hono</code>.</li><li>Crea una nueva instancia de la aplicación.</li><li>Define una ruta para el método <code>GET</code> en la URL raíz (<code>/</code>).</li><li>Cuando alguien visita esa ruta, le devuelve el texto “Hello Hono!”.</li><li>Finalmente, <code>Deno.serve</code> inicia el servidor.</li></ol><p>Para ponerlo en marcha, usamos la tarea que definimos en <code>deno.json</code>:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">deno task start</span><br></pre></td></tr></table></figure><p>Como <strong>Deno</strong> es seguro por defecto, te pedirá permiso para acceder a la red. ¡Y listo! Ya tienes un servidor corriendo. Si usas una herramienta como <a href="https://httpie.io/">httpie</a>, verás esto:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">$ http :8000/</span><br><span class="line"></span><br><span class="line">HTTP/1.1 200 OK</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">Hello Hono!</span><br></pre></td></tr></table></figure><h2 id="¿Y-si-quiero-devolver-JSON"><a href="#¿Y-si-quiero-devolver-JSON" class="headerlink" title="¿Y si quiero devolver JSON?"></a>¿Y si quiero devolver JSON?</h2><p>Fácil. <strong>Hono</strong> tiene un método específico para eso. Simplemente cambia <code>c.text()</code> por <code>c.json()</code>:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">get</span>(<span class="string">&quot;/&quot;</span>, <span class="function">(<span class="params">c</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> c.<span class="title function_">json</span>(&#123; <span class="attr">message</span>: <span class="string">&quot;Hello Hono!&quot;</span> &#125;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>El resultado ahora será una respuesta JSON perfecta:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">$ http :8000/</span><br><span class="line"></span><br><span class="line">HTTP/1.1 200 OK</span><br><span class="line">content-type: application/json; charset=UTF-8</span><br><span class="line">...</span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">    &quot;message&quot;: &quot;Hello Hono!&quot;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>En solo unos minutos, hemos montado un servidor web funcional. Esta simplicidad y rapidez es lo que me terminó de convencer de la combinación de <strong>Hono</strong> y <strong>Deno</strong>.</p><h3 id="¿-Como-cambiar-el-puerto-del-servidor"><a href="#¿-Como-cambiar-el-puerto-del-servidor" class="headerlink" title="¿ Cómo cambiar el puerto del servidor ?"></a>¿ Cómo cambiar el puerto del servidor ?</h3><p>Esto me costó pillarlo en su momento, así que dejo aquí cómo se hace:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Deno</span>.<span class="title function_">serve</span>(&#123; <span class="attr">port</span>: <span class="number">8080</span> &#125;, app.<span class="property">fetch</span>);</span><br></pre></td></tr></table></figure><h2 id="Revisemos-algunos-middlewares-utiles"><a href="#Revisemos-algunos-middlewares-utiles" class="headerlink" title="Revisemos algunos middlewares útiles"></a>Revisemos algunos middlewares útiles</h2><h3 id="logger"><a href="#logger" class="headerlink" title="logger"></a>logger</h3><p>Un middleware bien útil es el de <em>logger</em>, permite registrar (o loggear) lo que entra y lo que sale a <strong>Hono</strong> (obviamente depende de la ubicación en el archivo principal de la aplicación.)</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Hono</span> &#125; <span class="keyword">from</span> <span class="string">&quot;hono&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; logger &#125; <span class="keyword">from</span> <span class="string">&quot;hono/logger&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = <span class="keyword">new</span> <span class="title class_">Hono</span>();</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">logger</span>());</span><br></pre></td></tr></table></figure><p>Con esta configuración se puede obtener este tipo de logs.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Listening on http://0.0.0.0:8000/ (http://localhost:8000/)</span><br><span class="line">&lt;-- GET /</span><br><span class="line">--&gt; GET / 200 0ms</span><br></pre></td></tr></table></figure><h3 id="etag"><a href="#etag" class="headerlink" title="etag"></a>etag</h3><p>La cabecera o <em>header</em> ETag (que viene de Entity Tag o “etiqueta de entidad”) es básicamente una huella digital o un identificador único que el servidor le asigna a una versión específica de un recurso (como una página, una imagen o un archivo JSON).</p><p>Imagina que tienes un archivo en tu servidor. Cada vez que modificas y guardas ese archivo, su ETag cambia. Es como el número de versión de ese recurso en un momento exacto.</p><p><strong>¿Y para qué sirve?</strong></p><p>Su propósito principal es hacer que el cacheo sea mucho más eficiente y ahorrar ancho de banda. El flujo es el siguiente:</p><ol><li>Primera Visita: Cuando tu navegador pide un recurso (ej: styles.css) por primera vez, el servidor se lo envía completo y, además, incluye el header ETag con su “huella digital”. Por ejemplo: ETag: “v1-a2b3c4d5”.</li><li>El Navegador Guarda la Huella: Tu navegador guarda el archivo styles.css en su caché y también anota su ETag.</li><li>Siguientes Visitas: La próxima vez que necesite ese mismo archivo, el navegador no lo pide a ciegas. En su lugar, le pregunta al servidor: “Oye, tengo una versión de styles.css con la huella v1-a2b3c4d5. ¿Sigue siendo la buena?”. Esto lo hace enviando un header llamado If-None-Match: “v1-a2b3c4d5”.</li><li>El Servidor Decide: <ul><li>Si la “huella digital” del archivo en el servidor coincide con la que envió el navegador, significa que el archivo no ha cambiado. El servidor responde con un 304 Not Modified. Este mensaje es muy liviano, no contiene el archivo, y básicamente le dice al navegador: “Todo sigue igual, usa la copia que ya tienes en tu caché”.</li><li>Si la “huella digital” no coincide, significa que el archivo fue actualizado. El servidor responde con un 200 OK, envía la nueva versión del archivo y, por supuesto, su nuevo <code>ETag</code>.</li></ul></li></ol><p>En resumen, el ETag permite al navegador evitar volver a descargar recursos que no han cambiado, haciendo que la navegación sea mucho más rápida y consuma menos datos. Además ayuda a las capas superiores de la aplicación a tomar mejores decisiones respecto del cache de la aplicación.</p><p>Ahora la configuración para <strong>Hono</strong>:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Hono</span> &#125; <span class="keyword">from</span> <span class="string">&quot;hono&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; etag &#125; <span class="keyword">from</span> <span class="string">&quot;hono/etag&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> app = <span class="keyword">new</span> <span class="title class_">Hono</span>();</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">etag</span>());</span><br></pre></td></tr></table></figure><p>Finalmente esta será la respuesta donde aparece una cabecera con el <strong>etag</strong>.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">http :8000/</span><br><span class="line">HTTP/1.1 200 OK</span><br><span class="line">content-length: 25</span><br><span class="line">content-type: application/json</span><br><span class="line">date: Tue, 28 Oct 2025 03:25:31 GMT</span><br><span class="line">etag: &quot;6e488564c25da2b4d7326d5ebfa92e957af61dcb&quot;</span><br><span class="line">vary: Accept-Encoding</span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">    &quot;message&quot;: &quot;Hello Hono!&quot;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="cors"><a href="#cors" class="headerlink" title="cors"></a>cors</h3><p>Probablemente, uno de los “problemas” más comunes al empezar a desarrollar una API es toparse con un error de CORS en el navegador.</p><p>Imagina que los sitios web son como reinos amurallados. Por seguridad, un reino (<code>tudominio.com</code>) no puede simplemente enviar un mensajero a pedirle recursos a otro reino (<code>api.otrodominio.com</code>). Esta regla se llama <strong>Política del Mismo Origen (Same-Origin Policy)</strong> y es fundamental para la seguridad en la web.</p><p>El middleware de CORS de <strong>Hono</strong> es el <strong>pasaporte diplomático</strong> que nos permite configurar qué “reinos” externos tienen permiso para comunicarse con nuestra API.</p><p>Por ejemplo, una configuración de CORS muy específica y segura podría ser así:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Hono</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;hono&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; cors &#125; <span class="keyword">from</span> <span class="string">&#x27;hono/cors&#x27;</span>;</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">use</span>(<span class="string">&#x27;/api/*&#x27;</span>, <span class="title function_">cors</span>(&#123;</span><br><span class="line">    <span class="attr">origin</span>: <span class="string">&#x27;http://example.com&#x27;</span>,</span><br><span class="line">    <span class="attr">allowMethods</span>: [<span class="string">&#x27;POST&#x27;</span>, <span class="string">&#x27;GET&#x27;</span>, <span class="string">&#x27;OPTIONS&#x27;</span>],</span><br><span class="line">    <span class="attr">allowHeaders</span>: [<span class="string">&#x27;X-Custom-Header&#x27;</span>, <span class="string">&#x27;Upgrade-Insecure-Requests&#x27;</span>],</span><br><span class="line">    <span class="attr">exposeHeaders</span>: [<span class="string">&#x27;Content-Length&#x27;</span>, <span class="string">&#x27;X-Kuma-Revision&#x27;</span>],</span><br><span class="line">    <span class="attr">maxAge</span>: <span class="number">600</span>,</span><br><span class="line">    <span class="attr">credentials</span>: <span class="literal">true</span>,</span><br><span class="line">&#125;));</span><br></pre></td></tr></table></figure><p>Analicemos las reglas que hemos definido en este bloque:</p><ul><li><strong><code>app.use(&#39;/api/*&#39;, ...)</code></strong>: Primero, le indicamos a <strong>Hono</strong> que aplique este middleware <strong>únicamente</strong> a las rutas que comiencen con <code>/api/</code>. Esto es muy práctico para tener políticas de seguridad distintas para diferentes partes de tu aplicación.</li><li><strong><code>origin: &#39;http://example.com&#39;</code></strong>: La regla más importante. Se especifica que <strong>solo</strong> las peticiones que vengan desde <code>http://example.com</code> están permitidas.</li><li><strong><code>allowMethods: [...]</code></strong>: Define qué métodos HTTP están autorizados (<code>POST</code>, <code>GET</code>, <code>OPTIONS</code>). Un <code>DELETE</code> sería bloqueado.</li><li><strong><code>allowHeaders: [...]</code></strong>: Una lista blanca de las cabeceras HTTP que el cliente tiene permitido enviar.</li><li><strong><code>exposeHeaders: [...]</code></strong>: Permite que el código JavaScript del cliente pueda leer cabeceras de la respuesta que, por defecto, el navegador oculta por seguridad, como <code>Content-Length</code>.</li><li><strong><code>maxAge: 600</code></strong>: Una optimización de rendimiento. Indica al navegador que puede guardar en caché el resultado de la petición de “verificación” (<em>preflight</em>) durante 600 segundos (10 minutos).</li><li><strong><code>credentials: true</code></strong>: Esencial si tu frontend necesita enviar credenciales como <strong>cookies</strong> o cabeceras de <strong>autenticación (Authorization)</strong>.</li></ul><p>En resumen, este middleware te da un control muy granular para configurar una política de CORS segura, una práctica mucho más recomendable que simplemente abrir el acceso a todo el mundo con <code>origin: &#39;*&#39;</code>.</p><h3 id="Palabras-al-Cierre"><a href="#Palabras-al-Cierre" class="headerlink" title="Palabras al Cierre"></a>Palabras al Cierre</h3><p>Como hemos visto en este recorrido, <strong>Hono</strong> se presenta como una alternativa muy atractiva en el ecosistema de <a href="/tags/javascript/"><strong>JavaScript</strong></a> y <a href="/tags/typescript/"><strong>TypeScript</strong></a>. Su filosofía minimalista, su rendimiento y, sobre todo, su capacidad para adaptarse a cualquier entorno de ejecución, lo convierten en una herramienta que vale la pena tener en nuestro arsenal.</p><p>Personalmente, la combinación de la simplicidad de <strong>Hono</strong> con la seguridad y el entorno moderno de <strong>Deno</strong> ha hecho que desarrollar APIs vuelva a ser una experiencia ágil y productiva.</p><p>Pero esto es solo el comienzo. Este artículo es el primero de una serie donde exploraremos a fondo el ecosistema de <strong>Deno</strong> y <strong>Hono</strong>. En las próximas entregas, veremos temas un poco más avanzados como:</p><ul><li>Creación de nuestros propios middlewares.</li><li>Helpers de <strong>Hono</strong></li><li>Rutas avanzadas y manejo de grupos.</li><li>Estrategias de <em>testing</em> para nuestras APIs.</li></ul><p>Te invito a que experimentes con lo que hemos visto hoy y, por supuesto, a que te mantengas atento para los próximos artículos de la serie.</p><hr><h3 id="Referencias-Utiles"><a href="#Referencias-Utiles" class="headerlink" title="Referencias Útiles"></a>Referencias Útiles</h3><p>Aquí te dejo una lista de enlaces que te serán de gran ayuda para profundizar en <strong>Hono</strong> y <strong>Deno</strong>:</p><ul><li><a href="https://hono.dev/"><strong>Sitio y Documentación Oficial de Hono</strong></a>: El mejor lugar para empezar y la fuente de consulta principal.</li><li><a href="https://github.com/honojs/hono"><strong>Repositorio de Hono en GitHub</strong></a>: Para ver el código fuente, reportar issues o contribuir.</li><li><a href="https://hono.dev/middleware"><strong>Middleware de Hono</strong></a>: La lista completa de middlewares oficiales disponibles.</li><li><a href="https://hono.dev/docs/concepts/benchmarks"><strong>Benchmarks de Rendimiento de Hono</strong></a>: Para los que se preguntan qué tan rápido es Hono en realidad.</li><li><a href="https://deno.land/"><strong>Sitio y Documentación Oficial de Deno</strong></a>: Indispensable para entender el entorno de ejecución.</li><li><a href="https://jsr.io/"><strong>JSR (JavaScript Registry)</strong></a>: El nuevo registro de paquetes para JavaScript y TypeScript, donde <strong>Hono</strong> y muchos otros módulos modernos residen.</li><li><a href="https://httpie.io/"><strong>httpie</strong></a>: El cliente HTTP para terminal usado en los ejemplos.</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;img src=&quot;/images/2025/hono_logo.png&quot; class=&quot;&quot; title=&quot;Hono Logo&quot;&gt;

&lt;p&gt;Cuando me enfrento a un nuevo proyecto, ya sea una API para una aplica</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    <category term="TypeScript" scheme="https://blog.pcollaog.cl/categories/Programming/TypeScript/"/>
    
    
    <category term="web" scheme="https://blog.pcollaog.cl/tags/web/"/>
    
    <category term="javascript" scheme="https://blog.pcollaog.cl/tags/javascript/"/>
    
    <category term="framework" scheme="https://blog.pcollaog.cl/tags/framework/"/>
    
    <category term="expressjs" scheme="https://blog.pcollaog.cl/tags/expressjs/"/>
    
    <category term="typescript" scheme="https://blog.pcollaog.cl/tags/typescript/"/>
    
    <category term="hono" scheme="https://blog.pcollaog.cl/tags/hono/"/>
    
    <category term="deno" scheme="https://blog.pcollaog.cl/tags/deno/"/>
    
    <category term="rest" scheme="https://blog.pcollaog.cl/tags/rest/"/>
    
  </entry>
  
  <entry>
    <title>Deno: ¿Una alternativa real a Node.js?</title>
    <link href="https://blog.pcollaog.cl/2025/10/23/Deno-una-alternativa-a-node-js/"/>
    <id>https://blog.pcollaog.cl/2025/10/23/Deno-una-alternativa-a-node-js/</id>
    <published>2025-10-23T15:37:08.000Z</published>
    <updated>2025-11-01T19:36:46.063Z</updated>
    
    <content type="html"><![CDATA[<img src="/images/2025/deno_logo.svg" class="" width="100" height="100" title="Deno Logo"><p>Si te mueves en el mundo de JavaScript, seguro que Node.js es tu pan de cada día. Pero, ¿has oído hablar de <strong>Deno</strong>? Y no, no es solo “Node” al revés (aunque el guiño es genial). Deno es un runtime para JavaScript y TypeScript creado por el mismísimo Ryan Dahl, el padre de Node.js.</p><p>Imagínate que creas algo increíble, pero con el tiempo te das cuenta de que podrías haberlo hecho mejor. Eso es Deno para Ryan Dahl. Es su oportunidad de redimirse y arreglar lo que él considera los “errores de diseño” de Node.js. El resultado es un entorno de ejecución más moderno, seguro y con una experiencia de desarrollo que te va a sorprender.</p><h2 id="¿Que-hace-a-Deno-tan-especial"><a href="#¿Que-hace-a-Deno-tan-especial" class="headerlink" title="¿Qué hace a Deno tan especial?"></a>¿Qué hace a Deno tan especial?</h2><h3 id="¡A-programar-desde-el-minuto-cero"><a href="#¡A-programar-desde-el-minuto-cero" class="headerlink" title="¡A programar desde el minuto cero!"></a>¡A programar desde el minuto cero!</h3><p>Una de las cosas que más me gustan de Deno es que viene con todo lo que necesitas para empezar a trabajar. ¿Cansado de configurar <strong>ESLint</strong>, <strong>Prettier</strong>, <strong>Jest</strong> y un montón de dependencias de desarrollo cada vez que empiezas un proyecto?</p><p>Deno incluye <em>out of the box</em>:</p><ul><li><strong>Un formateador de código (<code>deno fmt</code>):</strong> Para que tu código siempre luzca impecable y consistente.</li><li><strong>Un linter (<code>deno lint</code>):</strong> Para detectar problemas y mantener la calidad del código.</li><li><strong>Un runner de tests (<code>deno test</code>):</strong> Con soporte para tests unitarios y de integración, al estilo BDD (como Jest) o al estilo de Deno con <code>Deno.test</code>.</li><li><strong>Soporte nativo para TypeScript:</strong> Sin necesidad de instalar <code>tsc</code> ni configurar <code>tsconfig.json</code>. Escribes en TypeScript y Deno se encarga del resto.</li><li><strong>Un repositorio de librerías (JSR)</strong>, Deno tiene su propio ecosistema de dependencias llamado <strong>JSR</strong>. Pero en las últimas versiones ahora soporta librerías del ecosistema de <strong>NPM</strong>.</li></ul><p>Esto significa menos tiempo configurando y más tiempo programando. ¡Productividad al máximo desde el primer momento! Toda la configuración del entorno queda en el archivo <code>deno.json</code> y de esta forma es fácil de transportar, lo subes al repositorio y todo tu equipo lo usa (y lo va mejorando).</p><h3 id="Seguridad-Tu-tienes-el-control"><a href="#Seguridad-Tu-tienes-el-control" class="headerlink" title="Seguridad: Tú tienes el control"></a>Seguridad: Tú tienes el control</h3><p>Otro de los pilares de Deno es la seguridad. A diferencia de Node.js, donde un script puede acceder a tu sistema de archivos, a la red o a las variables de entorno sin que te des cuenta, Deno ejecuta el código en un sandbox.</p><p>Por defecto, un script de Deno no tiene permisos para hacer nada “peligroso”. Si necesita acceder a la red, al sistema de archivos o a cualquier otra cosa, tienes que dárselo explícitamente con flags al ejecutar el comando:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Permite leer del sistema de archivos</span></span><br><span class="line">deno run --allow-read mi_script.ts</span><br><span class="line"></span><br><span class="line"><span class="comment"># Permite conexiones de red</span></span><br><span class="line">deno run --allow-net mi_script.ts</span><br><span class="line"></span><br><span class="line"><span class="comment"># ¡Permite todo! (Úsalo con cuidado)</span></span><br><span class="line">deno run -A mi_script.ts</span><br></pre></td></tr></table></figure><p>Este modelo de permisos explícitos te da un control total sobre lo que tus dependencias pueden y no pueden hacer, evitando sorpresas desagradables.</p><h3 id="Gestion-de-dependencias"><a href="#Gestion-de-dependencias" class="headerlink" title="Gestión de dependencias"></a>Gestión de dependencias</h3><p>En Deno, no existe la carpeta <code>node_modules</code> ni el archivo <code>package.json</code>. Las dependencias se importan directamente desde una URL, como en el navegador:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; serve &#125; <span class="keyword">from</span> <span class="string">&quot;https://deno.land/std@0.140.0/http/server.ts&quot;</span>;</span><br></pre></td></tr></table></figure><p>La forma de hacer los imports con las urls en los archivos TS, a mi modo de ver, es poco mantenible. Se hicieron varios esfuerzos para que sea una vía simple de mantener, pero al parecer llegaron a algo como un administrador de dependencias centralizado en el archivo <code>deno.json</code>. En las últimas versiones, además, agregaron soporte para incluir dependencias del ecosistema de <strong>NPM</strong>, de esta forma, se amplió la cantidad de librerías que puedes usar.</p><p>Si vas a usar dependencias de NPM, a veces se genera un archivo <code>package.json</code> muy básico con el propósito de agregar dependencias solamente.</p><p>Deno descarga y cachea las dependencias la primera vez que se ejecuta el script. Si quieres asegurarte de que las dependencias no cambien, puedes usar un archivo <code>deno.json</code> (o <code>deno.jsonc</code>) para gestionar las versiones, de forma similar a como lo harías con un <code>package.json</code>, pero mucho más simple.</p><h2 id="Un-ejemplo-rapido"><a href="#Un-ejemplo-rapido" class="headerlink" title="Un ejemplo rápido"></a>Un ejemplo rápido</h2><p>La mejor forma de entenderlo es probándolo. ¡Vamos a crear un pequeño proyecto!</p><h3 id="1-Instalacion"><a href="#1-Instalacion" class="headerlink" title="1. Instalación"></a>1. Instalación</h3><p>Deno está disponible para la mayoría de los sistemas operativos. Pásate por la <a href="https://deno.land/manual/getting_started/installation">página de instalación</a>, busca tu SO y sigue los pasos.</p><h3 id="2-Inicializando-el-proyecto"><a href="#2-Inicializando-el-proyecto" class="headerlink" title="2. Inicializando el proyecto"></a>2. Inicializando el proyecto</h3><p>Una vez instalado, crear un proyecto es tan fácil como esto:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">mkdir</span> mi-proyecto-deno &amp;&amp; <span class="built_in">cd</span> mi-proyecto-deno</span><br><span class="line">$ deno init</span><br><span class="line"></span><br><span class="line">✅ Project initialized</span><br><span class="line"></span><br><span class="line">Run these commands to get started</span><br><span class="line"></span><br><span class="line">  <span class="comment"># Run the program</span></span><br><span class="line">  deno run main.ts</span><br><span class="line"></span><br><span class="line">  <span class="comment"># Run the program and watch for file changes</span></span><br><span class="line">  deno task dev</span><br><span class="line"></span><br><span class="line">  <span class="comment"># Run the tests</span></span><br><span class="line">  deno <span class="built_in">test</span></span><br></pre></td></tr></table></figure><p>¡Y ya está! Deno te crea tres archivos:</p><ul><li><code>deno.json</code>: El corazón de tu proyecto, similar al <code>package.json</code>.</li><li><code>main.ts</code>: Tu punto de entrada.</li><li><code>main_test.ts</code>: Un archivo de ejemplo para tus tests.</li></ul><h3 id="3-El-codigo"><a href="#3-El-codigo" class="headerlink" title="3. El código"></a>3. El código</h3><p>El archivo <code>main.ts</code> que se genera es súper simple:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">add</span>(<span class="params"><span class="attr">a</span>: <span class="built_in">number</span>, <span class="attr">b</span>: <span class="built_in">number</span></span>): <span class="built_in">number</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> a + b;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Learn more at https://docs.deno.com/runtime/manual/examples/module_metadata#concepts</span></span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">import</span>.<span class="property">meta</span>.<span class="property">main</span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;2 + 3 =&quot;</span>, <span class="title function_">add</span>(<span class="number">2</span>, <span class="number">3</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Puedes ejecutarlo con <code>deno run main.ts</code> y verás en la consola:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">2 + 3 = 5</span><br></pre></td></tr></table></figure><h3 id="4-Los-tests"><a href="#4-Los-tests" class="headerlink" title="4. Los tests"></a>4. Los tests</h3><p>Y el archivo de test, <code>main_test.ts</code>, no se queda atrás en simplicidad:</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; assertEquals &#125; <span class="keyword">from</span> <span class="string">&quot;@std/assert&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; add &#125; <span class="keyword">from</span> <span class="string">&quot;./main.ts&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="title class_">Deno</span>.<span class="title function_">test</span>(<span class="keyword">function</span> <span class="title function_">addTest</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="title function_">assertEquals</span>(<span class="title function_">add</span>(<span class="number">2</span>, <span class="number">3</span>), <span class="number">5</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>Ejecútalo con <code>deno test</code> y verás que todo funciona como la seda:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Check file:///Users/pcollaog/mi-proyecto-deno/main_test.ts</span><br><span class="line">running 1 test from ./main_test.ts</span><br><span class="line">addTest ... ok (0ms)</span><br><span class="line"></span><br><span class="line">ok | 1 passed | 0 failed (3ms)</span><br></pre></td></tr></table></figure><h2 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusión"></a>Conclusión</h2><p>Como ves, Deno no es solo un capricho. Es una propuesta seria que replantea el desarrollo del lado del servidor con JavaScript&#x2F;TypeScript, poniendo el foco en la seguridad, la simplicidad y una experiencia de desarrollo moderna y sin fricciones.</p><p>Si vienes de Node.js, la curva de aprendizaje es mínima y las ventajas son enormes. Menos configuración, más seguridad y un conjunto de herramientas unificado que te hará la vida más fácil.</p><p>¿Mi recomendación? Dale una oportunidad. Puede que te sorprendas y encuentres a tu nuevo mejor amigo para tus proyectos de backend.</p><p>¿Y tú, ya has probado Deno? ¡Cuéntame tu experiencia en los comentarios!</p><p>En un próximo artículo, profundizaré en mi experiencia con los frameworks web más populares para Deno.</p><hr><h2 id="Referencias"><a href="#Referencias" class="headerlink" title="Referencias"></a>Referencias</h2><ul><li><a href="https://deno.land/">Sitio oficial de Deno</a></li><li><a href="https://deno.land/manual">Manual de Deno</a></li><li><a href="https://jsr.io/">JSR: The JavaScript Registry</a></li><li><a href="https://www.youtube.com/watch?v=M3BM9TB-8yA">10 Things I Regret About Node.js - Ryan Dahl - JSConf EU (YouTube)</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;img src=&quot;/images/2025/deno_logo.svg&quot; class=&quot;&quot; width=&quot;100&quot; height=&quot;100&quot; title=&quot;Deno Logo&quot;&gt;

&lt;p&gt;Si te mueves en el mundo de JavaScript, segur</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    <category term="TypeScript" scheme="https://blog.pcollaog.cl/categories/Programming/TypeScript/"/>
    
    
    <category term="javascript" scheme="https://blog.pcollaog.cl/tags/javascript/"/>
    
    <category term="nodejs" scheme="https://blog.pcollaog.cl/tags/nodejs/"/>
    
    <category term="typescript" scheme="https://blog.pcollaog.cl/tags/typescript/"/>
    
    <category term="deno" scheme="https://blog.pcollaog.cl/tags/deno/"/>
    
  </entry>
  
  <entry>
    <title>conventional commits y algunas herramientas de apoyo</title>
    <link href="https://blog.pcollaog.cl/2024/04/22/Conventional-Commits/"/>
    <id>https://blog.pcollaog.cl/2024/04/22/Conventional-Commits/</id>
    <published>2024-04-22T13:12:40.000Z</published>
    <updated>2025-11-01T19:36:46.063Z</updated>
    
    <content type="html"><![CDATA[<h2 id="¿-que-es-conventional-commits"><a href="#¿-que-es-conventional-commits" class="headerlink" title="¿ qué es conventional commits ?"></a>¿ qué es conventional commits ?</h2><p><a href="https://commitlint.js.org/">CommitLint</a> es una herramienta que ayuda a adoptar una convención para escribir commits de forma estandarizada. esta convención se llama <a href="https://www.conventionalcommits.org/"><strong>Conventional Commits</strong></a> y esta relacionada con un estándar a la hora de versionar artefactos llamada <a href="https://semver.org/"><strong>Semantic Versioning</strong></a>.</p><p>La especificación de <strong>Conventional Commits</strong> es una convención sobre cómo escribir los mensajes de commits (específicamente el título del commit). Además nos provee de un conjunto sencillo de reglas para crear un <strong>CHANGELOG</strong> de commits explícito; lo que hace más fácil escribir herramientas encima del historial. Esta convención encaja con <strong>SemVer</strong>, al describir en los mensajes de los commits las funcionalidades, parches y cambios de ruptura hechos.</p><p>El mensaje del commit debe ser estructurado de la siguiente manera:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;tipo&gt;(ámbito opcional): &lt;descripción&gt;</span><br><span class="line"></span><br><span class="line">[cuerpo opcional]</span><br><span class="line"></span><br><span class="line">[nota(s) al pie opcional(es)]</span><br></pre></td></tr></table></figure><p>Por ejemplo:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">fix(api): se corrige validacion de email</span><br><span class="line"></span><br><span class="line">Se agregan nuevos dominios a la validación del correo</span><br><span class="line"></span><br><span class="line">Issue #2</span><br></pre></td></tr></table></figure><p>Los <code>tipos</code> que más se utilizan en Conventional Commits son los siguientes:</p><ul><li><strong>feat</strong>: Se agrega una nueva característica</li><li><strong>fix</strong>: Se corrige algún problema</li><li><strong>chore</strong>: Se modifican archivos que rodean el código fuente (configuraciones, cambios de versión)</li><li><strong>refactor</strong>: Refactorización del código</li><li><strong>docs</strong>: se agrega o modifica documentación</li><li><strong>test</strong>: Se agrega o modifican tests</li></ul><p>Los tipos relevantes a la hora de generar valor en el <strong>CHANGELOG</strong> son los <strong>feat</strong> y los <strong>fix</strong>, en base a esos tipos se construye de forma automática la bitácora de cambios relevantes (útil al usar <em>standard-version</em>, leer mas adelante)</p><h2 id="Instalar-commitlint"><a href="#Instalar-commitlint" class="headerlink" title="Instalar commitlint"></a>Instalar commitlint</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn add -D @commitlint/&#123;cli,config-conventional&#125; </span><br></pre></td></tr></table></figure><p>Si estas usando <code>commonsjs</code> debes cambiar el <code>export default</code> por <code>module.exports</code>. debes revisar el atributo <strong>type</strong> dentro del archivo <code>package.json</code>.</p><p>Ejecuta el siguiente comando para crear el archivo <code>commitlint.config.js</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">echo</span> <span class="string">&quot;export default &#123; extends: [&#x27;@commitlint/config-conventional&#x27;] &#125;;&quot;</span> &gt; commitlint.config.js</span><br></pre></td></tr></table></figure><p>O agregar este archivo en la raíz del proyecto:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123; </span><br><span class="line">  <span class="attr">extends</span>: [<span class="string">&#x27;@commitlint/config-conventional&#x27;</span>] </span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Demás esta decir que puedes extender la configuración y acomodarla a tus necesidades, sólo considerar que las  herramientas que se basan en estas convenciones también deberás adaptarlas y en otros casos es posible que no te sirvan.</p><h2 id="husky"><a href="#husky" class="headerlink" title="husky"></a>husky</h2><p><a href="https://typicode.github.io/husky/">Husky</a> es una herramienta que permite gestionar de forma simple git-hooks y que nos permite que cada vez que hagamos un commit, por ejemplo, corra los test unitarios o que nos revise si el commit message cumple con la convención de conventional commits (que es nuestro caso).</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">yarn add -D husky </span><br><span class="line">yarn husky init </span><br><span class="line"></span><br><span class="line">npm pkg <span class="built_in">set</span> scripts.commitlint=<span class="string">&quot;commitlint --edit&quot;</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;yarn commitlint \$&#123;1&#125;&quot;</span> &gt; .husky/commit-msg</span><br></pre></td></tr></table></figure><p>El ultimo comando (el echo), genera un archivo cuyo contenido es la ejecución de commitlint y será ubicado en el directorio de los hooks de <em>husky</em>.</p><p><strong>Nota</strong>: Cuando ejecutas el comando <code>yarn husky init</code> este te genera un directorio llamando <code>.husky</code> y dentro quedará un archivo llamado <code>pre-commit</code> con el siguiente contenido:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn <span class="built_in">test</span></span><br></pre></td></tr></table></figure><p>Esto quiere decir que antes de que se realice el commit, husky ejecurata el comando <code>yarn test</code> y si este comando sale sin problemas, se efectuará el commit, en caso contrario los archivos no serán agregados al historial. </p><h2 id="standard-version"><a href="#standard-version" class="headerlink" title="standard version"></a>standard version</h2><p>Otra herramienta que nos puede ayudar a mejorar la forma en que realizamos los releases, es una utilidad llamada standard-version (es algo vieja pero funciona perfectamente). Según su propia descripción: </p><blockquote><p>Una utilidad para el versionamiento usando <em>semver</em> y generación de <em>CHANGELOG</em> potenciados por <strong>conventional commits</strong>.</p></blockquote><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn add -D standard-version</span><br></pre></td></tr></table></figure><p>Una vez agregada la librería se debe agregar un comando en la sección de scripts en el package.json (sólo para mayor comodidad).</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">&quot;scripts&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">  ...</span><br><span class="line">  <span class="attr">&quot;release&quot;</span><span class="punctuation">:</span> <span class="string">&quot;standard-version&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;pre-release&quot;</span><span class="punctuation">:</span> <span class="string">&quot;standard-version --dry-run&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>Con eso ya puedes usar los comandos <strong>release</strong> y <strong>pre-release</strong>, el primero para concretar el release y el segundo es para ver como quedará de forma verbosa pero sin afectar el repositorio. Por ejemplo:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">$ yarn pre-release</span><br><span class="line"></span><br><span class="line">yarn run v1.22.19</span><br><span class="line">$ standard-version --dry-run</span><br><span class="line">✔ bumping version <span class="keyword">in</span> package.json from 1.0.0 to 1.1.0</span><br><span class="line">✔ created CHANGELOG.md</span><br><span class="line">✔ outputting changes to CHANGELOG.md</span><br><span class="line"></span><br><span class="line">---</span><br><span class="line"><span class="comment">## 1.1.0 (2024-04-22)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">### Features</span></span><br><span class="line"></span><br><span class="line">* se agrega busqueda de app por su <span class="built_in">id</span></span><br><span class="line">* se agrega funcion para eliminar aplicacion</span><br><span class="line">* se agrega persistencia (find,delete,create)  de app</span><br><span class="line">* se agrega persistencia de eventos por app</span><br><span class="line">* se agrega validacion de esquema para applicacion</span><br><span class="line">* se agregan controladores para aplicaciones y logs</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">### Bug Fixes</span></span><br><span class="line"></span><br><span class="line">* **ci:** se corrige nombre de la imagen mongodb</span><br><span class="line">* **ci:** se corrige script para <span class="built_in">test</span>, falta instalar deps</span><br><span class="line">* se corrigen <span class="built_in">test</span> unitarios</span><br><span class="line">* se incluye close connection</span><br><span class="line">---</span><br><span class="line"></span><br><span class="line">✔ committing package.json and CHANGELOG.md</span><br><span class="line">✔ tagging release v1.1.0</span><br><span class="line">ℹ Run `git push --follow-tags origin develop` to publish</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Nótese que el comando de <strong>pre-release</strong> nos indica exactamente lo que hará el comando <strong>release</strong>, donde hay que resaltar la linea <code>bumping version in package.json from 1.0.0 to 1.1.0</code> que indica, en función de commits messages, califican para cambio de minor (feat agregados) o patch (fix agregados). Por ejemplo… si entre versiones solo tienes commits messages con <strong>fix</strong> cuando hagas el release, lo hara modificando el dígito del patch, por otro lado, si agregas un nuevo feature (feat) te modificará el minor en la versión.</p><p>Si requieres hacer un versionamiento manual debes ejecutar el siguiente comando:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn release --releas-as 1.1.1</span><br></pre></td></tr></table></figure><p>Con eso fuerzas a que la versión sea la que indicas como argumento.</p><h3 id="GitFlow"><a href="#GitFlow" class="headerlink" title="GitFlow"></a>GitFlow</h3><p>Si usas git-flow como modelo de ramas, te sugiero configurar <strong>standard-version</strong> para que no realice el tag una vez que hagas el release, de esta forma le delegas dicha función a git-flow. Les dejo el archivo de configuración que se llama <code>.versionrc</code> y debe estar ubicado en la raíz del proyecto:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;skip&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;tag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>Con esta configuración, puedes lanzar los comandos de release en la rama <em>hotfix</em> o <em>release</em> y luego finalizas las rama con git-flow.</p><h2 id="Palabras-al-cierre"><a href="#Palabras-al-cierre" class="headerlink" title="Palabras al cierre"></a>Palabras al cierre</h2><p>Espero les sirva este pequeño post sobre herramientas de desarrollo que utilizo en el día a día y sus configuraciones.</p><p>Les dejo los links de las referencias:</p><ul><li><a href="https://commitlint.js.org/">CommitLint - Lint commit messages</a></li><li><a href="https://semver.org/">Semantic Versioning</a></li><li><a href="https://www.npmjs.com/package/standard-version">Standard Version</a></li><li><a href="https://typicode.github.io/husky/">Husky</a></li><li><a href="https://www.conventionalcommits.org/">Conventional Commits</a></li><li><a href="https://github.com/petervanderdoes/gitflow-avh">git-flow (AVH Edition)</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;¿-que-es-conventional-commits&quot;&gt;&lt;a href=&quot;#¿-que-es-conventional-commits&quot; class=&quot;headerlink&quot; title=&quot;¿ qué es conventional commits ?&quot;&gt;&lt;</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    
    <category term="javascript" scheme="https://blog.pcollaog.cl/tags/javascript/"/>
    
    <category term="git" scheme="https://blog.pcollaog.cl/tags/git/"/>
    
    <category term="development" scheme="https://blog.pcollaog.cl/tags/development/"/>
    
    <category term="yarn" scheme="https://blog.pcollaog.cl/tags/yarn/"/>
    
    <category term="semver" scheme="https://blog.pcollaog.cl/tags/semver/"/>
    
    <category term="devtools" scheme="https://blog.pcollaog.cl/tags/devtools/"/>
    
    <category term="git-flow" scheme="https://blog.pcollaog.cl/tags/git-flow/"/>
    
    <category term="linter" scheme="https://blog.pcollaog.cl/tags/linter/"/>
    
  </entry>
  
  <entry>
    <title>AWS Lambda - ESM Node.js</title>
    <link href="https://blog.pcollaog.cl/2023/06/04/ESM-AWS-Lambda/"/>
    <id>https://blog.pcollaog.cl/2023/06/04/ESM-AWS-Lambda/</id>
    <published>2023-06-05T01:15:50.000Z</published>
    <updated>2025-11-01T19:36:46.063Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Algunas-generalidades-previas"><a href="#Algunas-generalidades-previas" class="headerlink" title="Algunas generalidades previas"></a>Algunas generalidades previas</h1><p>En la mayoría de los paradigmas de programación, podemos encontrar sistemas que nos permiten auto organizar el código en pequeñas piezas o para incorporar librerías&#x2F;bibliotecas de terceros a nuestro código. Al combinar todo lo anterior resulta una pieza de código más grande y compleja.</p><p>Desde un inicio Javascript utilizó el sistema de carga de módulos llamado CommonsJS (CJS) y es parte integral de Node.js hasta la version <strong>v8.5.0</strong> donde se incorpora un nuevo sistema de carga de módulos, ESM. A partir de la version <strong>v13.2.0</strong> de Node.js fue estabilizado e incorporado como un nuevo estándar.</p><h1 id="¿-Por-que-deberiamos-usar-ESM-en-AWS-Lambdas"><a href="#¿-Por-que-deberiamos-usar-ESM-en-AWS-Lambdas" class="headerlink" title="¿ Por qué deberíamos usar ESM en AWS Lambdas ?"></a>¿ Por qué deberíamos usar ESM en AWS Lambdas ?</h1><p><a href="https://aws.amazon.com/es/blogs/compute/author/jbeswick/">James Beswick</a> (Principal Developer Advocate for the AWS Serverless Team) escribió un artículo titulado <strong><a href="https://aws.amazon.com/es/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda/">Using Node.js ES modules and top-level await in AWS Lambda</a></strong> ,donde detalla el por qué y en qué casos deberías usar ESM como cargador de módulos de Javascript en el contexto de un AWS Lambda. Uno de los motivos más importantes de usar ESM, es que la carga en frío de un lambda tarda casi un tercio en comparación con CommonsJS.</p><p>Dejo aquí la comparativa entre CJS y ESM donde en el p99 (carga en frío) la partida se reduce a un tercio mejorando el rendimiento en un 43,5%. Para esta prueba, todas las métricas de ESM salieron por debajo (mejores en tiempo) de las de CJS es simplemente marginal (alrededor de 2-5ms).</p><img src="https://d2908q01vomqb2.cloudfront.net/1b6453892473a467d07372d45eb05abc2031647a/2021/12/22/await3-1024x400.png" class=""><h1 id="¿-Como-usamos-ESM-en-AWS-Lambdas"><a href="#¿-Como-usamos-ESM-en-AWS-Lambdas" class="headerlink" title="¿ Cómo usamos ESM en AWS Lambdas ?"></a>¿ Cómo usamos ESM en AWS Lambdas ?</h1><h2 id="Configuracion-del-artefacto-package-json"><a href="#Configuracion-del-artefacto-package-json" class="headerlink" title="Configuración del artefacto - package.json"></a>Configuración del artefacto - package.json</h2><p>Primero que todo se deben ajustar un par de atributos en el archivo <code>package.json</code> para indicar que el módulo es del tipo ESM.</p><figure class="highlight json"><figcaption><span>package.json</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;serverless-lambda-esm&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;version&quot;</span><span class="punctuation">:</span> <span class="string">&quot;1.0.0-beta&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;description&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Serverless Lambda ESM&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;main&quot;</span><span class="punctuation">:</span> <span class="string">&quot;src/Handler.js&quot;</span><span class="punctuation">,</span> <span class="comment">// &lt;-- Sera cargado como módulo</span></span><br><span class="line">  <span class="attr">&quot;license&quot;</span><span class="punctuation">:</span> <span class="string">&quot;UNLICENSED&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;private&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;module&quot;</span><span class="punctuation">,</span> <span class="comment">// &lt;-- Este atributo debe tener el valor: module</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>Con este ajuste le indicamos al cargador que trate los archivos como ES módulos según su extensión, es decir, con el atributo <code>type</code> y valor en <code>module</code> todos los archivos con extensión <code>.js</code> serán tratados como ESM. Si por alguna razón quieres mezclar ambos mundos debes hacerlo de forma explícita usando como extensión <code>.cjs</code>. Por el contrario, si no utilizas el atributo <code>type</code> o lo dejas con valor <code>commonjs</code>, todos los archivos con extension <code>.js</code> serán tratados como CJS y si quieres utilizar ESM estos deben tener extension <code>.mjs</code>.</p><h2 id="Preparamos-el-Handler"><a href="#Preparamos-el-Handler" class="headerlink" title="Preparamos el Handler"></a>Preparamos el Handler</h2><figure class="highlight javascript"><figcaption><span>Handler.js</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">DateTime</span> &#125; <span class="keyword">from</span> <span class="string">&quot;luxon&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">*</span>&#125; <span class="variable">event</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@returns</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">handler</span> = <span class="keyword">async</span> (<span class="params">event, context</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> date = <span class="title class_">DateTime</span>.<span class="title function_">now</span>().<span class="title function_">toFormat</span>(<span class="string">&quot;yyyy-MM-dd&quot;</span>);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Date: &quot;</span>, date);</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(event));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        <span class="attr">statusCode</span>: <span class="number">200</span>,</span><br><span class="line">        <span class="attr">body</span>: <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(&#123; <span class="attr">message</span>: <span class="string">&quot;ok&quot;</span> &#125;)</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>El handler debe estar expuesto de esa forma para que sea cargado como ESM. Se puede apreciar que ya no usamos la sentencia <code>require</code> para cargar una dependencia externa (en esta caso <code>luxon</code>) y en su reemplazo utilizamos <code>import</code>.</p><p>Algunos detallitos que he ido aprendiendo en el camino y que no está muy explícito en la documentación, es que los <code>imports</code> de nuestros archivos, es decir, el código que está dentro del proyecto, deben ser cargados y nombrados con su extensión, dejo un ejemplo:</p><figure class="highlight javascript"><figcaption><span>Handler.js</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">DateTime</span> &#125; <span class="keyword">from</span> <span class="string">&quot;luxon&quot;</span>; <span class="comment">// &lt;-- Sin la extension (lib)</span></span><br><span class="line"><span class="keyword">import</span> <span class="title class_">Service</span> <span class="keyword">from</span> <span class="string">&#x27;./service/Service.js&#x27;</span>; <span class="comment">// &lt;-- Con la extension</span></span><br></pre></td></tr></table></figure><h2 id="Export-de-los-modulos"><a href="#Export-de-los-modulos" class="headerlink" title="Export de los módulos"></a>Export de los módulos</h2><figure class="highlight javascript"><figcaption><span>Service.js</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title class_">Service</span> = &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Funcion</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="attr">doSomething</span>: <span class="title function_">async</span>(event)=&gt;&#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Event: &quot;</span>, <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(event));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="title class_">Service</span>; <span class="comment">// &lt;-- Así se exponen los módulos al código</span></span><br></pre></td></tr></table></figure><h2 id="Palabras-al-cierre"><a href="#Palabras-al-cierre" class="headerlink" title="Palabras al cierre"></a>Palabras al cierre</h2><p>Espero les sea útil para sus desarrollos de lambdas con <code>Node.js</code>. Más adelante ire dejando nuevos artículos con ejemplos e ideas para implementar con AWS Lambdas. Pase y deje su comentario.</p><h2 id="Enlaces-de-interes"><a href="#Enlaces-de-interes" class="headerlink" title="Enlaces de interés"></a>Enlaces de interés</h2><ul><li><a href="https://aws.amazon.com/es/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda/">Using Node.js ES modules and top-level await in AWS Lambda</a></li><li><a href="https://aws.amazon.com/es/about-aws/whats-new/2022/01/aws-lambda-es-modules-top-level-await-node-js-14/">AWS Lambda ahora admite módulos ES y Top-Level Await para Node.js 14</a></li><li><a href="https://advancedweb.hu/how-to-use-es6-modules-and-top-level-await-in-aws-lambda/">How to use ES6 modules and top-level await in AWS Lambda</a></li><li><a href="https://dev.to/prabusah_53/esmodule-in-aws-lambda-7ml">ESModule in AWS Lambda</a></li></ul><blockquote><p>Escuchando <em>Subterranean Homesick Alien</em> del disco <strong>OK Computer</strong></p><footer><strong>Radiohead</strong></footer></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Algunas-generalidades-previas&quot;&gt;&lt;a href=&quot;#Algunas-generalidades-previas&quot; class=&quot;headerlink&quot; title=&quot;Algunas generalidades previas&quot;&gt;&lt;/a</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    <category term="JavaScript" scheme="https://blog.pcollaog.cl/categories/Programming/JavaScript/"/>
    
    
    <category term="javascript" scheme="https://blog.pcollaog.cl/tags/javascript/"/>
    
    <category term="nodejs" scheme="https://blog.pcollaog.cl/tags/nodejs/"/>
    
    <category term="aws" scheme="https://blog.pcollaog.cl/tags/aws/"/>
    
    <category term="aws lambda" scheme="https://blog.pcollaog.cl/tags/aws-lambda/"/>
    
    <category term="commonsjs" scheme="https://blog.pcollaog.cl/tags/commonsjs/"/>
    
    <category term="esm" scheme="https://blog.pcollaog.cl/tags/esm/"/>
    
  </entry>
  
  <entry>
    <title>Nuevo Comienzo</title>
    <link href="https://blog.pcollaog.cl/2023/05/27/nuevo-comienzo/"/>
    <id>https://blog.pcollaog.cl/2023/05/27/nuevo-comienzo/</id>
    <published>2023-05-28T02:38:40.000Z</published>
    <updated>2025-11-01T19:36:46.063Z</updated>
    
    <content type="html"><![CDATA[<h2 id="De-vuelta"><a href="#De-vuelta" class="headerlink" title="De vuelta"></a>De vuelta</h2><p>Hola, se que no he escrito en mucho tiempo, muchísimo tiempo.</p><p>Partiré diciendo que me cambie de sistema de blog desde <a href="https://jekyllrb.com/">Jekyll</a> (ruby… puaj) a <a href="https://hexo.io/">Hexo</a> (nodejs) solo por salir de una tecnología que simplemente no va conmigo y tampoco le he dado el suficiente tiempo para entenderlo. Hexo es una plataforma para generar contenido estático (blog) a partir de archivos markdown, está desarrollado sobe NodeJS y todos sus componentes (plugins y themes) siguen la misma línea. Debo decir que hay muchos componentes que están bien des-actualizados y muchos de ellos con documentación en algo que parece ser Chino.</p><p>Ha pasado muchas cosas desde la última vez que escribí, tuvimos un estallido social en Octubre del 2019 y luego nos remeció una pandemia que nos estuvo encerrados un buen tiempo. De alguna forma ambos eventos forzaron al trabajo remoto y muchas empresas nos vimos obligados a adaptarnos a la nueva forma de trabajar y relacionarnos entre los diferentes equipos.</p><h2 id="En-Pandemia"><a href="#En-Pandemia" class="headerlink" title="En Pandemia"></a>En Pandemia</h2><p>En pandemia no había mucho que hacer (fuera de la casa) así que aplicamos creatividad y aprendí a hacer Pan Amasado y pan con Masa Madre (al igual que muchos). Esto debido a que en esos días salir a comprar el pan era de riesgo vital.</p><img src="/images/2023/IMG_20200530_193718.jpg" class="" title="Pan Amasado"><p>En mitad de la pandemia nos cambiamos de casa apenas se dió la oportunidad (los permisos de mudanza estaban cerrados). Ya instalados en el nuevo HQ comenzó la nueva aventura de colegio virtual. No fue fácil y menos para la Vale, no generó un vínculo con sus profesores a través de una pantalla. Por otro lado la Javi se adaptó de una forma increíble a los quehaceres del colegio.</p><p>Afortunadamente para nuestro rubro, la pandemia aceleró muchos procesos informáticos y como mencioné mas arriba, presionó para que el trabajo remoto se consolidara como LA nueva forma de trabajo. Muchas compañías necesariamente tuvieron que crear nuevos sistemas y aplicaciones para atender a sus clientes o darles la posibilidad de no ir a hacer un tramite presencial (no se podía), lo que de alguna forma benefició a muchas empresas de desarrollo.</p><p>Estando encerrado aprendí cosas muy básicas sobre mantenimiento de guitarras (no quiero decir lutheria porque estoy a años luz de ese conocimiento) para justamente echarles una “manito de gato” a mis guitarras. Fue tanto el entusiasmo que me armé una guitarra que compre en Amazon, un kit DIY <em>Do it yourself</em> estilo PRS.</p><img src="/images/2023/IMG_20201022_153417.jpg" class="" title="Kit DIY - Estilo PRS"><p>Por supuesto que no fue fácil y creo que las dos etapas críticas fueron pegar el mástil al cuerpo y la “pintura”, en ese orden de complejidad. Digo “pintura” pero en realidad es una técnica de teñido de la madera con tinturas basadas en anilina y agua. Les dejo parte del proceso:</p><img src="/images/2023/IMG_20201107_165108.jpg" class="" title="Teñido de la Madera"><p>Ahora esa guitarra es una de mis favoritas por varias razones, tiene un sonido único como hecha para tocar metal, es cómoda y tiene un sustain exagerado. Por lo demás es escala 25” con 24 trastes lo que la hace distinta de las demás guitarras. Cosas que le faltan, aparte de un buen guitarrista XD, mejorar la entonación y cambiar el puente porque lo rompí y no hay repuesto. Afortunadamente la cuerda mas difícil de todas la <code>G</code> quedó perfectamente entonada para el calibre de cuerdas que usa esa guitarra.</p><p>Eso es todo por hoy… iré agregando mas contenido a mi blog que dicho sea de paso tiene 19 años (ni yo me lo creo).</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;De-vuelta&quot;&gt;&lt;a href=&quot;#De-vuelta&quot; class=&quot;headerlink&quot; title=&quot;De vuelta&quot;&gt;&lt;/a&gt;De vuelta&lt;/h2&gt;&lt;p&gt;Hola, se que no he escrito en mucho tiempo</summary>
      
    
    
    
    <category term="Personal" scheme="https://blog.pcollaog.cl/categories/Personal/"/>
    
    
    <category term="música" scheme="https://blog.pcollaog.cl/tags/musica/"/>
    
    <category term="guitarra" scheme="https://blog.pcollaog.cl/tags/guitarra/"/>
    
    <category term="personal" scheme="https://blog.pcollaog.cl/tags/personal/"/>
    
    <category term="blog" scheme="https://blog.pcollaog.cl/tags/blog/"/>
    
    <category term="nodejs" scheme="https://blog.pcollaog.cl/tags/nodejs/"/>
    
    <category term="jekyll" scheme="https://blog.pcollaog.cl/tags/jekyll/"/>
    
    <category term="covid19" scheme="https://blog.pcollaog.cl/tags/covid19/"/>
    
    <category term="hexo" scheme="https://blog.pcollaog.cl/tags/hexo/"/>
    
  </entry>
  
  <entry>
    <title>Adiós 2017... bienvenido 2018</title>
    <link href="https://blog.pcollaog.cl/2018/01/01/happy-new-year/"/>
    <id>https://blog.pcollaog.cl/2018/01/01/happy-new-year/</id>
    <published>2018-01-01T03:00:00.000Z</published>
    <updated>2025-10-28T19:34:18.373Z</updated>
    
    <content type="html"><![CDATA[<img src="/images/2018/end-2017-start-2018.png" class="" title="End 2017, Start 2018"><blockquote><p>Un año más, que se va,<br>un año más, cuántos se han ido.<br>Un año más, que más da,<br>cuántos se han ido ya…</p><footer><strong>Hernán Gallardo Pavéz</strong></footer></blockquote><p>Esta canción es casi un himno patrio de fin de año y no hay fiesta donde no se toque esta canción, que dicho sea de paso, ha sido interpretada por varias bandas. Aquí les dejo un <a href="https://es.wikipedia.org/wiki/Un_a%C3%B1o_m%C3%A1s_(cumbia_chilena)">link</a> para que lean acerca de la historia de ésta canción.</p><h2 id="Symbiose-SpA-y-Tecnologia"><a href="#Symbiose-SpA-y-Tecnologia" class="headerlink" title="Symbiose SpA y Tecnología"></a>Symbiose SpA y Tecnología</h2><p>Este año ha sido particularmente extraño en lo que a negocios y pega se refiere. Tuvimos elecciones presidenciales y que durante lo que dura la “incertidumbre”, los proyectos y las inversiones en tecnología se aletargar <del>paralizan</del> bastante. Una vez pasada la “incertidumbre” (para bien o para mal) se vuelven a activar los proyectos. En <a href="http://www.symbiose.cl/">Symbiose SpA</a> hemos sentidos esos embates del mundo económico y político aunque no tengamos que ver con ninguno de los dos.</p><p>En lo técnico quizás lo mas novedoso ha sido programar en nuevos frameworks y lenguajes. Uno de los nuevos frameworks con los que he tenido que <del>sufrir</del> lidiar ha sido <a href="https://angular.io/">Angular</a> + <a href="https://www.typescriptlang.org/">TypeScript</a>. Solo les puedo comentar que este último lenguaje ha sido vilipendiado de la peor forma en el trabajo y básicamente por lo odioso que es el “compilador” y los mensajes de error que salen en la consola de desarrollo del browser (sólo si es que salen). Hace mucho tiempo que no rabiaba tanto con algo que me gusta hacer.</p><p>En comparación, usando AngularJS como framework, es bastante mas legible y decente los errores que salen en la consola y los errores típicos son los dolores de cabeza que te da Javascript, que de alguna u otra forma, muchos developers tenemos interiorizados.</p><img src="https://assets.hongkiat.com/uploads/coders-worst-nightmare/semicolon.jpg" class="" title="semicolon"><p>Sin lugar a duras en temas tecnológicos el uso de contenedores ha sido protagonista en el desarrollo de microservicios y la aceptación de esta arquitectura que viene de hace hace un par de años. En este ámbito <a href="https://www.docker.com/">Docker</a> ha sido una de las plataformas que se mantiene en la pelea de la “containerización” junto a <a href="https://kubernetes.io/">Kubernetes</a>.</p><img src="https://cdn-images-1.medium.com/max/1600/1*qHvFfsb8YriqUsGe1Q9e9A.png" class="" title="docker-vs-kubernetes"><p>El uso que le damos a diario a estas herramientas van de la mano con <a href="https://es.wikipedia.org/wiki/Integraci%C3%B3n_continua">Continuous Integration</a> y <a href="https://es.wikipedia.org/wiki/Entrega_continua">Continuous Delivery</a> evitando así HH preciadas de los desarrolladores peleando contra los servidores de aplicación, bases datos y cuanta aplicación ofrezca pelea. Para resumir este punto, que mejor que utilizar la palabra <strong>AUTOMATIZACIÓN</strong>.</p><p>Para finalizar lo técnico, sigo acumulando horas de vuelo <a href="https://spring.io/">SpringFramework</a> y toda sus componentes orientados a crear microservicios y ambientes cloud. Cada release nueva de estos componentes traen un montón de nuevas funcionalidades que nos hace la vida mas fácil a la hora de pensar en soluciones Cloud. Kudos para los developers de SpringFramework.</p><h2 id="Libros-varios"><a href="#Libros-varios" class="headerlink" title="Libros varios"></a>Libros varios</h2><p>Un hobby que había dejado totalmente en el olvido era el de leer. Tenía mi Kindle juntando polvo en algún rincón hasta que me puse la meta de leer al menos 1 libro al mes (empezando como en septiembre) y puedo decir que me fue bastante bien. Les dejo un listado de libros interesantes que pude leer o terminar de leer durante el año pasado:</p><ul><li><a href="https://www.goodreads.com/book/show/35077991-la-ciencia-pop">La ciencia pop</a>, Gabriel León</li><li><a href="https://www.goodreads.com/book/show/18757610-la-naturaleza-del-software">La naturaleza del Software</a>, Eduardo Díaz</li><li><a href="https://www.goodreads.com/book/show/34833184-somos-polvo-de-estrellas">Somos polvo de estrellas</a>, José Maza</li><li><a href="https://www.goodreads.com/book/show/20950082-confidencias-de-un-locutor">Confidencias de un locutor</a>, Patricio Bañados</li><li><a href="https://www.goodreads.com/book/show/35565972-hijos-de-las-estrellas-un-maravilloso-recorrido-sobre-los-or-genes-del">Hijos de las estrellas</a>, María Teresa Ruíz</li></ul><p>Cabe destacar todos estos libros son de escritores Chilenos y que por cierto disfruté cada uno en su ámbito. El libro de Patricio Bañados es como estar tras bambalinas de TVN en los tiempos donde nuestro país paso por un periodo triste de su historia. Pero lo mas interesante es cuando superamos el periodo de la dictadura y las historias de codazos, volteretas y bajezas políticas se hacen presente en la vida del Relator.   </p><p>Los libros de Ciencias de José Maza, Gabriel León y María Teresa Ruíz todos tienen la característica de un lenguaje muy simple y de fácil comprensión. Todos ellos muy entretenidos. Ciencia Pop tiene muchas anécdotas científicas y descubrimientos que se han hecho de casualidad (como la mayoría de los descubrimientos científicos). Somos polvo de estrellas y Hijos de las estrellas nos invitan a reflexionar sobre el origen del universo, sobre el origen de la vida y de qué estamos hechos, literalmente… Polvo de estrellas.</p><p>Sobre la Naturaleza del Software, también es un libro de fácil lectura con muchas anécdotas del mundo informático. También invita a reflexionar sobre la evolución de la Ingeniería Informática, los errores recurrentes en esta área, de lo joven que es esta rama de la ingeniería y las comparaciones odiosas con otras ramas. Destaca a grandes personajes que han participado en la evolución del cómo se construye software hasta el día de hoy.</p><p>En proceso de lectura aún:</p><ul><li><a href="https://www.goodreads.com/book/show/14700.El_Universo_Elegante">El universo elegante</a>, Brian Greene</li><li><a href="https://www.goodreads.com/book/show/61666.Contact">Contacto</a>, Carl Sagan</li><li><a href="https://www.goodreads.com/book/show/34910695-yo-robot">Yo, Robot</a>, Isaac Asimov</li></ul><p>Sobre “Contacto” de Carl Sagan, es un libro lleno de detalles y abundante en información de los personajes… muy muy descriptivo (a veces aburre un poco). Lo que me chocó es que uno espera una cierta similitud con la película Contacto y dicha similitud no es tal. La película la habré visto al menos una docena de veces y siempre emociona el momento en que empieza a escuchar los pulsos que provienen de la estrella Vega o al final cuando les habla apasionadamente a los niños sobre el universo. El libro es totalmente diferente o mejor dicho… la película es “basada” en la novela original de Carl Sagan.</p><p>Lo mismo me pasó con “Yo, Robot”, la película es también una de mis favoritas y con el libro no pega ni junta, aunque la trama del libro es la misma que se trata en la película y tiene que ver con el conflicto que hay con las 3 leyes de la robótica, pero en muchas situaciones diferentes a la película. El libro contiene un conjunto historias cortas que hablan de la forma en que los robots interactúan con los humanos en situaciones límite exigiendo al máximo las 3 leyes de la robótica. Interesante libro!</p><p>Alguna sugerencia de lectura para este año? déjenlo en los comentarios.</p><h2 id="Palabras-al-cierre"><a href="#Palabras-al-cierre" class="headerlink" title="Palabras al cierre"></a>Palabras al cierre</h2><p>Feliz 2018 para todos! Bienvenido 2018!</p><p>y si… voy a escribir mas este año :D</p>]]></content>
    
    
      
      
    <summary type="html">&lt;img src=&quot;/images/2018/end-2017-start-2018.png&quot; class=&quot;&quot; title=&quot;End 2017, Start 2018&quot;&gt;

&lt;blockquote&gt;&lt;p&gt;Un año más, que se va,&lt;br&gt;un año más,</summary>
      
    
    
    
    <category term="Personal" scheme="https://blog.pcollaog.cl/categories/Personal/"/>
    
    
    <category term="javascript" scheme="https://blog.pcollaog.cl/tags/javascript/"/>
    
    <category term="angular" scheme="https://blog.pcollaog.cl/tags/angular/"/>
    
    <category term="tecnología" scheme="https://blog.pcollaog.cl/tags/tecnologia/"/>
    
    <category term="resumen" scheme="https://blog.pcollaog.cl/tags/resumen/"/>
    
    <category term="docker" scheme="https://blog.pcollaog.cl/tags/docker/"/>
    
    <category term="kubernetes" scheme="https://blog.pcollaog.cl/tags/kubernetes/"/>
    
    <category term="spring-boot" scheme="https://blog.pcollaog.cl/tags/spring-boot/"/>
    
    <category term="symbiose" scheme="https://blog.pcollaog.cl/tags/symbiose/"/>
    
    <category term="typescript" scheme="https://blog.pcollaog.cl/tags/typescript/"/>
    
    <category term="libros" scheme="https://blog.pcollaog.cl/tags/libros/"/>
    
  </entry>
  
  <entry>
    <title>Cambio de casa, adiós Octopress bienvenido Jekyll</title>
    <link href="https://blog.pcollaog.cl/2017/07/12/cambio-de-casa-jekyll/"/>
    <id>https://blog.pcollaog.cl/2017/07/12/cambio-de-casa-jekyll/</id>
    <published>2017-07-12T04:00:00.000Z</published>
    <updated>2025-10-28T18:59:26.336Z</updated>
    
    <content type="html"><![CDATA[<img src="/images/2017/jekyllrb.png" class="" title="Jekyllrb"><p>Estoy de mudanza de blog, adiós <a href="http://octopress.org/">Octopress</a> bienvenido <a href="http://jekyllrb.com/">Jekyll</a>.</p><p>Una de las razones que me empujó a cambiarme de sistema de blog, es que <strong>Octopress</strong> esta sacando la versión 3 desde el 15 de enero del 2015, esta algo abandonado (<a href="https://github.com/octopress/octopress">ver los commits</a>).</p><img src="/images/2017/octopress.png" class="" title="Octopress"><p>La pregunta era… ¿ hacia donde migro ? </p><p><strong>Octopress</strong> se basa en <strong>Jekyll</strong> y la organización de los artículos es básicamente la misma. Pero no todo es tan fácil. <strong>Octopress</strong> tiene un conjunto de <a href="http://octopress.org/2011/07/23/octopress-20-surfaces/">plugins</a> que facilitan y ayudan a embellecer los artículos, por ejemplo, para destacar código fuente, citas, imágenes y video.</p><p><strong>Jekyll</strong> de alguna u otra forma también tiene <em>plugins</em> para lo mismo, el problema es que hay que modificar todos los artículos donde fueron usados los <em>plugins</em> de Octopress y modificarlos al gusto de Jekyll.</p><p>Siguiente problema, elegir un lindo (?) tema para el blog, después de un largo recorrido buscando, encontré <a href="https://mademistakes.com/work/minimal-mistakes-jekyll-theme/">Minimal Mistakes</a>, bien lindo, personalizable, con gran capacidad de extender y todas esa funcionalidades que a los <em>developers</em> nos enamoran (pero que jamás usamos al 100%). De todas formas, la instalación de este tema no fue sencillo, demasiadas configuraciones y cosas que no andan a la primera y la documentación, que es bien buena, no dice las cosas clave.</p><p>Algunas características de Jekyll son:</p><ul><li>Posee muchos plugins</li><li>Esta escrito en ruby (puaj)</li><li>Tiene varios mecanismos de <a href="http://import.jekyllrb.com/">importación desde otros blogs</a>.</li><li>El contenido se genera a partir de documentos escritos en markdown</li><li>Como el contenido es texto, estos se pueden mantener fácilmente en <strong>git</strong></li></ul><p>Si ve errores, considere que el blog esta en rodaje y sea amable… reporte el bug.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;img src=&quot;/images/2017/jekyllrb.png&quot; class=&quot;&quot; title=&quot;Jekyllrb&quot;&gt;

&lt;p&gt;Estoy de mudanza de blog, adiós &lt;a href=&quot;http://octopress.org/&quot;&gt;Octopres</summary>
      
    
    
    
    <category term="Blog" scheme="https://blog.pcollaog.cl/categories/Blog/"/>
    
    
    <category term="blog" scheme="https://blog.pcollaog.cl/tags/blog/"/>
    
    <category term="ruby" scheme="https://blog.pcollaog.cl/tags/ruby/"/>
    
    <category term="jekyll" scheme="https://blog.pcollaog.cl/tags/jekyll/"/>
    
    <category term="octopress" scheme="https://blog.pcollaog.cl/tags/octopress/"/>
    
    <category term="git" scheme="https://blog.pcollaog.cl/tags/git/"/>
    
  </entry>
  
  <entry>
    <title>jEnv una solución para múltiples instalaciones de Java</title>
    <link href="https://blog.pcollaog.cl/2015/12/23/jEnv-una-solucion-para-multiples-instalaciones-de-java/"/>
    <id>https://blog.pcollaog.cl/2015/12/23/jEnv-una-solucion-para-multiples-instalaciones-de-java/</id>
    <published>2015-12-23T03:00:00.000Z</published>
    <updated>2025-11-01T19:36:46.063Z</updated>
    
    <content type="html"><![CDATA[<img src="/images/2015/c9lcw62x8525gtex8a0l-20151222-2348.png" class="" title="jEnv"><p><strong>jEnv</strong> es una herramienta de linea de comandos que ayuda a mantener múltiples instalaciones de Java (versiones y&#x2F;o sabores) y permite cambiar las versiones por linea de comandos para poder mantener diversos entornos de desarrollo.</p><p>Una de las funcionalidades interesantes de <strong>jEnv</strong> es que configura las variables de entorno de java <em>JAVA_HOME</em> al vuelo según una pequeña configuración que se agrega al proyecto. Más adelante veremos algunas gracias de <em>jEnv</em>.</p><h1 id="Instalacion"><a href="#Instalacion" class="headerlink" title="Instalación"></a>Instalación</h1><p>La instalación es bien sencilla y la pueden revisar en la <a href="http://www.jenv.be/">página oficial de jEnv</a>, acá dejo un resumen:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ git <span class="built_in">clone</span> https://github.com/gcuisinier/jenv.git ~/.jenv</span><br></pre></td></tr></table></figure><p>Ahora debes ejecutar (dependiendo de tu shell) lo siguiente:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">echo</span> <span class="string">&#x27;export PATH=&quot;$HOME/.jenv/bin:$PATH&quot;&#x27;</span> &gt;&gt; ~/.bash_profile</span><br><span class="line">$ <span class="built_in">echo</span> <span class="string">&#x27;eval &quot;$(jenv init -)&quot;&#x27;</span> &gt;&gt; ~/.bash_profile</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">echo</span> <span class="string">&#x27;export PATH=&quot;$HOME/.jenv/bin:$PATH&quot;&#x27;</span> &gt;&gt; ~/.zshrc</span><br><span class="line">$ <span class="built_in">echo</span> <span class="string">&#x27;eval &quot;$(jenv init -)&quot;&#x27;</span> &gt;&gt; ~/.zshrc</span><br></pre></td></tr></table></figure><p>Reiniciamos el terminal y&#x2F;o cargamos las nueva variables de entorno de nuestra shell y primero probamos que todo funcione correctamente con el siguiente comando:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ jenv --version</span><br></pre></td></tr></table></figure><p>Si el comando te responde con la versión de <em>jEnv</em> es porque esta todo correctamente instalado.</p><h1 id="Configuracion"><a href="#Configuracion" class="headerlink" title="Configuración"></a>Configuración</h1><p>Luego tenemos que agregar las diferentes versiones de java que tengas instaladas en tu sistema de la siguiente forma:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ jenv add /path/to/java6-oracle/java_home</span><br><span class="line">$ jenv add /path/to/java6-openjdk/java_home</span><br><span class="line">$ jenv add /path/to/java7-oracle/java_home</span><br><span class="line">...</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>Una ves que hayas concluido la configuración de las diferentes versiones de Java de tu sistema, puedes listarlos con el siguiente comando:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ jenv versions</span><br></pre></td></tr></table></figure><p>Y aparecerá algo como esto:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">  system</span><br><span class="line">* 1.7 (<span class="built_in">set</span> by /home/pcollaog/.jenv/version)</span><br><span class="line">  1.7.0.79</span><br><span class="line">  1.8</span><br><span class="line">  1.8.0.45</span><br><span class="line">  oracle64-1.7.0.79</span><br><span class="line">  oracle64-1.8.0.45</span><br></pre></td></tr></table></figure><p>Ahora corresponde configurar cual de todas esas instalaciones será la que funcionará de forma global, es decir, la configuración por omisión de Java. En este ejemplo se configura la versión oracle64-1.7.0.79 como global. </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ jenv global oracle64-1.7.0.79</span><br></pre></td></tr></table></figure><p>Tambien se puede configurar de forma mas genérico, es decir, la última versión de java 7, por ejemplo:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ jenv global 1.7</span><br></pre></td></tr></table></figure><p>Con esto siempre tomará la versión mas nueva de java 7 que tengan previamente configurada.</p><h1 id="Activar-la-configuracion-automatica-de-JAVA-HOME"><a href="#Activar-la-configuracion-automatica-de-JAVA-HOME" class="headerlink" title="Activar la configuración automática de JAVA_HOME"></a>Activar la configuración automática de JAVA_HOME</h1><p>Para delegar la configuración de las variables de entorno de java a <em>jEnv</em>, debemos activar el <em>plugin export</em> de la siguiente forma:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ jenv enable-plugin export</span><br></pre></td></tr></table></figure><p><strong>Nota:</strong> para que funcione correctamente el plugin, se debe eliminar la configuración de las variables de entorno que se tengan en los perfiles de bash (.bashrc) , zsh (.zshrc) o de su shell favorita.</p><p>Luego deben reiniciar su terminal o volver a cargar los perfiles de su shell y probar:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ echo $JAVA_HOME</span><br></pre></td></tr></table></figure><p>Debería aparecer algo como lo que sigue:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/home/pcollaog/.jenv/versions/1.7</span><br></pre></td></tr></table></figure><p>Y si vemos la versión de java debería aparecer algo como esto:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ java -version</span><br><span class="line">java version &quot;1.7.0_79&quot;</span><br><span class="line">Java(TM) SE Runtime Environment (build 1.7.0_79-b15)</span><br><span class="line">Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)</span><br></pre></td></tr></table></figure><h1 id="Configuracion-personalizada-de-Java"><a href="#Configuracion-personalizada-de-Java" class="headerlink" title="Configuración personalizada de Java"></a>Configuración personalizada de Java</h1><p>Si por alguna razón necesitas tener una versión especifica de Java en un proyecto de código fuente, debes configurar (estando dentro del directorio principal del proyecto) de la siguiente forma:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ jenv local 1.7</span><br></pre></td></tr></table></figure><p>Este comando creará un archivo en el directorio en el que te encuentras (directorio base de tu código fuente) llamado <strong>.java-version</strong> y cuyo contenido será la versión de java especificada. Con esto todos los subdirectorios (a partir de donde se encuentras este archivo) estarán configurados con la versión de java seleccionada. Si tienes correctamente configurado el plugin export, <em>jEnv</em> hará el trabajo sucio de configurar la variable <strong>JAVA_HOME</strong>.</p><p>Sus comentarios son bienvenidos!</p>]]></content>
    
    
      
      
    <summary type="html">&lt;img src=&quot;/images/2015/c9lcw62x8525gtex8a0l-20151222-2348.png&quot; class=&quot;&quot; title=&quot;jEnv&quot;&gt;

&lt;p&gt;&lt;strong&gt;jEnv&lt;/strong&gt; es una herramienta de linea </summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    <category term="Java" scheme="https://blog.pcollaog.cl/categories/Programming/Java/"/>
    
    
    <category term="java" scheme="https://blog.pcollaog.cl/tags/java/"/>
    
    <category term="bash" scheme="https://blog.pcollaog.cl/tags/bash/"/>
    
    <category term="environment" scheme="https://blog.pcollaog.cl/tags/environment/"/>
    
    <category term="shell" scheme="https://blog.pcollaog.cl/tags/shell/"/>
    
    <category term="zsh" scheme="https://blog.pcollaog.cl/tags/zsh/"/>
    
  </entry>
  
  <entry>
    <title>Spring Constructor Namespace</title>
    <link href="https://blog.pcollaog.cl/2015/12/18/spring-constructor-namespace/"/>
    <id>https://blog.pcollaog.cl/2015/12/18/spring-constructor-namespace/</id>
    <published>2015-12-18T03:00:00.000Z</published>
    <updated>2025-11-01T19:36:46.063Z</updated>
    
    <content type="html"><![CDATA[<p>En esta oportunidad les escribo sobre un <del>nuevo</del> namespace que apareció en Spring 3.1 (y me dí cuenta recién XD ) y sirve para configurar los beans haciendo uso de su constructor. Como su nombre lo indica este es un namespace que opera sólo sobre los constructores de beans y así permitir la inyección de beans o valores.</p><p>Les dejo una imagen de como se activa este <del>nuevo</del> namespace en el STS.</p><img src="/images/2015/qg7ia2uaqcild17htesk-20151218-1555.png" class="" title="STS - Spring Namespaces Config"><p>Veamos un ejemplo simple de cómo usar <strong>namespace C</strong>.</p><p>Supongamos la siguiente clase:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SimpleSPImpl</span> <span class="keyword">extends</span> <span class="title class_">StoredProcedure</span></span><br><span class="line">        <span class="keyword">implements</span> <span class="title class_">SimpleSP</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">SimpleSPImpl</span><span class="params">(DataSource ds, String spName)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(ds, spName);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bean_id&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.example.SimpleSPImpl&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;ds&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;datasource&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">name</span>=<span class="string">&quot;spName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;spNameTest&quot;</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- Definición del datasource de ejemplo --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;datasource&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.mchange.v2.c3p0.ComboPooledDataSource&quot;</span>&gt;</span></span><br><span class="line">...</span><br><span class="line">...</span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Ahora usando el <strong>namespace c</strong> quedaría algo mas simple:</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;bean_id&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.example.SimpleSPImpl </span></span></span><br><span class="line"><span class="string"><span class="tag">    c:ds-ref=&quot;</span><span class="attr">datasource</span>&quot; <span class="attr">c:spName</span>=<span class="string">&quot;spNameTest&quot;</span> /&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- Definición del datasource de ejemplo --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;datasource&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.mchange.v2.c3p0.ComboPooledDataSource&quot;</span>&gt;</span></span><br><span class="line">...</span><br><span class="line">...</span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Como pueden notar en el ejemplo, el <strong>namespace C</strong> permite configurar los constructores de los beans y tiene dos formas básicas, por valor y referencia. Para inyectar una instancia preconfigurada se debe usar el sufijo <strong>-ref</strong> para hacer alusión a que es una referencia. Si se desea inyectar un valor, sólo se usa el nombre del argumento del constructor.</p><p>Como siempre sus comentarios son bienvenidos.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;En esta oportunidad les escribo sobre un &lt;del&gt;nuevo&lt;/del&gt; namespace que apareció en Spring 3.1 (y me dí cuenta recién XD ) y sirve para c</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    <category term="Java" scheme="https://blog.pcollaog.cl/categories/Programming/Java/"/>
    
    
    <category term="java" scheme="https://blog.pcollaog.cl/tags/java/"/>
    
    <category term="spring" scheme="https://blog.pcollaog.cl/tags/spring/"/>
    
    <category term="springframework" scheme="https://blog.pcollaog.cl/tags/springframework/"/>
    
    <category term="xml" scheme="https://blog.pcollaog.cl/tags/xml/"/>
    
  </entry>
  
  <entry>
    <title>Checked y Unchecked Exception</title>
    <link href="https://blog.pcollaog.cl/2015/08/02/cheked-y-unchecked-exception/"/>
    <id>https://blog.pcollaog.cl/2015/08/02/cheked-y-unchecked-exception/</id>
    <published>2015-08-02T03:00:00.000Z</published>
    <updated>2025-11-01T19:36:46.062Z</updated>
    
    <content type="html"><![CDATA[<p>Dado que varios de mis lectores me han solicitado un post sobre tipos de excepciones en Java, les dejaré un par de notas para que consideren al momento de diseñar soluciones y por su puesto el cómo manejar los errores. Aquí vamos!</p><p>Primero que todo, un par de definiciones básicas y características antes de partir.</p><h2 id="Jerarquia-de-Excepciones"><a href="#Jerarquia-de-Excepciones" class="headerlink" title="Jerarquía de Excepciones"></a>Jerarquía de Excepciones</h2><p>Esta es la jerarquía de excepciones de mas alto nivel que encontramos en Java.</p><img src="/images/2015/exceptions.png" class="" title="Jerarquía de Throwable"><h2 id="Unchecked-Exception"><a href="#Unchecked-Exception" class="headerlink" title="Unchecked Exception"></a>Unchecked Exception</h2><p>Generalmente este tipo de excepciones son lanzadas por la aplicación y se generan a partir de errores en tiempo de <em>Runtime</em>. Este tipo de excepciones representan errores en el código y que la aplicación no es capaz de controlar. Algunos de errores causados y que lanzan este tipo de excepciones, por ejemplo, argumentos inválidos pasados a un método (argumentos <em>null</em> pueden causar <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/NullPointerException.html">NullPointerException</a>), otro error común son la excepciones del tipo <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/IndexOutOfBoundsException.html">IndexOutOfBoundsException</a> y que son lanzadas cuando se quieren obtener elementos de una lista y el índice que se entrega está fuera del tamaño del arreglo. Como podrán ver, son errores de programación y que generarán defectos en momento de correr la aplicación (no así al compilar).</p><blockquote><p>Unchecked runtime exceptions represent conditions that, generally speaking, reflect errors in your program’s logic and cannot be reasonably recovered from at runtime.</p><p>Gosling&#44; Arnold and Holmes, The Java Programming Language</p></blockquote><p>Las excepciones de tipo <strong>Unchecked</strong> son subclases que heredan desde <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimeException.html">RuntimeException</a>. Además este tipo de excepciones no tienen la obligación de ser declaradas con la cláusula <strong>throws</strong> en la cabecera del método. Otra característica es que tampoco se tiene la obligación de atraparlas con un <strong>catch</strong> como se muestra en el ejemplo siguiente:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Ejemplo de exception tipo &#123;<span class="doctag">@link</span> RuntimeException&#125;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RuntimeDemo</span> &#123;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * Método principal</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">mainMethod</span><span class="params">()</span> &#123;</span><br><span class="line">      methodThowsRuntimeException();</span><br><span class="line">      methodThowsRuntimeException2();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * Este método lanzará una excepción de tipo runtime no declarada en su</span></span><br><span class="line"><span class="comment">   * firma</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">methodThowsRuntimeException</span><span class="params">()</span> &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ExampleRuntimeException</span>();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * Este método lanzará una excepción de tipo runtime está declarada en su</span></span><br><span class="line"><span class="comment">   * firma (no es obligación) pero deja mas claro al desarrollador las</span></span><br><span class="line"><span class="comment">   * excepciones que debería manejar con la API.</span></span><br><span class="line"><span class="comment">   * </span></span><br><span class="line"><span class="comment">   * <span class="doctag">@throws</span> ExampleRuntimeException</span></span><br><span class="line"><span class="comment">   *             en caso de error</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">methodThowsRuntimeException2</span><span class="params">()</span> <span class="keyword">throws</span> ExampleRuntimeException &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ExampleRuntimeException</span>();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * Clase de error tipo Runtime</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">ExampleRuntimeException</span> <span class="keyword">extends</span> <span class="title class_">RuntimeException</span> &#123;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">public</span> <span class="title function_">ExampleRuntimeException</span><span class="params">()</span> &#123;</span><br><span class="line">          <span class="built_in">super</span>();</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Checked-Exception"><a href="#Checked-Exception" class="headerlink" title="Checked Exception"></a>Checked Exception</h2><p>Este tipo de excepciones representan condiciones inválidas en el contexto de la línea de ejecución y que están fuera del control de dicho contexto, como por ejemplo, problemas con la base de datos, problemas de red, acceso a los archivos. También pueden ser condiciones de ingreso al sistema en donde el sistema no tiene ninguna participación, como por ejemplo, ingresar un nombre de usuario y contraseña incorrectos.</p><p><em>Contexto de ejecución ó scope: Corresponde al las líneas de código que están encerradas en un bloque de código, como por ejemplo, un método, un try&#x2F;catch, bloque estático, etc.</em></p><p>Este tipo de excepciones deben ser declaradas en la firma del método. Además deben ser atrapadas dentro de los bloques de código donde se invoque un método que contenga la clausula <strong>throws</strong>.</p><p>Todas las excepciones de este tipo son subclases que heredan desde <em>Exception</em>, como por ejemplo:</p><ul><li><a href="http://docs.oracle.com/javase/7/docs/api/java/net/SocketTimeoutException.html">SocketTimeoutException</a></li><li><a href="http://docs.oracle.com/javase/7/docs/api/java/io/IOException.html">IOException</a></li><li><a href="http://docs.oracle.com/javase/7/docs/api/java/util/zip/DataFormatException.html">DataFormatException</a></li></ul><p>Otra característica de este tipo de excepciones es que existe una probabilidad de recuperación de la ejecución y el método puede realizar alguna acción correctiva y&#x2F;o informativa (log) en el bloque <em>catch</em> o simplemente relanzar la excepción y confiar en que el método invocante la atrape y haga algo con ella.</p><p>Para enviar el <em>stacktrace</em> al sistema de log (systemout) pueden usar los métodos de <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html">Throwable</a> y en específico al método <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#printStackTrace()">printStackTrace</a>.</p><p>Un pequeño ejemplo de checked exception:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Clase de ejemplo para checked exceptions</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CheckedExample</span> &#123;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * Método que atrapa una checked exception</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">catchCheckedException</span><span class="params">()</span> &#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">          throwCheckedException();</span><br><span class="line">      &#125; <span class="keyword">catch</span> (ExampleCheckedException e) &#123;</span><br><span class="line">          <span class="comment">// <span class="doctag">TODO:</span> hacer algo en caso de error (recuperacion)</span></span><br><span class="line">      &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * Método que relanza la checked exception a un método superior</span></span><br><span class="line"><span class="comment">   * </span></span><br><span class="line"><span class="comment">   * <span class="doctag">@throws</span> ExampleCheckedException</span></span><br><span class="line"><span class="comment">   *             checked exception error</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">rethrowCheckedException</span><span class="params">()</span> <span class="keyword">throws</span> ExampleCheckedException &#123;</span><br><span class="line">      throwCheckedException();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * Método que lanza una checked exception</span></span><br><span class="line"><span class="comment">   * </span></span><br><span class="line"><span class="comment">   * <span class="doctag">@throws</span> ExampleCheckedException</span></span><br><span class="line"><span class="comment">   *             checked exception error</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">throwCheckedException</span><span class="params">()</span> <span class="keyword">throws</span> ExampleCheckedException &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ExampleCheckedException</span>();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * Clase que representa la excepcion de ejemplo</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">ExampleCheckedException</span> <span class="keyword">extends</span> <span class="title class_">Exception</span> &#123;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">public</span> <span class="title function_">ExampleCheckedException</span><span class="params">()</span> &#123;</span><br><span class="line">          <span class="built_in">super</span>();</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Error"><a href="#Error" class="headerlink" title="Error"></a>Error</h2><p>Las excepciones de tipo <strong>Error</strong> son excepciones en las que el sistema no puede hacer nada con ellas, son clasificadas como errores irreversibles y que en su mayoría provienen desde la JVM, como por ejemplo: <a href="http://docs.oracle.com/javase/7/docs/api/java/io/IOError.html">IOError</a>, <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/NoClassDefFoundError.html">NoClassDefFoundError</a>, <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/NoSuchMethodError.html">NoSuchMethodError</a>, <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/OutOfMemoryError.html">OutOfMemoryError</a> y <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/VirtualMachineError.html">VirtualMachineError</a> por mencionar algunos de los errores.</p><h2 id="Un-poco-de-diseno-y-consejos-para-el-manejo-de-excepciones"><a href="#Un-poco-de-diseno-y-consejos-para-el-manejo-de-excepciones" class="headerlink" title="Un poco de diseño y consejos para el manejo de excepciones"></a>Un poco de diseño y consejos para el manejo de excepciones</h2><p>Para iniciar esta última parte, comenzaré con algunos ejemplos de malas prácticas con las que siempre nos encontramos cuando programamos, les dejo unas pocas:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="comment">//ejecución que lanza checked exceptions</span></span><br><span class="line">&#125; <span class="keyword">catch</span> (ExampleCheckedException e) &#123;</span><br><span class="line">    <span class="comment">// No hace nada</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>En el ejemplo de arriba claramente no se hace nada con la excepción dentro del <strong>try</strong>, lo recomendable es que si de verdad no vas a hacer nada con la excepción, al menos debes enviarla a tu sistema de <em>Logger</em> favorito con algún nivel de <strong>debug</strong> aceptable para poder revisar el log. Siempre se recomienda hacer algo en el bloque <strong>catch</strong> ya que ocurrió un error que debe ser controlado.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="comment">//ejecución que lanza checked exceptions</span></span><br><span class="line">&#125; <span class="keyword">catch</span> (ExampleCheckedException e) &#123;</span><br><span class="line">    <span class="keyword">throw</span> e;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Es similar ejemplo 1 pero lo que se hace es relanzar la excepción atrapada hacia el método invocante. La recomendación es que nunca hagas eso ya que se presta para confusión al leer el código fuente y en la practica se estarían ejecutando dos bloques <em>catch</em> para la misma excepción (el directo y el del método invocante).</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="comment">//ejecución que lanza checked exceptions</span></span><br><span class="line">&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">    <span class="comment">// alguna lógica de negocio</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Es recomendable que <em>nunca</em> atrapen todas las excepciones en un bloque <em>catch</em> y básicamente porque uno pierde la noción de por qué se produjo la excepción. Además en ese bloque también se atrapan las excepciones de tipo <em>Runtime</em> y ya mencionamos que estas excepciones significan errores en tu programa y que deben ser depurados (no escondidos debajo de la alfombra). Lo mejor es atrapar cada una de las excepciones y darle un tratamiento a cada una, si necesitan agrupar usen la herencia&#x2F;jerarquía de las excepciones.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="comment">//ejecución que lanza checked exceptions</span></span><br><span class="line">&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">    <span class="comment">// alguna lógica de negocio</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (e <span class="keyword">instanceof</span> BlaException )&#123;</span><br><span class="line"></span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (e <span class="keyword">instanceof</span> FooException) &#123;</span><br><span class="line"></span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> .....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Ese bloque de <em>if’s</em> compuestos se debe transformar en varios <strong>catch</strong> para cada una de las excepciones lanzadas. No usen un control de errores manual, es mejor usar las herramientas que te provee el lenguaje.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="comment">//ejecución que lanza checked exceptions</span></span><br><span class="line">&#125; <span class="keyword">catch</span> (ErrorBlaException e) &#123;</span><br><span class="line">    ...</span><br><span class="line">&#125; <span class="keyword">catch</span> (ErrorFooException e) &#123;</span><br><span class="line">    ...</span><br><span class="line">&#125; <span class="keyword">catch</span> (ErrorOMGException e) &#123;</span><br><span class="line">    ...</span><br><span class="line">&#125; <span class="keyword">catch</span> (SDWException e) &#123;</span><br><span class="line">    ...</span><br><span class="line">&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>No abusar de las <em>checked exceptions</em> ya que hacen nuestro código confuso y poco mantenible. Si bien es cierto, es la herramienta que nos provee el lenguaje, no abusemos de ella y convirtamos los bloques <strong>catch</strong> en pseudo programas y rutinas anexas a la lógica de negocio (que es la que vale).</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line"> <span class="comment">// código de negocio   </span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Nunca lancen <strong>Exception</strong> como una excepción de su lógica de negocio y es que básicamente los <strong>catch</strong> están pensados en atrapar excepciones particulares y al lanzar <strong>Exception</strong> (de la mas alta jerarquía) jamás entrarás al bloque <strong>catch</strong> que corresponda y que pueda gestionar el error. Por otro lado el programador pierde la visibilidad de los errores particulares que debe gestionar.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">foo</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// logica de negocio</span></span><br><span class="line">    &#125; <span class="keyword">catch</span> (ParserConfigurationException e) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">RuntimeException</span>(<span class="string">&quot;Error&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Jamás se debe hacer esto, jamás!. Esto romperá todo tu programa ya que al lanzar la excepción <strong>RuntimeException</strong> esta llegará sin control a la capa mas alta provocando un error. Recuerden que ese tipo de excepciones son errores sin recuperación y justamente estamos tratando de hacer lo contrario gestionar los errores de lógica de negocio.</p><h3 id="Mantener-un-arbol-de-excepciones"><a href="#Mantener-un-arbol-de-excepciones" class="headerlink" title="Mantener un árbol de excepciones"></a>Mantener un árbol de excepciones</h3><p>Esta sección del post quizás sea el más polémico ya que no hay receta perfecta para el manejo de excepciones y daré mis consejos (personales), puede que estén de acuerdo como puede que no.</p><p>Les recomiendo siempre mantener un árbol de excepciones que representen los errores (de negocio y de ejecución) de tu aplicación. Para que sea mas simple la mantención del árbol de excepciones, usen polimorfismo, herencia y todas las herramientas que ofrece OOP. En este punto siempre hay detractores de los árboles de excepciones con la excusa de su mantención. </p><p>Contraria a mi propuesta de manejo de errores, existen quienes mantienen sólo 1 excepción y a dicha excepción le agregan atributos y cuanta metadata puedan agregar. Qué se consigue finalmente con ese esquema de errores, es llenarte de <strong>IF</strong> por todos lados mirando los atributos que contiene la instancia de excepción y haciendo todo un control de errores manual.</p><h2 id="Palabras-al-cierre"><a href="#Palabras-al-cierre" class="headerlink" title="Palabras al cierre"></a>Palabras al cierre</h2><p>Quedan muchas cosas por mencionar de las excepciones y ahondar mucho mas en cómo diseñar y construir un árbol de excepciones, creo que sera materia para otro artículo. Demás esta decirles que esta abierta la discusión. Los comentarios bienvenidos sean.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Dado que varios de mis lectores me han solicitado un post sobre tipos de excepciones en Java, les dejaré un par de notas para que conside</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    <category term="Java" scheme="https://blog.pcollaog.cl/categories/Programming/Java/"/>
    
    
    <category term="java" scheme="https://blog.pcollaog.cl/tags/java/"/>
    
    <category term="error" scheme="https://blog.pcollaog.cl/tags/error/"/>
    
    <category term="exception" scheme="https://blog.pcollaog.cl/tags/exception/"/>
    
    <category term="design" scheme="https://blog.pcollaog.cl/tags/design/"/>
    
  </entry>
  
  <entry>
    <title>Ud. no lo haga - Parte 1</title>
    <link href="https://blog.pcollaog.cl/2014/10/04/ud-no-lo-haga-parte-1/"/>
    <id>https://blog.pcollaog.cl/2014/10/04/ud-no-lo-haga-parte-1/</id>
    <published>2014-10-04T03:00:00.000Z</published>
    <updated>2025-11-01T19:36:46.062Z</updated>
    
    <content type="html"><![CDATA[<p>En este post, pondré algunas capturas de pantallas de cosas que Ud. como desarrollador (java) no debe hacer (en algunos casos debe evitar hacer).</p><h1 id="Constantes"><a href="#Constantes" class="headerlink" title="Constantes"></a>Constantes</h1><p>En Java las constantes por lo general se declaran en estilo <em>uppercase</em> usando como separador de palabras el <em>underscore</em> <strong>ALGO_COMO_ESTO</strong>, en este ejemplo, se pueden notar que agregan un <em>underscore</em> al principio (No lo haga!). Generalmente se usa <em>underscore</em> al principio para nombrar los atributos de una clase, de esta forma no usas <strong>this</strong> para identificar un atributo de clase.</p><img src="/images/2014/0ca8ff8c80b71b4c110707600d6d0e3e-20140825.png" class="" title="El Gato y La arroba"><h1 id="El-falso-catch"><a href="#El-falso-catch" class="headerlink" title="El falso catch"></a>El falso catch</h1><p>Si va hacer algún tipo de control sobre una <em>exception</em>, pués hágalo. En este ejemplo sólo se captura la <em>exception</em> y se vuelve a lanzar. Si realmente quiere hacer eso, no haga el *<em>catch]</em> de la <em>exception</em>, déjela salir libremente.</p><img src="/images/2014/1c22163b2c857dfa_20131218.png" class="" title="El falso catch"><h1 id="La-estetica-del-codigo-si-importa"><a href="#La-estetica-del-codigo-si-importa" class="headerlink" title="La estética del código si importa"></a>La estética del código si importa</h1><p>Si esta programando y al final de su algoritmo, le queda algo parecido a lo que sale en la imagen, recapacite, tome aire y refactorice su código. Hay algunas alertas que se pueden ver fácilmente con la estética del código, es decir, al cómo queda escrito (forma, silueta). Hay algunos desarrolladores que les encanta tener sus líneas de código hasta el infinito, lo que dificulta su lectura cuando tienes una pantalla distinta a la del desarrollador.</p><img src="/images/2014/0093266316e7e635e8197e80574c3c78-20140912.png" class=""><p>Otro ejemplo más:</p><img src="/images/2014/20f539b414c0eb20591be30e5467f84e-20140825.png" class=""><p>Algunos consejos que te ayudarán a darte cuenta de errores en tu código de forma visual, aquí los dejo:</p><ul><li>Ajusta tu IDE para que te corte las lineas en los 80&#x2F;120 caracteres. Con esto podrás tener como buena práctica nombrar bien tus variables (cortas y precisas) y es un buen límite cuando empiezas a avanzar en la identación del código producto de los <strong>if&#x2F;else&#x2F;for&#x2F;while&#x2F;try&#x2F;catch</strong>. Si terminas escribiendo código cerca de los 80 caracteres es que algún problema tienes en tu código y necesita refactorización.</li><li>Si trabajas en equipo, es indispensable que todos tengan los mismos settings para la identación y el encoding, de esta forma, no tendrás problemas al comparar código (diff).</li></ul><p>Estos son mis ajustes en el <strong>STS&#x2F;Eclipse</strong>:</p><img src="/images/2014/6cbdf5af1473bca17f392e2c1a1f3072-20141003.png" class="" title="Text Editor Settings"><h1 id="Estilo-Visual-Basic"><a href="#Estilo-Visual-Basic" class="headerlink" title="Estilo Visual Basic"></a>Estilo Visual Basic</h1><p>Si esta escribiendo código Java, por favor no cometa este error. Si va a declarar una variable, hágalo en el lugar donde se utilizará, de esta forma los refactoring de código son mas simples. Por otro lado, estéticamente queda feo tu código. Ahora si entramos en el micro manejo de memoria, posiblemente estas reservando memoria que no utilizarás en todo el método. En este ejemplo, se declaran muchas variables con un valor, pero que pasa si salta una <em>exception</em>? o algún control de flujo que no considere todas las variables?, habrás perdido innecesariamente un par de bytes.</p><img src="/images/2014/12e05108cf4e69b8e608b01eb9935acd-20140828.png" class="" title="Estilo Visual Basic"><h1 id="WTF"><a href="#WTF" class="headerlink" title="WTF!!!"></a>WTF!!!</h1><p><strong>Nunca</strong>, pero nunca, asignes a una variable el valor de una constante, no tiene ningún sentido. Además en este ejemplo, podrán notar que hay código que no tiene ningún sentido, <strong>nameCombobox</strong> nunca jamás en la vida va a ser <strong>null</strong> por lo tanto ese <strong>if</strong> esta de sobra. Escriba código que realmente es útil y que funciona.</p><img src="/images/2014/c8cf9d7708f56cda222c7f3fb8a5c9cd-20140923.png" class="" title="Confusión"><p>Hay algunas cosas que no tienen una explicación razonable, como instanciar un objeto para luego no utilizarlo. Esto sólo provoca perdida de preciados bytes y ciclos de procesador.</p><img src="/images/2014/861615e07816c3553c1d99d0fc35a9c0-20140826.png" class=""><p>Creo que califica en la misma descripción de arriba, escriba código que funcione.</p><img src="/images/2014/fe4d2cbe378bfa37_20140123.png" class=""><p>Si va a utilizar <strong>StringBuffer</strong> hágalo de la forma correcta, se merece un mínimo de respeto dicha clase.</p><img src="/images/2014/89a200b6791dc2c5_20140106.png" class=""><p>Evite el código que está de más, la API de commons-lang <strong>StringUtils.isEmpty()</strong> evalua que sea <strong>null</strong> y vacío. Ahora bien en el código podrían utilizar de la misma API <strong>StringUtils.isNotEmpty()</strong> y con eso le sacan el signo <strong>!</strong> y todo queda mas bonito, por su puesto que la primera parte del <strong>if</strong> vuela también del código.</p><img src="/images/2014/51bb732a2360b0f484996a1adfffc807-20141003.png" class=""><p>Finalmente esto se traduce en:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (StringUtils.isNotEmpty(codeAdditional))&#123;</span><br><span class="line">  ....</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Espero les sirvan estos anti-ejemplos de código fuente. A medida que siga revisando código iré agregando algún otro post con mas código para el bronce. La discusión esta abierta por si quieren agregar algún otro tip.</p><blockquote><p>PD: Las variables han sido renombradas para proteger a los verdaderos autores, cualquier coincidencia con la realidad es casualmente cierta y verídica.</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;En este post, pondré algunas capturas de pantallas de cosas que Ud. como desarrollador (java) no debe hacer (en algunos casos debe evitar</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    
    <category term="java" scheme="https://blog.pcollaog.cl/tags/java/"/>
    
    <category term="ejemplos" scheme="https://blog.pcollaog.cl/tags/ejemplos/"/>
    
  </entry>
  
  <entry>
    <title>¿Ha muerto el diseño?</title>
    <link href="https://blog.pcollaog.cl/2014/06/08/ha-muerto-el-diseno/"/>
    <id>https://blog.pcollaog.cl/2014/06/08/ha-muerto-el-diseno/</id>
    <published>2014-06-08T04:00:00.000Z</published>
    <updated>2025-11-01T19:36:46.062Z</updated>
    
    <content type="html"><![CDATA[<p>Este artículo es sólo un <em>copy&amp;paste</em> de un viejo articulo de <a href="http://martinfowler.com/">Martin Fowler</a> titulado <a href="http://martinfowler.com/articles/designDead.html">¿Ha muerto el diseño?</a>, todo esto porque el otro día lo anduve buscando en español y el link esta roto.</p><p>Aún recuerdo cuando entré a trabajar como informático y me recibieron con este artículo. (ping <a href="https://twitter.cl/ferchik">@ferchik</a>)</p><p>Pues aquí mi grano de arena para que este artículo no se pierda. Aquí va el artículo.</p><h1 id="¿-Ha-muerto-el-diseno"><a href="#¿-Ha-muerto-el-diseno" class="headerlink" title="¿ Ha muerto el diseño ?"></a>¿ Ha muerto el diseño ?</h1><p>Para algunas personas que sólo han tenido un contacto breve con la <a href="http://www.extremeprogramming.org/">Programación Extrema</a>, pareciera que la XP convoca a la muerte del diseño de software. No solamente se ridiculiza a la actividad de diseño como “Big Up Front Design”, sino que técnicas como UML, marcos flexibles e incluso patrones son menospreciados o simplemente ignorados. De hecho la XP involucra mucho diseño, pero lo hace de una manera diferente a la de los procesos de software establecidos. La XP ha rejuvenecido la noción de diseño evolutivo con prácticas que permiten a la evolución ser una estrategia de diseño viable. También brinda nuevos retos y habilidades pues los diseñadores necesitan aprender cómo hacer diseño simple, cómo usar refactorización para mantener el diseño limpio y cómo usar patrones en un estilo evolutivo.</p><p>La Programación Extrema (XP por sus siglas en inglés) desafía muchos de los presupuestos comunes acerca del desarrollo de software. La más controversial es el rechazo a un esfuerzo significativo en el diseño previo, en favor de un estilo más evolutivo. Para sus detractores, esto es un retorno al desarrollo “codificar y corregir” - usualmente denostado como hackear. Para sus fans esto es frecuentemente visto como un rechazo a técnicas de diseño (tal como el UML), principios y patrones. No preocuparse por el diseño, si escuchas tu código un buen diseño aparecerá.</p><p>Me encuentro en el centro de este debate. Gran parte de mi carrera ha involucrado lenguajes gráficos de diseño -el Unified Modeling Language (UML) y sus seguidores- y patrones. Realmente he escrito libros tanto sobre UML como sobre patrones. ¿Significa mi adhesión a la XP una renuncia a todo lo que he escrito sobre esos temas, limpiando mi mente de todas esas nociones contrarrevolucionarias?</p><p>Bueno, no puedo prolongar más el suspenso. La respuesta corta es no. La larga es el resto de este artículo.</p><h2 id="Diseno-planeado-y-evolutivo"><a href="#Diseno-planeado-y-evolutivo" class="headerlink" title="Diseño planeado y evolutivo"></a>Diseño planeado y evolutivo</h2><p>Voy a describir dos estilos de cómo se diseña en desarrollo de software. Quizá el más común es el diseño evolutivo. Esencialmente, evolutivo significa que el diseño del sistema crece conforme se implanta el sistema. El diseño es parte del proceso de programación y conforme el programa evoluciona el diseño cambia.</p><p>En su uso común, el diseño evolutivo es un desastre. El diseño acaba siendo la agregación de una sarta de decisiones tácticas ad-hoc, cada una de las cuales hace el código más difícil de modificar. Se podría alegar que eso no es diseño, ciertamente suele llevar a un diseño pobre. Como indica Kent, el diseño está para permitir cambiar el software fácilmente a largo plazo. Conforme el diseño se deteriora, igualmente se deteriora la capacidad de cambio. Se tiene el estado de entropía de software, conforme pasa el tiempo el diseño empeora y empeora. Esto no solo hace el software más difícil de cambiar, también facilita la generación de bugs y dificulta el encontrarlos y eliminarlos con seguridad. Esta es la pesadilla de “codifica y corrige”, donde los bugs devienen exponencialmente más costosos de arreglar conforme el proyecto avanza.</p><p>El diseño planeado es todo lo contrario, y contiene nociones nacidas de otras ramas de la ingeniería. Si usted quiere construir la casa de su perro, puede simplemente tomar unas tablas y construir una forma ruda. Si quiere construir un rascacielos, no puede hacerlo de la misma manera - se caería antes de terminar siquiera la mitad. Así que empieza con dibujos ingenieriles, hechos en un estudio ingenieril como en el que trabaja mi esposa en el centro de Boston. Conforme hace el diseño ella se figura todo el asunto, en parte por análisis matemático pero principalmente usando códigos de construcción. Los códigos de construcción son reglas acerca de cómo diseñar estructuras con base en la experiencia de qué es lo que funciona bien (y algo de matemáticas). Una vez hecho el diseño, su compañía ingenieril puede pasar el diseño a otra empresa que lo construya.</p><p>El diseño planeado en software debería funcionar de la misma manera. Los diseñadores piensan los grandes problemas con anticipación. No necesitan programar porque no están construyendo el software, sólo lo están planeando. Así que pueden usar técnicas de diseño como el UML que deja de lado algunos de los detalles de la programación y permite a los diseñadores trabajar a un nivel más abstracto. Una vez hecho el diseño, pueden pasarlo a otro grupo (o a otra compañía) que lo construya. Ya que los diseñadores están pensando en una escala mayor, pueden evitar las series de decisiones tácticas que llevan a la entropía del software. Los programadores pueden seguir la dirección del diseño y, dado que siguen el diseño al pie de la letra, tener un sistema bien construido.</p><p>Ahora bien, el diseño planeado ha estado allí desde los 70s, y mucha gente lo ha usado. Es mejor en muchas formas que el diseño evolutivo de codificar y corregir. Pero tiene algunas fallas. La primera es que es imposible pensar en todos los problemas que se necesitan tratar cuando se programa. Es inevitable que al programar se encuentren cosas que ponen en entredicho el diseño. Si los diseñadores ya acabaron y ya están en otro proyecto, ¿qué pasa? Los programadores empiezan a codificar en torno al diseño y la entropía aparece. Aún si el diseñador no se ha ido, lleva tiempo organizar los problemas de diseño, cambiar los dibujos y alterar el código. Usualmente se hace una corrección rápida por la presión de tiempo. Entropía (otra vez).</p><p>Además frecuentemente hay un problema cultural. Los diseñadores se han formado por su habilidad y experiencia, pero están tan ocupados trabajando en diseños que ya no tienen tiempo para programar. Sin embargo las herramientas y materiales de desarrollo de software cambian rápidamente. Cuando dejas de programar no solo pierdes los cambios que ocurren en este flujo tecnológico, también pierdes el respeto de los que sí programan.</p><p>Esta tensión entre constructores y diseñadores también existe en la construcción, pero es más intensa en el software. Es intensa porque hay una diferencia clave. En construcción hay una división clara de habilidades entre los que diseñan y los que construyen, pero en software no es tanto así. Cualquier programador trabajando en ambientes de alto diseño necesita ser muy hábil. Lo suficientemente hábil para cuestionar los diseños del diseñador, especialmente cuando el diseñador sabe menos acerca de las realidades diarias de la plataforma de desarrollo.</p><p>Ahora bien, estos problemas pueden corregirse. Podríamos manejar la tensión humana. Quizá podemos conseguir diseñadores tan hábiles para tratar con la mayoría de los problemas y tener un proceso suficientemente disciplinado para cambiar los dibujos. Aún hay otro problema: los requerimientos cambiantes. Ese es el problema número uno, causante de dolores de cabeza en los proyectos de software en que he participado.</p><p>Una manera de controlar los requerimientos cambiantes es añadir flexibilidad en el diseño de modo que se pueda cambiar fácilmente conforme cambian los requerimientos. Esto requiere perspicacia en la clase de cambios esperados. Un diseño puede planearse para tratar con áreas de volatilidad, pero mientras eso ayuda con cambios de requerimientos previstos, no ayuda (y puede dañar) con cambios imprevistos. Así que los requerimientos tienen que entenderse lo suficientemente bien para separar las áreas volátiles, y en mi experiencia eso es muy difícil.</p><p>Algunos de estos problemas de requerimientos se deben a la falta de un entendimiento claro de los mismos. Mucha gente se enfoca en los procesos de ingeniería de requerimientos con la esperanza de que esto prevendrá la necesidad de cambiar el diseño más tarde. Pero aún esta receta puede no llevar a la cura. Muchos requerimientos cambiantes imprevistos ocurren debido a cambios en el negocio. Esos no pueden prevenirse, no importa cuan cuidadoso sea el proceso de ingeniería de requerimientos.</p><p>Esto hace sonar imposible al diseño planeado. Ciertamente estos son grandes retos. Pero no me inclino a afirmar que el diseño planeado es peor que el evolutivo, bajo el estilo “codifica y corrige”. De hecho prefiero el diseño planeado. No obstante estoy consciente de los problemas del diseño planeado y busco una dirección nueva.</p><h2 id="Las-Practicas-Habilitadoras-de-la-XP"><a href="#Las-Practicas-Habilitadoras-de-la-XP" class="headerlink" title="Las Prácticas Habilitadoras de la XP"></a>Las Prácticas Habilitadoras de la XP</h2><p>La XP es controversial por muchas razones, pero una de las banderas rojas clave de la XP es que aboga por el diseño evolutivo en lugar del diseño planeado. Como sabemos, el diseño evolutivo no puede funcionar debido a decisiones ad-hoc y la entropía de software.</p><p>El meollo para entender este argumento es la curva de cambio del software. La curva del cambio dice que mientras más avanza el proyecto, es exponencialmente más caro hacer cambios. La curva del cambio se expresa usualmente en términos de las fases “un cambio hecho en el análisis por $1 cuesta miles en producción”. Esto es irónico ya que la mayoría de los proyectos aún trabajan en un proceso ad-hoc que no tiene una fase de análisis, pero las exponenciaciones aún están allí. La curva exponencial del cambio significa que el diseño evolutivo no puede funcionar. También explica por qué el diseño planeado debe ser hecho cuidadosamente porque cualquier error encara la misma exponenciación.</p><p>La suposición fundamental de la XP es que es posible aplanar la curva del cambio lo suficiente como para hacer que funcione el diseño evolutivo. Este aplanamiento es a la vez permitido y explotado por la XP. Esto es parte del enganche de prácticas en XP: específicamente no puedes hacer todas las cosas que explotan la curva aplanada sin hacer las cosas que permiten aplanarla. Esta es una fuente común de controversia sobre la XP. Mucha gente critica la explotación sin entender la habilitación. Frecuentemente las críticas surgen de la propia experiencia de los críticos que no hicieron las prácticas habilitadoras que permiten funcionar a las prácticas explotadoras. Como resultado se quemaron y cuando ven la XP recuerdan el fuego.</p><p>En el centro de las prácticas habilitadoras están las de Pruebas e Integración Continua. Sin la seguridad dada por las pruebas el resto de la XP sería imposible. La integración continua es necesaria para mantener al equipo en sincronía, de modo que puedas hacer un cambio sin preocuparte de integrarla con otra gente. Juntas, estas prácticas pueden tener un gran efecto en la curva del cambio. Me acordé de esto otra vez aquí en ThoughtWorks. La introducción de Pruebas e Integración Continua ha marcado un mejoramiento en el esfuerzo de desarrollo. Ciertamente suficiente para cuestionar seriamente la afirmación de la XP de que necesitas todas las prácticas para lograr una gran mejoría.</p><p>La refactorización tuvo un efecto similar. La gente que refactoriza su código de la manera disciplinada sugerida por la XP encuentra una diferencia significativa en la efectividad comparada a hacer una reestructuración relajada más ad-hoc. Esa fue ciertamente mi experiencia una vez que Kent me enseñó a refactorizar propiamente. Después de todo, sólo un cambio así de fuerte me habría motivado a escribir un libro entero sobre el tema.</p><p>Jim Highsmith, en su excelente resumen de la XP, usa la analogía de un conjunto de escalas. En una bandeja está el diseño planeado, en la otra la refactorización. En propuestas más tradicionales el diseño planeado domina porque se supone que no puedes cambiar de idea más tarde. Conforme baja el costo del cambio puedes hacer más con tu diseño más tarde como refactorización. El diseño planeado no se esfuma, solo que ahora hay un balance entre los dos acercamientos. Para mi, siento que antes de la refactorización estaba diseñando con una sola mano.</p><p>Estas prácticas habilitadoras de integración continua, pruebas y refactorización, crean un nuevo ambiente que hace plausible el diseño evolutivo. Sin embargo algo que aún no imaginamos es el lugar del punto de equilibrio. Estoy seguro de que, a pesar de la impresión externa, XP no es sólo prueba, codifica y refactoriza. Hay espacio para el diseño antes de codificar. Algo de esto ocurre antes de que se haya código, la mayor parte ocurre en las iteraciones antes de codificar una tarea particular. Pero hay un nuevo balance entre diseño <em>up-front</em> y refactorización.</p><h2 id="El-valor-de-la-Simplicidad"><a href="#El-valor-de-la-Simplicidad" class="headerlink" title="El valor de la Simplicidad"></a>El valor de la Simplicidad</h2><p>Dos de los más grandes gritos de batalla de la XP son los eslogans “Haz la cosa más simple que pueda funcionar” y “No lo vas a necesitar” (conocido como YAGNI por sus siglas en inglés). Ambos son manifestaciones de la práctica XP del diseño simple.</p><p>La manera en que usualmente se describe YAGNI, es que no deberías añadir hoy código que sólo será usado por alguna característica que será necesaria mañana. En principio esto suena simple. El problema viene con cosas tales como marcos (frameworks), componentes reusables, y diseño flexible. Tales cosas son complicadas de construir. Se paga un costo up-front extra para construirlas, en la expectativa de que recuperarás ese costo más tarde. Esta idea de construir flexibilidad up-front es vista como la parte clave del diseño de software efectivo.</p><p>Sin embargo el consejo de la XP es que no construyas componentes flexibles y frameworks para el primer caso que necesite esa funcionalidad. Deja crecer esas estructuras como se necesiten.</p><p>Si quiero una clase Money hoy que maneje adición pero no multiplicación entonces solo construyo adición en la clase Money. Aún si estoy seguro de que necesitaré multiplicación en la iteración siguiente, y entiendo cómo hacerlo fácilmente, y creo que sería realmente rápido hacerlo, aún así lo dejaré para la siguiente iteración.</p><p>Una razón de esto es económica. Si tengo que trabajar por una característica que sólo se necesitará mañana, estoy comprometiendo esfuerzo de características que necesitan hacerse para la iteración actual. El plan de entrega dice qué es lo que necesita trabajarse ahora, trabajar en cosas del futuro es contrario a los acuerdos de los desarrolladores con el cliente. Hay un riesgo de que las historias de la iteración pudieran no hacerse. Aún si estas historias de la iteración no están en riesgo depende del cliente decidir que trabajo extra debe hacerse -y que podría no incluir aún la multiplicación.</p><p>Este contraincentivo económico es reforzado por la posibilidad de que pudiéramos no hacerlo bien. Como sea que estemos seguros de que esta función trabaja, aún podríamos equivocarnos -especialmente si aún no tenemos requerimientos detallados. Trabajar en la solución errónea anticipadamente es aún peor despilfarro que trabajar en la función correcta con anticipación. Y los XPertos generalmente creen que es más probable que nos equivoquemos (y yo concuerdo con esa opinión).</p><p>La segunda razón por el diseño simple es que un diseño complejo es más difícil de entender que un diseño simple. Por lo tanto cualquier modificación al sistema se hace más difícil por la complejidad añadida. Esto agrega un costo en el periodo que va de cuando el diseño más complicado se añadió a cuando se necesitó.</p><p>Ahora bien, para mucha gente este consejo no tiene sentido, y tienen razón. Tienen razón si te imaginas en el mundo de desarrollo convencional donde las prácticas habilitadoras de la XP no existen. No obstante, cuando el balance entre diseño planeado y evolutivo cambia, entonces YAGNI se convierte en una buena práctica (y sólo entonces).</p><p>Para resumir, no debes gastar esfuerzo añadiendo cosas que no serán necesarias hasta una iteración futura. Aun si el costo es cero, no debes porque eso incrementa el costo de modificación. De cualquier manera sólo puedes comportarte así si estás usando XP o alguna práctica similar que baje el costo del cambio.</p><h2 id="Finalmente-Que-Demonios-es-Simplicidad"><a href="#Finalmente-Que-Demonios-es-Simplicidad" class="headerlink" title="Finalmente Qué Demonios es Simplicidad"></a>Finalmente Qué Demonios es Simplicidad</h2><p>Así que queremos nuestro código tan simple como sea posible. Eso no suena difícil de sostener, después de todo ¿quién quiere ser complicado? Pero desde luego esto trae la pregunta “¿qué es simple?”</p><p>En XPE Kent da cuatro criterios para un diseño simple, en orden de importancia:</p><ul><li>Correr todas las pruebas</li><li>Revelar toda la intención</li><li>Evitar duplicación</li><li>El menor número de clases y métodos</li></ul><p>El que corran todas las pruebas es un criterio muy simple. No duplicación también es muy directo, aunque muchos de los desarrolladores necesitan guía para lograrlo. El truco tiene que ver con revelar la intención. ¿Qué significa eso exactamente?</p><p>El valor básico aquí es claridad de código. XP pone en alto el código fácil de leer. En XP “código astuto” es un término de abuso. Pero para algunas personas, el código que revela la intención es otra astucia.</p><p>En su artículo en XP 2000, Josh Kerievsky señala un buen ejemplo de esto. El atiende al que posiblemente es el código XP más público - JUnit. JUnit usa decoradores para añadir funcionalidad opcional a los casos de prueba, tales como sincronización concurrente y código batch set up. Separando este código en decoradores permite al código general ser más claro de lo que podría ser.</p><p>Pero uno se pregunta si el código resultante es realmente simple. Para mí lo es, pero estoy familiarizado con el patrón Decorator. Pero para muchos que no lo están esto es muy complicado. Similarmente JUnit usa métodos enchufables los cuales, he notado, la mayoría de la gente los encuentra cualquier cosa menos claros. ¿Así que debemos concluir que el diseño de JUnit es simple para diseñadores experimentados pero complicado para los menos experimentados?</p><p>Yo creo que el meollo en eliminar la duplicación, tanto el “Una vez y sólo una vez” de la XP y el DRY (Don’t Repeat Yourself) del Programador Pragmático es uno de esos obvios y maravillosamente poderosos buenos consejos. El solo seguirlo puede llevar muy lejos. Pero no es todo, y la simplicidad es aún algo complicado de hallar.</p><p>Recientemente me vi envuelto en hacer algo que bien podría estar sobrediseñado. Lo arreglamos refactorando y removiendo algo de su flexibilidad. Pero como uno de los desarrolladores dijo “es más fácil refactorizar sobrediseño que refactorizar sin diseño”. Es mejor ser un poco más simple de lo que necesitas ser, pero no es un desastre ser un poco más complejo.</p><p>El mejor consejo que he escuchado sobe todo esto vino del tío Bob (Robert Martin). Su consejo fue no demorarse mucho sobre cual es el diseño más simple. Después de todo se puede, se debe y se refactorará más tarde. Al final la disposición a refactorizar es más importante que saber que la cosa más simple ya está.</p><h2 id="La-refactorizacion-viola-YAGNI"><a href="#La-refactorizacion-viola-YAGNI" class="headerlink" title="La refactorización viola YAGNI"></a>La refactorización viola YAGNI</h2><p>Este asunto surgió recientemente en la lista de correo XP, y vale la pena traerlo a colación, ya que estamos viendo el rol del diseño en la XP.<br>Básicamente la cuestión empieza con el punto de que la refactorización toma tiempo pero no añade funcionalidad. Como el punto del YAGNI es que se supone que se debe diseñar para el presente y no para el futuro, ¿es esto una violación?</p><p>El punto de YAGNI es no añadir complejidad innecesaria para las historias actuales. Esto es parte de la práctica del diseño simple. Refactorizar es necesario para mantener el diseño tan simple como puedas, así que debes refactorizar cuando notes que puedes simplificar las cosas.</p><p>El diseño simple explota las prácticas de la XP y es también una práctica habilitadora. Sólo si has hecho pruebas, integrado continuamente y refactorizando puedes practicar el diseño simple efectivamente. Pero al mismo tiempo, mantener el diseño simple es esencial para mantener la curva del cambio plana. Cualquier complejidad innecesaria hace al sistema difícil de cambiar en toda dirección excepto la que anticipaste con la complicada flexibilidad añadida. Sin embargo la gente no es buena anticipando, así que es mejor esforzarse por la simplicidad. No se obtiene la cosa más simple la primera vez, así que necesitas refactorizar para acercarte a la meta.</p><h2 id="Patrones-y-XP"><a href="#Patrones-y-XP" class="headerlink" title="Patrones y XP"></a>Patrones y XP</h2><p>El ejemplo JUnit me lleva inevitablemente a los patrones. La relación entre patrones y la XP es interesante y es una cuestión común. Joshua Kerievsky arguye que los patrones son subestimados en la XP y lo sustenta elocuentemente, así que no lo repetiré. Pero vale la pena tomar en cuenta que para mucha gente los patrones parecen estar en conflicto con la XP.</p><p>La esencia de este argumento es que los patrones frecuentemente se sobreutilizan. El mundo esta lleno del legendario buen programador, fresco de su primera lectura del GOF que incluye 16 patrones en 32 líneas de código. Recuerdo una tarde, alimentada por una muy buena cerveza, trabajando con Kent en un artículo que sería llamado “Patrones de No Diseño: 23 trucos baratos”. Estábamos pensando en cosas como usar una declaración <em>if</em> en lugar de una estrategia. La broma tenía una razón, los patrones son frecuentemente sobreutilizados, pero eso no los hace tan mala idea. La cuestión es cómo los usas.</p><p>Una teoría es que las fuerzas del diseño simple te llevarán a los patrones. Muchas refactorizaciones hacen esto explícitamente, pero aún sin ellas siguiendo las reglas del diseño simple llegarás a los patrones aun si no los conoces previamente. Esto puede ser cierto pero, ¿es la mejor forma de hacerlo? Seguramente es mejor si sabes toscamente a dónde vas y tienes un libro que te guíe en lugar de tener que inventarlo tú mismo. Yo ciertamente aún uso el GOF cuando siento que surge un patrón. Para mí el diseño efectivo implica que necesitamos saber si vale la pena pagar el precio de un patrón -eso es su propia habilidad. Similarmente, como sugiere Joshua, necesitamos estar más familiarizados acerca de cómo llegar a un patrón gradualmente. En este respecto la XP trata la manera en que usamos patrones diferente a la manera en que algunas personas los usan, pero ciertamente no elimina su valor.</p><p>Leyendo algunas de las listas de correo tengo la sensación de que mucha gente ve a la XP como desalentadora de patrones, a pesar de la ironía de que la mayoría de los proponentes de la XP también han sido líderes del movimiento de los patrones. ¿Será que ellos han visto más allá de los patrones, o tienen a los patrones tan embebidos en su pensamiento que ellos ya no lo notan? No sé la respuesta para otros, pero para mí los patrones aún son vitalmente importantes. XP puede ser un proceso de desarrollo, pero los patrones son una columna vertebral del conocimiento de diseño, conocimiento que es valioso cualquiera que sea el proceso. Procesos diferentes pueden usar patrones de diferente manera. XP enfatiza no usar patrones hasta que sea necesario y evolucionar el camino hacia un patrón vía una implementación simple. Pero los patrones son todavía una pieza clave de conocimiento a adquirir.</p><p>Mi consejo a los XPeros en el uso de patrones es:</p><ul><li>Invertir tiempo en aprender sobre patrones</li><li>Concentrarse en cuándo aplicarlos (no muy pronto)</li><li>Concentrarse en cómo implementar el patrón en su forma más simple primero, y añadir complejidad luego.</li><li>No temer eliminar un patrón si no está valiendo su peso.</li></ul><p>Pienso que la XP debería enfatizar aprender más sobre patrones. No estoy seguro de cómo encajaría esto en las prácticas de la XP, pero estoy seguro que Kent puede encontrar la manera.</p><h2 id="Creciendo-una-arquitectura"><a href="#Creciendo-una-arquitectura" class="headerlink" title="Creciendo una arquitectura"></a>Creciendo una arquitectura</h2><p>¿Qué queremos decir con arquitectura de software? Para mí el término arquitectura conlleva una noción de los elementos centrales del sistema, las piezas que son difíciles de cambiar. Un fundamento sobre el cual debe construirse el resto.</p><p>¿Qué rol juega la arquitectura cuando usamos diseño evolutivo? De nuevo los críticos de la XP afirman que la XP ignora la arquitectura, que la ruta de la XP es ir hacia la codificación rápida y confiar en que la refactorización resolverá todos los problemas de diseño. Interesantemente tienen razón, y eso bien puede ser una debilidad. Ciertamente los más agresivos XPeros - Kent Beck, Ron Jeffries y Bob Martin - están poniendo más y más energía en evitar cualquier diseño arquitectónico. No pongas una base de datos hasta que realmente sepas que la necesitas. Trabaja con archivos primero y refactoriza a la base de datos en una iteración posterior.</p><p>Yo soy conocido por ser un XPero cobarde, y como tal tengo que discordar. Yo creo que hay lugar para una amplia arquitectura inicial. Cosas tales como establecer temprano cómo separaremos la aplicación, como interaccionaremos con la base de datos (si hace falta una), qué estrategia usar para manejar el servidor web.</p><p>Esencialmente creo que muchas de estas áreas son patrones que hemos aprendido a través de los años. Conforme crece el conocimiento de patrones, se debe tener una idea razonable de cómo usarlos. De cualquier modo la diferencia clave es que no se espera poner en piedra estas decisiones arquitectónicas tempranas , o bien el equipo sabe que ellas pueden errar sus decisiones tempranas y deberán tener el valor de arreglarlas. Otros cuentan la historia de un proyecto en que, cerca de la implantación, deciden que no necesitaban más EJB y lo quitaron del sistema. Fue una refactorización considerable, se hizo tarde, pero las prácticas habilitadoras lo hicieron no sólo posible, sino valioso.</p><p>Cómo habría funcionado esto de la otra manera. Si decides no usar EJB, ¿habría sido más difícil añadirlo luego? ¿No debes pues empezar con EJB hasta que hayas tratado cosas sin él y encontrado su falta? Es una pregunta que implica varios factores. Ciertamente trabajar sin un componente complejo incrementa la simplicidad y hace las cosas ir más rápido. Sin embargo algunas veces es más fácil sacar algo que meterlo.</p><p>Mi consejo es empezar estimando la arquitectura probable. Si ves un gran montón de datos con múltiples usuarios, adelante, usa una base de datos desde el primer día. Si ves lógica de negocio compleja, pon un modelo del dominio. De cualquier modo en deferencia a los dioses del YAGNI, cuando dudes ve al lado de la simplicidad. También prepárate para simplificar tu arquitectura tan pronto veas que parte de la misma no está dando nada.</p><h2 id="UML-y-XP"><a href="#UML-y-XP" class="headerlink" title="UML y XP"></a>UML y XP</h2><p>De todas las preguntas que me hacen sobre mi compromiso con la XP una de las más grandes es respecto a mi asociación con el UML. ¿No son los dos incompatibles?</p><p>Hay un número de puntos de incompatibilidad. Ciertamente la XP menosprecia los diagramas en gran medida. Aunque la posición oficial es en la línea de “úsalos si son útiles”, se puede leer entre líneas “los verdaderos XPeros no diagraman”. Esto se refuerza con el hecho de que gente como Kent no se sienten cómodos con los diagramas, de hecho nunca he visto a Kent dibujar voluntariamente un diagrama de software en ninguna notación fija.</p><p>Yo creo que el asunto viene de dos causas separadas. Una es el hecho de que algunas personas encuentran los diagramas útiles y otras no. El peligro está en los que piensan que quienes no los usan deberían usarlos y viceversa. En lugar de eso deberíamos aceptar que algunos usen diagramas y otros no.</p><p>El otro problema es que los diagramas tienden a asociarse con procesos pesados. Tales procesos gastan mucho tiempo en dibujar diagramas que no ayudan y pueden dañar. De manera que pienso que la gente debe ser guiada en cómo usar bien los diagramas y evitar las trampas, en lugar del mensaje “solo si tienes que” de los XPertos.</p><p>Aquí esta mi consejo para usar bien los diagramas.</p><p>Primero piensa para qué los estás dibujando. El principal valor es la comunicación. Comunicación efectiva significa seleccionar las cosas más importantes y descuidar las menos. Esta selectividad es la clave para usar bien el UML. No dibujes cada clase -sólo las importantes. Para cada clase, no muestres cada atributo y operación -sólo los importantes. No dibujes diagramas de secuencia para todos los casos de uso y escenarios -sólo… ya lo entiendes. Un problema común con el uso de los diagramas es que la gente intenta hacerlos extensos. El código es la mejor fuente de información extensa ya que el código es lo más fácil de mantener en sincronía con el código. La exhaustibilidad de los diagramas es la enemiga de su comprensión.</p><p>Un uso común de los diagramas es explorar un diseño antes de empezar a programarlo. Frecuentemente se tiene la impresión de que tal actividad es ilegal en XP, pero eso no es cierto. Mucha gente dice que cuando se tiene una tarea difícil vale la pena juntarse para tener una sesión de diseño rápido. De cualquier manera cuando hagan tales sesiones:</p><ul><li>manténganlas cortas</li><li>no traten de concentrarse en todos los detalles (sólo los importantes)</li><li>traten el diseño resultante como un esbozo, no como el diseño final</li></ul><p>El último punto merece extenderse. Cuando se hace un diseño <em>up-front</em>, inevitablemente encontrarás que algunos aspectos del diseño están mal, y eso sólo se descubre cuando lo programas. Eso no es un problema dado que entonces cambias el diseño. El problema viene cuando la gente piensa que el diseño está hecho y entonces no aprovechan la oportunidad de devolver al diseño el conocimiento adquirido al programar.</p><p>Cambiar el diseño no necesariamente implica cambiar los diagramas. Es perfectamente razonable dibujar diagramas que te ayuden a entender el diseño y entonces hacerlos a un lado. El dibujarlos ayudó y eso es suficiente para que valga la pena hacerlos. Pero no tienen que ser artefactos permanentes. Los mejores diagramas UML no son artefactos.</p><p>Muchos XPeros usan tarjetas CRC. Eso no entra en conflicto con el UML. Yo uso una mezcla de CRC y UML todo el tiempo, usando la técnica que sea más útil para el trabajo en mano.</p><ul><li>Toma mucho tiempo mantener los diagramas actualizados, así que pierden sincronía con el código.</li><li>Están ocultos en una herramienta CASE, así que nadie los mira.</li></ul><p>El consejo de documentación sobre la marcha viene de estos problemas observados:</p><ul><li>Sólo usa diagramas que puedas mantener actualizados sin esfuerzo notable.</li><li>Pon los diagramas donde todos puedan verlos fácilmente. Me gusta pegarlos en la pared. Alienta a la gente a editar la copia en la pared para cambios simples.</li><li>Presta atención a si alguien usa los diagramas. Si nadie lo hace, tíralos.</li></ul><p>El último aspecto de usar UML es para documentación en una situación de relevo, tal como cuando un grupo ocupa el lugar de otro. Aquí el punto XP es que producir documentación es una historia como cualquier otra, y así su valor de negocio es determinado por el cliente. Otra vez la UML es útil aquí, los diagramas son selectivos para ayudar a la comunicación. Recuerda que el código es el repositorio de información detallada, el diagrama actúa para resumir y resaltar asuntos importantes.</p><h2 id="Sobre-la-Metafora"><a href="#Sobre-la-Metafora" class="headerlink" title="Sobre la Metáfora"></a>Sobre la Metáfora</h2><p>Bueno, podría decirlo públicamente -no he captado el punto de esta cosa, metáfora. La he visto funcionar, y funcionó bien en el proyecto C3, pero eso no significa que yo tenga una idea de cómo hacerla, ni menos cómo explicar cómo hacerla.</p><p>La práctica XP de la metáfora se originó a partir de la propuesta de Ward Cunningham de un sistema de nombres. El punto es que vienes con un bien conocido conjunto de nombres que actúan como vocabulario para hablar acerca del dominio. Este sistema de nombres juega en el modo en que nombras las clases y métodos en el sistema.</p><p>He construido un sistema de nombres construyendo un modelo conceptual del dominio. Lo he hecho con los expertos del dominio usando UML o sus predecesores. He encontrado que hay que ser cuidadoso al hacerlo. Se necesita mantener un conjunto de notación mínimo y tienes que guardarte de dejar que cualquier asunto técnico se cuele en el modelo. Pero si lo haces, he encontrado que puedes usarlo para construir un vocabulario del dominio que los expertos del dominio puedan entender y usarlo para comunicarse con los desarrolladores. El modelo no empareja con el diseño de clases perfectamente, pero es suficiente para dar un vocabulario común de todo el dominio.</p><p>Ahora, no veo ninguna razón por la que este vocabulario no pueda ser metafórico, tal como la metáfora C3 en que la nómina se convirtió en una linea de ensamblaje de fábrica. Pero tampoco veo por qué el basar tu sistema de nombres en el vocabulario del dominio sea tan mala idea. Ni me inclino a abandonar una técnica que funciona bien para mi obteniendo los nombres del sistema.</p><p>Frecuentemente se critica a la XP sobre la base de que se necesita al menos algún esbozo de diseño de un sistema. Los XPeros frecuentemente responden con la respuesta “esa es la metáfora”. Pero yo aún no creo haber visto una explicación convincente de la metáfora. Este es un hoyo real en la XP, y uno que el XPero necesita sortear.</p><h2 id="¿Quieres-ser-arquitecto-cuando-seas-grande"><a href="#¿Quieres-ser-arquitecto-cuando-seas-grande" class="headerlink" title="¿Quieres ser arquitecto cuando seas grande?"></a>¿Quieres ser arquitecto cuando seas grande?</h2><p>En la última década, el término “arquitecto de software” se ha vuelto popular. Es un término que me resulta difícil de usar. Mi esposa es ingeniero estructural. La relación entre ingenieros y arquitectos es … interesante. Mi favorito es “los arquitectos son buenos para las tres B’s: bulbos, bushes [arbustos], birds [pájaros]”. La idea es que los arquitectos salen con todos esos dibujos bonitos, pero son los ingenieros quienes tienen que asegurarse de que realmente puedan ponerse en pie. Como resultado he evitado el término arquitecto de software; después de todo si mi esposa no puede tratarme con respeto profesional quién puede hacerlo.</p><p>En software, el término arquitecto significa muchas cosas. (En software cualquier término significa muchas cosas.) En general, sin embargo conlleva ciertos problemas, como “no soy un mero programador -soy un arquitecto”. Esto puede traducirse como “ahora soy un arquitecto -soy demasiado importante como para programar”. La cuestión es si separarte del mundano esfuerzo de programar es algo que debes hacer si quieres ejercer liderazgo técnico.</p><p>Esta cuestión genera demasiada emoción. He visto gente enojarse mucho al pensar que no tienen más el rol de arquitectos. “No hay lugar en XP para arquitectos experimentados” es el grito que frecuentemente escucho.</p><p>Tanto como en el rol del diseño en sí, no creo que sea el caso que la XP no valore la experiencia de o las buenas habilidades de diseño. En realidad muchos de los proponentes de la XP - Kent Beck, Bob Martin, y desde luego Ward Cunningham - están entre de quienes he aprendido mucho acerca de lo que es el diseño. De cualquier manera esto significa que sus roles difieren de lo que mucha gente ve como un rol de liderazgo técnico.</p><p>Como ejemplo, citaré a uno de nuestros líderes técnicos en ThoughtWorks: Dave Rice. Dave ha estado en varios ciclos de vida y se ha puesto el sombrero extraoficial de líder técnico en un proyecto de 50 personas. Su rol como líder significa gastar mucho tiempo con los programadores. El trabaja con un programador cuando éste necesita ayuda, siempre anda merodeando para ver quién necesita ayuda. Una señal significativa es cuando se sienta. Como un trabajador de mucho tiempo en ThoughtWorks, él podría muy bien tener la oficina que quisiera. Compartió una por un tiempo con Cara, la gerente de entregas. Sin embargo en los últimos meses se mudó a las bahías abiertas donde trabajan los programadores (usando el estilo abierto “war room” que la XP favorece). Esto es importante para él porque de este modo ve lo que está pasando y está disponible para dar la mano donde se necesite.</p><p>Aquellos que saben XP se darán cuenta de que estoy describiendo el rol explícito de Coach. En verdad uno de los varios juegos de palabras que hace la XP es que llama a la figura de primer técnico el “Coach”. El significado es claro: en XP el liderazgo técnico se muestra enseñando a los programadores y ayudándolos a tomar decisiones. Es uno que requiere buena habilidad de gentes tanto como buenas habilidades técnicas. Jack Bolles en XP 2000 comentó que hay poco espacio ahora para el maestro solitario. Colaboración y enseñanza son las claves del éxito.</p><p>En una cena en una conferencia, Dave y yo hablábamos con un oponente a la XP. Conforme discutíamos lo que hacíamos, las similaridades de nuestro enfoque eran marcadas. Todos nosotros gustábamos del desarrollo adaptativo e iterativo. Las pruebas eran importantes. Así que nos tenía perplejos su oposición. Entonces vino esta declaración en la línea de “lo último que quiero es que mis programadores refactoren y manoseen el diseño”. Ahora todo estaba claro. La laguna conceptual me la explicó Dave “si él no confía en sus programadores ¿por qué los contrata?”. En XP la cosa más importante que puede hacer el desarrollador experimentado es pasar cuantas habilidades pueda a los desarrolladores junior. En lugar de un arquitecto que toma todas las decisiones importantes, tienes un coach que enseña a los desarrolladores a tomar decisiones importantes. Como Ward Cunningham señaló, así él amplía sus habilidades y añade más a un proyecto de lo que cualquier héroe solitario podría.</p><h2 id="Reversibilidad"><a href="#Reversibilidad" class="headerlink" title="Reversibilidad"></a>Reversibilidad</h2><p>En la XP 2000 Enrico Zaninotto dió una plática fascinante en la que discutió la relación entre los métodos ágiles y la manufactura moderna. Según él, uno de los aspectos clave de ambos enfoques es que atajan la complejidad al reducir la irreversiblidad del proceso.</p><p>Desde esta vista una de las principales fuentes de complejidad es la irreversibilidad de las decisiones. Si puedes cambiar tus decisiones, no es tan importante que sean correctas - lo que hace tu vida mucho más sencilla. </p><p>La consecuencia para el diseño evolutivo es que los diseñadores deben pensar en cómo evitar la irreversibilidad en sus decisiones. Más que tratar de tomar la decisión correcta ahora, busca una manera de posponerla (hasta que tengas más información) o toma la decisión de tal modo que seas capaz de revertirla después sin demasiada dificultad.</p><p>Esta determinación de mantener la reversibilidad es una de las razones de que los métodos ágiles pongan tanto énfasis en sistemas de control de código fuente y de ponerlo todo en esos sistemas. Mientras que esto no garantiza la reversibilidad, particularmente para decisiones de vida larga, proporciona un fundamento que da confianza al equipo, aun si rara vez se usa.</p><p>Diseñar para la irreversibilidad también implica un proceso que hace que los errores se muestren pronto. Uno de los valores del desarrollo iterativo es que las iteraciones rápidas permiten a los clientes ver el sistema conforme crece, y si se comete un error en los requerimientos, puede ser localizado y corregido antes de que el costo de la corrección sea prohibitivo. Esta misma localización rápida es importante para el diseño. Esto significa que tienes que poner las cosas de modo que las áreas potencialmente problemáticas sean rápidamente verificadas para ver qué problema sale. También significa que hay que hacer experimentos para ver qué tan difíciles pueden ser los cambios futuros, aun si no haces el cambio ahora - efectivamente desechando un prototipo de una rama del sistema. Varios equipos han reportado tratar un cambio futuro en modo prototipo temprano para ver qué tan difícil sería.</p><h2 id="El-Deseo-de-Disenar"><a href="#El-Deseo-de-Disenar" class="headerlink" title="El Deseo de Diseñar"></a>El Deseo de Diseñar</h2><p>Aunque me he concentrado mucho en las prácticas técnicas en este artículo, una cosa que es muy fácil de pasar por alto es el aspecto humano.</p><p>Para funcionar, el diseño evolutivo necesita una fuerza que lo lleve a converger. Esta fuerza sólo puede venir de la gente -alguien en el equipo tiene que tener la deteminación para asegurar que la calidad del diseño permanezca alta.</p><p>Este deseo no tiene que venir de todos (aunque es bueno si así pasa), usualmente sólo una o dos personas en el equipo toman la responsabilidad de mantener el diseño íntegro. Esta es una de las tareas que usualmente caen bajo el término ‘arquitecto’.</p><p>Esta responsabilidad significa vigilar el código base, por si cualquier área del mismo se está enredando, y entonces actuar de inmediato para corregir el problema antes de que se salga de control. El encargado del diseño no tiene que ser el mismo que lo arregla - pero tiene que asegurarse de que alguien lo arregle.</p><p>La falta del deseo de diseñar parece ser una razón importante por la que el diseño evolutivo falla. Aun si la gente está familiarizada con las cosas de las que he hablado en este artículo, sin ese deseo no habrá diseño.</p><h2 id="Cosas-que-son-dificiles-de-refactorar"><a href="#Cosas-que-son-dificiles-de-refactorar" class="headerlink" title="Cosas que son difíciles de refactorar"></a>Cosas que son difíciles de refactorar</h2><p>¿Podemos usar la refactorización para tratar todas las decisiones de diseño, o hay algunos asuntos tan diseminosos que son difíciles de añadir después? Actualmente, la XP ortodoxa dice que todas las cosas son fáciles de añadir cuando las necesitas, así que YAGNI siempre se aplica. Me pregunto si hay excepciones. Un buen ejemplo de algo que es controversial de añadir es la internacionalización. ¿Cuesta tanto añadirla después que deberías empezar con ella desde un principio?</p><p>Podría fácilmente imaginar que hay algunas cosas que caerían en esta categoría. Sin embargo la realidad es que aún tenemos muy pocos datos. Si tienes algo que añadir más tarde, como internacionalización, eres muy consciente del esfuerzo que tomará hacerlo. Eres menos consciente del esfuerzo que realmente habría tomado, semana tras semana, ponerlo y mantenerlo antes de que fuera necesario. También estás menos consciente del hecho de que bien podrías haberlo puesto mal, y así de todos modos tendrías que hacer algo de refactorización.</p><p>Parte de la justificación del YAGNI es que muchas de estas necesidades potenciales terminan no siendo necesarias, o al menos no en el modo que esperabas. El esfuerzo que ahorras no haciendo ninguna de ellas es menor al esfuerzo requerido para refactorizar las que realmente necesitas.</p><p>Otra cuestión a tener en cuenta es si realmente sabes cómo hacerlo. Si has hecho internacionalización varias veces, sabes los patrones que necesitas emplear. Como tal es más probable que lo hagas bien. Añadir estructuras anticipatorias es probablemente mejor si estás en esa posición, que si eres nuevo en el problema. Mi consejo sería que si sabes cómo hacerlo, estás en la posición de juzgar el costo de hacerlo o no hacerlo después. No obstante si no lo has hecho antes, no sólo no eres capaz de calcular el costo lo suficientemente bien, es menos probable que lo hagas bien. En ese caso deberías dejarlo para después. Si lo añades entonces, y lo encuentras doloroso, probablemente aún así estarás mejor de lo que estarías si lo hubieras instalado antes. Tu equipo es más experimentado, conoces mejor el dominio y entiendes mejor los requerimientos. A menudo en esta posición ves lo fácil que hubiera sido con una retrospectiva 20&#x2F;20. Añadirlo antes puede ser mucho más difícil de lo que crees.</p><p>Esto trae a colación la cuestión del orden de las historias. En Planning XP, Kent y yo abiertamente manifestamos nuestro desacuerdo. Kent está a favor de dejar que los valores de negocio sean el único factor de orden de las historias. Después de un desacuerdo inicial, Ron Jeffries ahora coincide. Yo todavía no estoy seguro. Yo creo que hay un balance entre valores de negocio y riesgo técnico. Esto me llevaría a proveer al menos algo de internacionalización pronto para mitigar este riesgo. No obstante esto sólo es cierto si la internacionalización fuera necesaria para la primera entrega. Llegar a la entrega tan rápido como sea posible es vitalmente importante. Cualquier complejidad adicional debe hacerse después de la primera entrega si no se necesita para la primera entrega. El poder del código empacado y funcionando es enorme. Esto enfoca la atención del cliente, aumenta la credibilidad y es una fuente masiva de aprendizaje. Haz todo lo que puedas para adelantar esa fecha. Aún si es más esfuerzo añadir algo después de la primera entrega, es mejor entregar antes.</p><h2 id="¿Esta-ocurriendo-el-diseno"><a href="#¿Esta-ocurriendo-el-diseno" class="headerlink" title="¿Está ocurriendo el diseño?"></a>¿Está ocurriendo el diseño?</h2><p>Una de las dificultades del diseño evolutivo es que es muy difícil decir si el diseño está realmente ocurriendo. El peligro de entremezclar diseño con programación es que puede haber programación sin diseño - esta es la situación donde el Diseño Evolutivo diverge y falla.</p><p>Si estás en el equipo de desarrollo, entonces sabes si el diseño está ocurriendo por la calidad del código base. Si el código base se vuelve más complejo y difícil de trabajar, no se está haciendo suficiente diseño. Pero este es tristemente un punto de vista subjetivo. No tenemos métricas confiables que nos permitan medir objetivamente la calidad del diseño.</p><p>Si esta falta de visibilidad es dura para personas técnicas, es más alarmante para miembros del equipo no técnicos. Si usted es un gerente o cliente ¿cómo puede decir si el software está bien diseñado? A usted le interesa porque un software pobremente diseñado será más caro de modificar en el futuro. No hay una respuesta fácil para esto, pero aquí van unas pocas sugerencias:</p><ul><li>Escuche a la gente técnica. Si se quejan de la dificultad de hacer cambios, tome esas quejas seriamente y deles tiempo de arreglar las cosas.</li><li>Vigile cuanto código se desecha. Un proyecto que hace refactorización saludable estará constantemente eliminando código malo. Si no se elimina nada, entonces es casi seguro que no se está refactorizando lo suficiente - lo cual llevará a la degradación del diseño. Sin embargo, como cualquier métrica esta puede ser abusada, la opinión de gente técnica buena, por subjetiva que sea, triunfa sobre cualquier métrica.</li></ul><h2 id="¿Asi-que-ha-muerto-el-diseno"><a href="#¿Asi-que-ha-muerto-el-diseno" class="headerlink" title="¿Así que ha muerto el diseño?"></a>¿Así que ha muerto el diseño?</h2><p>De ninguna manera, pero la naturaleza del diseño ha cambiado. El diseño XP busca las siguientes habilidades:</p><ul><li>Un deseo constante de mantener el código tan claro y simple como sea posible. Habilidades de refactorización, de modo que puedas confiadamente hacer mejoras cuando veas la necesidad.</li><li>Un buen conocimiento de patrones: no sólo las soluciones sino también apreciar cuando usarlos y cuando evolucionar hacia ellos.</li><li>Saber cómo comunicar el diseño a la gente que necesita entenderlo, usando código, diagramas y sobre todo conversación.</li></ul><p>Esta es una selección pusilánime de habilidades, pero siempre ha sido difícil ser un buen diseñador. La XP no lo hace realmente más fácil, al menos para mí. Pero creo que la XP nos da una nueva forma de pensar acerca del diseño efectivo porque ha hecho el diseño evolutivo una estrategia plausible otra vez. Y yo soy un gran fan de la evolución -¿de otro modo quién sabe qué podría ser yo?</p><h2 id="Reconocimientos"><a href="#Reconocimientos" class="headerlink" title="Reconocimientos"></a>Reconocimientos</h2><p>En los últimos años he recogido y robado muchas buenas ideas de mucha buena gente. La mayoría de ellas están perdidas en la turbiedad de mi memoria. Pero recuerdo haber pinchado buenas ideas de Joshua Kerievski. También recuerdo muchos comentarios útiles de Fred George y Ron Jeffries. Tampoco puedo olvidar cuantas buenas ideas siguen viniendo de Ward y Kent.</p><p>Siempre estoy agradecido de todos aquellos que hacen preguntas y señalan errores de tecleo. Me ha dado flojera mantener una lista de estos a reconocer, pero incluyen a Craig Jones, Nigel Thorne, Sven Gorts, Hilary Nelson, Terry Camerlengo.</p><h2 id="Revision"><a href="#Revision" class="headerlink" title="Revisión"></a>Revisión</h2><p>He aquí una lista de las principales actualizaciones de este artículo</p><ul><li>Mayo 2004: Se añadieron las secciones ‘Reversibilidad’, ‘El Deseo de Diseñar’ y ‘¿Está Ocurriendo el Diseño?’.</li><li>Febrero 2001: Articulo actualizado con secciones sobre madurando una arquitectura, el rol del arquitecto, y cosas difíciles de refactorizar.</li><li>Julio 2000: Artículo original enviado a XP 2000 y publicado en <a href="http://martinfowler.com/">martinfowler.com</a></li></ul><h3 id="Creditos-de-la-traduccion"><a href="#Creditos-de-la-traduccion" class="headerlink" title="Créditos de la traducción"></a>Créditos de la traducción</h3><p>Traducción: Alejandro Sierra, marzo de 2003, revisada en septiembre de 2004.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Este artículo es sólo un &lt;em&gt;copy&amp;amp;paste&lt;/em&gt; de un viejo articulo de &lt;a href=&quot;http://martinfowler.com/&quot;&gt;Martin Fowler&lt;/a&gt; titulado &lt;a</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    
    <category term="design pattern" scheme="https://blog.pcollaog.cl/tags/design-pattern/"/>
    
    <category term="agile" scheme="https://blog.pcollaog.cl/tags/agile/"/>
    
    <category term="xp" scheme="https://blog.pcollaog.cl/tags/xp/"/>
    
  </entry>
  
  <entry>
    <title>Recuento del 2013</title>
    <link href="https://blog.pcollaog.cl/2014/01/01/recuento-del-2013/"/>
    <id>https://blog.pcollaog.cl/2014/01/01/recuento-del-2013/</id>
    <published>2014-01-01T03:00:00.000Z</published>
    <updated>2025-11-01T19:36:46.062Z</updated>
    
    <content type="html"><![CDATA[<img src="/images/2014/html-end-2013-start-2014.png" class=""><p>El año que recién pasó ha sido uno de los más complicados que me ha tocado en todo ámbito. </p><h1 id="Familia"><a href="#Familia" class="headerlink" title="Familia"></a>Familia</h1><p>A principios de año nos dimos unas merecidas vacaciones en familia con destino <strong>La Serena</strong>, disfrutamos de unos lindos y temperados días. La Javi conoció la piscina y se largo a nadar (con alitas) sola.</p><img src="/images/2014/IMG_20130129_1129474.jpg" class=""><p>Un hecho que nos pilló total y absolutamente de sorpresa fue la muerte de la mamá de la <a href="https://twitter.com/guzyy">@guzyy</a> <em>Maruca</em>, estábamos planificando un viaje para que viniera a conocer a la Valentina cuando naciera en un par de meses más. Fue un mes duro para la familia.</p><p>A mediados de año nuestra segunda hija, <em>Valentina</em> que llegó para revolucionar nuestras vidas. Si no sabe por qué, lea este post <a href="http://blog.pcollaog.cl/2013/07/13/mi-valentina/">Mi valentina</a>. Hemos aprendido (con la <a href="https://twitter.com/guzyy">@guzyy</a> y <a href="https://twitter.com/javicollaov">@javicollaov</a>) a llevar este tema adelante y preparándonos para lo que se nos viene por delante, tratando de anticipar y planificar al corto plazo.<br>Mientras tanto, disfrutar al máximo a nuestra hija Valentina con cada logro, por muy pequeño que sea, desde sonreír hasta tomar algún objeto con su mano o tratar de sentarse sola.</p><img src="/images/2014/DSC06371.jpg" class=""><p>La Javiera por su parte, ha aprendido muchas cosas y le interesan muchas otras que ni si quiera se pueden imaginar, como por ejemplo, los planetas, las estrellas o por qué la sangre es roja o qué son los anticuerpos. Está en la etapa en que todo se transforma en un:</p><blockquote><p>…¿y po qué?</p><footer><strong>@javicollaov</strong></footer></blockquote><p>Ya que la Javi tiene gustos un tanto “científicos”, la lleve a conocer, en un tour de fin de año, <a href="http://www.planetariochile.cl/">El Planetario</a> (que esta de pelos),el Museo Ferroviario de Santiago, <a href="http://www.mnhn.cl/">El Museo Nacional de Historia Natural</a>, el Museo de Ciencia y Tecnología. Aprendió sobre los planetas, estrellas y galaxias, además fuimos a conocer la ballena (que la encontró fome porque eran puros “huesitos”) y fuimos a experimentar con la luz, el sonido y la física.</p><img src="/images/2014/its-science-anchorman.gif" class=""><p>La Javi acompañó a la <a href="https://twitter.com/guzyy">@guzyy</a> durante unos meses en el post-natal ayudando con su propio estilo de hacer las cosas. Aprendió a escuchar música rock y su grupo favorito es “el de los martillos” por <a href="http://es.wikipedia.org/wiki/Pink_Floyd">Pink Floyd</a> y <a href="http://es.wikipedia.org/wiki/The_Wall">The Wall</a>. Fanática de 31 Minutos y no nos perdimos el show que dieron con <a href="http://aplaplac.cl/radio-guaripolo/">Radio Guaripolo</a> donde pudimos disfrutar (yo más que ella seguramente) de <strong>Fredy Turbina</strong> y la canción <a href="spoti.fi/12jM87L">Mi Equilibrio Espiritual</a>.</p><h1 id="El-Trabajo"><a href="#El-Trabajo" class="headerlink" title="El Trabajo"></a>El Trabajo</h1><p>En el trabajo, me tocó compartir con un selecto grupo de <em>egipcios</em> a los que estimo mucho, vaya para ellos un abrazo (<a href="https://twitter.com/rodchile">@rodchile</a>, <a href="https://twitter.com/lecaros">@lecaros</a>, <a href="https://twitter.com/solemoris">@solemoris</a>, Camilo no más, la Caroline, Don Richie,el responsivo <a href="https://twitter.com/rosoristico">@rosoristico</a>, <a href="https://twitter.com/perrefe">@perrefe</a>, <a href="https://twitter.com/pabloc6">@pabloc6</a>, ordenados en orden de desaparición XD). Con ellos compartimos la creación de un nuevo producto, compartimos muchas reuniones donde definimos desde nuestro punto de vista, que era lo mejor para dicho producto, desde lo mas geek&#x2F;nerd técnico hasta los colores y estilos del sitio. Vivimos discusiones épicas y desayunos con <em>choriqueques</em>. Lamento personalmente que algunos de ellos ya no estén en nuestro equipo de trabajo, por diversas razones. En este equipo además aprendimos a querer a nuestro amigo <a href="http://hubot.github.com/"><em>hubot</em></a> quien todos los días nos daba ánimos para poder seguir trabajando.</p><h1 id="Palabras-al-cierre"><a href="#Palabras-al-cierre" class="headerlink" title="Palabras al cierre"></a>Palabras al cierre</h1><p>Sin duda me quedaron muchas cosas que nos pasaron este año que no puse aquí, pero no quiero dejar la oportunidad de dar a conocer. </p><p>Fui testigo de matrimonio de <a href="https://twitter.com/rodchile">@rodchile</a> con <a href="https://twitter.com/sarahfriedland">@sarahfriedland</a> y ahora forman una linda y <em>koalesca</em> familia.</p><p>Con la <a href="https://twitter.com/guzyy">@guzyy</a> conocimos la <a href="http://www.fundacionser.cl/">Fundación Ser</a> de la que estamos muy agradecidos, hemos aprendido mucho sobre el mundo de los niños con necesidades especiales. Conocimos otros papás que enfrentan los mismos desafíos que nosotros y con los que hemos podido compartir ideas, consejos y la sonrisa de sus hijos.</p><h1 id="Cosas-irrelevantes-que-solo-a-un-geek-le-importan"><a href="#Cosas-irrelevantes-que-solo-a-un-geek-le-importan" class="headerlink" title="Cosas irrelevantes que sólo a un geek le importan"></a>Cosas irrelevantes que sólo a un geek le importan</h1><p>Si no es un geek, por favor no continúe leyendo, le advierto que no entenderá un carajo de lo que voy a escribir. Ahora bien si lo hace… después no se queje XD</p><ul><li>Comencé a programar en <a href="http://nodejs.org/">node.js</a> y <a href="http://angularjs.org/">angular</a></li><li>Migré mi blog de <a href="http://wordpress.org/">WordPress</a> a <a href="http://octopress.org/">Octopress</a></li><li>Me cambie de shell a zsh + <a href="https://github.com/robbyrussell/oh-my-zsh">oh-my-zsh</a></li><li>Sigo odiando las bases de dato (ahora mas que nunca)</li><li>Me gustan cada día más <strong>noSQL</strong> (<a href="http://www.mongodb.org/">mongoDB</a> y <a href="http://redis.io/">redis</a>)</li><li>Confirmo que sigo odiando ruby y sus derivados (aunque los uso y les he dado varias oportunidades)</li><li>Comencé a usar intensivamente <a href="http://www.sublimetext.com/">Sublime Text</a> (hasta he escrito plugins) y pague por su licencia… <em>kudos para ellos!</em></li><li>Las nuevas APIs de Spring Framework singuen sorprendiéndome, especialmente <a href="http://projects.spring.io/spring-data/">Spring Data</a>, <a href="http://projects.spring.io/spring-boot/">Spring Boot</a> y <a href="http://projects.spring.io/spring-xd/">Spring XD</a>.</li><li>Entendí la mitad de <a href="http://projects.spring.io/spring-security/">Spring Security</a> tratando de implementar algo que no estaba soportado en la API.</li><li><a href="http://maven.apache.org/">Maven</a> es mi copiloto</li><li>Si se trata de optimizar aplicaciones Java aún no alcanzo el nivel <em>Dios del 1800 %</em> (#elquesaesae)</li><li>Tengo un cluster de <a href="http://www.raspberrypi.org/">Raspberry Pi</a> para aplicaciones web y una la uso para mediacenter con <a href="http://www.xbian.org/">Xbian</a> (xbmc)</li><li>Use por primera vez <a href="http://nginx.org/">nginx</a> para servir mi blog y estoy pensando seriamente en migrar de <a href="http://httpd.apache.org/">apache2</a>.</li><li><a href="http://www.open-iscsi.org/">open-iscsi</a> realmente la llea!</li><li>Volví a instalar <a href="http://www.cyanogenmod.org/">cyanogenmod</a> y como siempre en la versión inestable.</li><li>Le tomé cariño a Jira y Confluence. (aunque sean propietarios)</li><li>Un <strong>hubot</strong> bien configurado es la mano para insultos motivacionales.</li></ul><p>Que tengan todos un <strong>Feliz Año 2014</strong> y a echarle pa adelante (que pa atrás no cunde).</p>]]></content>
    
    
      
      
    <summary type="html">&lt;img src=&quot;/images/2014/html-end-2013-start-2014.png&quot; class=&quot;&quot;&gt;

&lt;p&gt;El año que recién pasó ha sido uno de los más complicados que me ha tocad</summary>
      
    
    
    
    <category term="Personal" scheme="https://blog.pcollaog.cl/categories/Personal/"/>
    
    
    <category term="trabajo" scheme="https://blog.pcollaog.cl/tags/trabajo/"/>
    
    <category term="nodejs" scheme="https://blog.pcollaog.cl/tags/nodejs/"/>
    
    <category term="recuento" scheme="https://blog.pcollaog.cl/tags/recuento/"/>
    
    <category term="2013" scheme="https://blog.pcollaog.cl/tags/2013/"/>
    
  </entry>
  
  <entry>
    <title>TodoList Con Node.js Y MongoDB - Parte II</title>
    <link href="https://blog.pcollaog.cl/2013/12/23/nodejs-plus-mongoose-plus-express-plus-angular-parte-II/"/>
    <id>https://blog.pcollaog.cl/2013/12/23/nodejs-plus-mongoose-plus-express-plus-angular-parte-II/</id>
    <published>2013-12-23T03:00:00.000Z</published>
    <updated>2025-11-01T19:36:46.062Z</updated>
    
    <content type="html"><![CDATA[<p>Lo prometido es deuda, aquí vamos con la segunda parte donde integraremos <a href="http://passportjs.org/">Passport</a> para poder validar los request y contronlar sesiones de usuarios.</p><p>Primero debemos agregar los siguientes imports al archivo <strong>app.js</strong> y la estrategia (plugin de autenticación) a utilizar. Además se agregan los archivos <strong>UserModel.js</strong> y <strong>security.js</strong> extensión del modelo de User y métodos de validación del request respectivamente:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> passport = <span class="built_in">require</span>(<span class="string">&#x27;passport&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> <span class="title class_">LocalStrategy</span> = <span class="built_in">require</span>(<span class="string">&#x27;passport-local&#x27;</span>).<span class="property">Strategy</span>;</span><br><span class="line"><span class="keyword">var</span> security = <span class="built_in">require</span>(<span class="string">&#x27;./config/security&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> <span class="title class_">User</span> = <span class="built_in">require</span>(<span class="string">&#x27;./model/UserModel&#x27;</span>);</span><br></pre></td></tr></table></figure><p>Ahora configuramos <a href="http://expressjs.com/">Express</a> para que pueda utilizar <a href="http://passportjs.org/">Passport</a> como administrador de sesiones de usuario. Es necesario que express use su propio administrador de sesiones y además debe ser inicializado antes que el de passport.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">cookieParser</span>(<span class="string">&#x27;your secret here&#x27;</span>));</span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">session</span>());</span><br><span class="line"></span><br><span class="line"><span class="comment">// passport initialize</span></span><br><span class="line">app.<span class="title function_">use</span>(passport.<span class="title function_">initialize</span>());</span><br><span class="line">app.<span class="title function_">use</span>(passport.<span class="title function_">session</span>());</span><br></pre></td></tr></table></figure><p>Luego agregamos mecanismos de autenticación, serialización y deserialización a passport:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">passport.<span class="title function_">use</span>(<span class="keyword">new</span> <span class="title class_">LocalStrategy</span>(<span class="title class_">User</span>.<span class="title function_">authenticate</span>()));</span><br><span class="line">passport.<span class="title function_">serializeUser</span>(<span class="title class_">User</span>.<span class="title function_">serializeUser</span>());</span><br><span class="line">passport.<span class="title function_">deserializeUser</span>(<span class="title class_">User</span>.<span class="title function_">deserializeUser</span>());</span><br></pre></td></tr></table></figure><h2 id="Model"><a href="#Model" class="headerlink" title="Model"></a>Model</h2><p>Ahora extendemos el modelo de usuario para agregar nuestros atributos (si es es necesario, por ahora lo dejaremos vacío):</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> mongoose = <span class="built_in">require</span>(<span class="string">&#x27;mongoose&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> passportLocalMongoose = <span class="built_in">require</span>(<span class="string">&#x27;passport-local-mongoose&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> <span class="title class_">UserSchema</span> = <span class="keyword">new</span> mongoose.<span class="title class_">Schema</span>(&#123;&#125;);</span><br><span class="line"></span><br><span class="line"><span class="title class_">UserSchema</span>.<span class="title function_">plugin</span>(passportLocalMongoose);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> <span class="title class_">UserModel</span> = mongoose.<span class="title function_">model</span>(<span class="string">&#x27;User&#x27;</span>, <span class="title class_">UserSchema</span>);</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="title class_">UserModel</span>;</span><br></pre></td></tr></table></figure><h2 id="Seguridad"><a href="#Seguridad" class="headerlink" title="Seguridad"></a>Seguridad</h2><p>Hay un archivo que se llama <strong>security.js</strong> que contiene una función que valida si el <em>request</em> solicitado está autenticado por <em>passport</em>, si está autenticado lo “deja pasar” (next), de lo contrario lo redirecciona al template de <em>login</em>.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">exports</span>.<span class="property">ensureAuthenticated</span> = <span class="keyword">function</span> <span class="title function_">ensureAuthenticated</span>(<span class="params">req, res, next</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (req.<span class="title function_">isAuthenticated</span>()) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">next</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    res.<span class="title function_">redirect</span>(<span class="string">&#x27;/login&#x27;</span>);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Nos queda asegurar las <em>urls</em> o recursos que necesitemos con la función <em>ensureAuthenticated</em> en el archivo <strong>app.js</strong>. La idea es que sea lo menos intrusivo posible. Hay dos formas de hacerlo, la primera es intrusiva (y no recomendada aunque puede utilizarse con fines específicos) y se debe realizar por cada request en los archivos que contienen los <em>Controllers</em>:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">exports</span>.<span class="property">authenticationExample</span> = <span class="keyword">function</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (req.<span class="title function_">isAuthenticated</span>()) &#123;</span><br><span class="line">        <span class="comment">// Do something</span></span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        res.<span class="title function_">redirect</span>(<span class="string">&#x27;/login&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>La segunda es interceptando los request y validando según algún patrón, que es nuestro caso. Esta configuración esta en <strong>app.js</strong> donde se declaran las rutas a los Controllers:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">all</span>(<span class="string">&#x27;/api/*&#x27;</span>, security.<span class="property">ensureAuthenticated</span>);</span><br><span class="line">app.<span class="title function_">all</span>(<span class="string">&#x27;/todos&#x27;</span>, security.<span class="property">ensureAuthenticated</span>);</span><br></pre></td></tr></table></figure><p>Con esto interceptamos todos los request que van a la API y los que van a <strong>&#x2F;todos</strong> y los hacemos pasar por la función de autenticación de request. Con esto evitamos poner dichas líneas de autenticación en cada controller.</p><h1 id="Login-y-Logout"><a href="#Login-y-Logout" class="headerlink" title="Login y Logout"></a>Login y Logout</h1><p>Finalmente nos queda la última parte respecto de la autenticación y es configurar el <strong>login</strong> y el <strong>logout</strong>. Para el <strong>login</strong> usamos la API de passport y delegamos el trabajo de autenticación de la siguiente forma (configuración):</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Funcion sin autenticación que permite desplegar el template de Login</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/login&#x27;</span>, <span class="keyword">function</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">    res.<span class="title function_">render</span>(<span class="string">&#x27;login&#x27;</span>, &#123;&#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Función de login que permite delegar la autenticacion en la API de</span></span><br><span class="line"><span class="comment"> *  passport, se configura además cuando la autenticación es exitosa a que url </span></span><br><span class="line"><span class="comment"> *  lo debe redireccinar y lo mismo en caso de error.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/login&#x27;</span>, passport.<span class="title function_">authenticate</span>(<span class="string">&#x27;local&#x27;</span>, &#123;</span><br><span class="line">    <span class="attr">successRedirect</span>: <span class="string">&#x27;/todos&#x27;</span>,</span><br><span class="line">    <span class="attr">failureRedirect</span>: <span class="string">&#x27;/login&#x27;</span></span><br><span class="line">&#125;));</span><br></pre></td></tr></table></figure><p>El <strong>logout</strong> es más sencillo y lo único que hay que hacer es invalidar el request, destruir la sesión del usuario y redireccionar al <strong>login</strong>.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/logout&#x27;</span>, <span class="keyword">function</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">    req.<span class="title function_">logout</span>();</span><br><span class="line">    res.<span class="title function_">redirect</span>(<span class="string">&#x27;/login&#x27;</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>Me queda pendiente en la próxima parte del tutorial explicar cómo consumir estos servicios usando angular y desplegar los templates.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Lo prometido es deuda, aquí vamos con la segunda parte donde integraremos &lt;a href=&quot;http://passportjs.org/&quot;&gt;Passport&lt;/a&gt; para poder valida</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    <category term="JavaScript" scheme="https://blog.pcollaog.cl/categories/Programming/JavaScript/"/>
    
    
    <category term="javascript" scheme="https://blog.pcollaog.cl/tags/javascript/"/>
    
    <category term="nodejs" scheme="https://blog.pcollaog.cl/tags/nodejs/"/>
    
    <category term="expressjs" scheme="https://blog.pcollaog.cl/tags/expressjs/"/>
    
    <category term="mongoose" scheme="https://blog.pcollaog.cl/tags/mongoose/"/>
    
    <category term="angular" scheme="https://blog.pcollaog.cl/tags/angular/"/>
    
    <category term="passportjs" scheme="https://blog.pcollaog.cl/tags/passportjs/"/>
    
    <category term="ejs" scheme="https://blog.pcollaog.cl/tags/ejs/"/>
    
  </entry>
  
  <entry>
    <title>TodoList con Node.js y MongoDB - Parte I</title>
    <link href="https://blog.pcollaog.cl/2013/12/01/nodejs-plus-mongoose-plus-express-plus-angular/"/>
    <id>https://blog.pcollaog.cl/2013/12/01/nodejs-plus-mongoose-plus-express-plus-angular/</id>
    <published>2013-12-01T03:00:00.000Z</published>
    <updated>2025-11-01T19:36:46.062Z</updated>
    
    <content type="html"><![CDATA[<p>Llevo un tiempo estudiando y haciendo algunas cosas con <a href="http://nodejs.org/">Node.js</a> y me he llevado una grata impresión con esta plataforma. Al principio cuesta un poco entender el cómo funciona ya que el paradigma es muy distinto del que he venido usando durante este último tiempo.</p><p>Me animé y empece a usar Node.js para hacer algo simple y así tratar de entender el cómo funciona. Para hacer algo mas sabrosa la experiencia agregué algunos ingredientes adicionales, un framework para desarrollo web llamado <a href="http://expressjs.com/">Express</a>, <a href="http://mongoosejs.com/">Mongoose</a> para modelar los documentos que van a ir a parar a MongoDB, <a href="http://passportjs.org/">Passport</a> para autenticar los request (control de usuarios y permisos), uso de templates con <a href="http://embeddedjs.com/">EJS</a> y finalmente para la vista usamos el framework <a href="http://angularjs.org/">AngularJS</a>. Como podrán ver es un stack de tecnologías basadas en Javascript.</p><p>Para iniciar voy a explicar algunas partes del código que personalmente me costó entender e implementar. Algunos de esos puntos fueron la integración con passport para la autenticación de los request, control de usuario y uso de datos en sesión.</p><h1 id="Configuracion-de-node-js"><a href="#Configuracion-de-node-js" class="headerlink" title="Configuración de node.js"></a>Configuración de node.js</h1><p>Cuando utilizamos nodejs siempre hay un archivo principal donde se configura toda la plataforma, en este caso el archivo es llamado <strong>app.js</strong>. Voy a ir mostrando ciertas partes del código (si quieren ver el código, <a href="https://github.com/pcollaog/todo-list-nodejs">esta disponible en github</a>):</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">&#x27;express&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> indexController = <span class="built_in">require</span>(<span class="string">&#x27;./routes/IndexController&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> todosController = <span class="built_in">require</span>(<span class="string">&#x27;./routes/TodosController&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> registerController = <span class="built_in">require</span>(<span class="string">&#x27;./routes/RegisterController&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">&#x27;http&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> app = <span class="title function_">express</span>();</span><br><span class="line"><span class="keyword">var</span> db = <span class="built_in">require</span>(<span class="string">&#x27;./config/database&#x27;</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> passport = <span class="built_in">require</span>(<span class="string">&#x27;passport&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> <span class="title class_">LocalStrategy</span> = <span class="built_in">require</span>(<span class="string">&#x27;passport-local&#x27;</span>).<span class="property">Strategy</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> security = <span class="built_in">require</span>(<span class="string">&#x27;./config/security&#x27;</span>);</span><br><span class="line"><span class="keyword">var</span> <span class="title class_">User</span> = <span class="built_in">require</span>(<span class="string">&#x27;./model/UserModel&#x27;</span>);</span><br></pre></td></tr></table></figure><h1 id="Controllers"><a href="#Controllers" class="headerlink" title="Controllers"></a>Controllers</h1><p>Lo primero es incluir el módulo de <strong>express</strong> y luego los <em>Controllers</em> de la aplicación. Veamos el código de <strong>IndexController</strong></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">exports</span>.<span class="property">index</span> = <span class="keyword">function</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">  res.<span class="title function_">render</span>(<span class="string">&#x27;todos&#x27;</span>, &#123;</span><br><span class="line">    <span class="attr">user</span>: req.<span class="property">user</span></span><br><span class="line">  &#125;);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>Este es el <em>Controller</em> mas simple de la aplicación, lo único que hace es exponer mediante <strong>exports</strong> la función <strong>index</strong> cuya responsabilidad es desplegar la página principal de la aplicación. Lo demás está en el controlador de la API que será llamada desde dicha página (usando ajax).</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> <span class="title class_">Todo</span> = <span class="built_in">require</span>(<span class="string">&#x27;../model/TodosModel&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Busca todos los todos para el usuario registrado</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  &#123;<span class="type">Object</span>&#125; req request</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  &#123;<span class="type">Object</span>&#125; res response</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">findAllTodosByUser</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> userId = req.<span class="property">user</span>.<span class="property">id</span>;</span><br><span class="line"></span><br><span class="line">  <span class="title class_">Todo</span>.<span class="title function_">find</span>()</span><br><span class="line">    .<span class="title function_">where</span>(<span class="string">&#x27;creator&#x27;</span>)</span><br><span class="line">    .<span class="title function_">equals</span>(userId)</span><br><span class="line">    .<span class="title function_">sort</span>(<span class="string">&#x27;date&#x27;</span>)</span><br><span class="line">    .<span class="title function_">exec</span>(<span class="keyword">function</span>(<span class="params">err, todos</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (err) &#123;</span><br><span class="line">        res.<span class="title function_">send</span>(err);</span><br><span class="line">      &#125;</span><br><span class="line">      res.<span class="title function_">json</span>(todos);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">exports</span>.<span class="property">allTodos</span> = findAllTodosByUser;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Crea un todo para el usuario</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  &#123;<span class="type">Object</span>&#125; req request</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  &#123;<span class="type">Object</span>&#125; res response</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">Object</span>&#125;     Lista de todos</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="built_in">exports</span>.<span class="property">createTodo</span> = <span class="keyword">function</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> userId = req.<span class="property">user</span>.<span class="property">id</span>;</span><br><span class="line">  <span class="keyword">var</span> textTodo = req.<span class="property">body</span>.<span class="property">text</span>;</span><br><span class="line"></span><br><span class="line">  <span class="title class_">Todo</span>.<span class="title function_">create</span>(&#123;</span><br><span class="line">    <span class="attr">text</span>: textTodo,</span><br><span class="line">    <span class="attr">done</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">creator</span>: userId</span><br><span class="line">  &#125;, <span class="keyword">function</span>(<span class="params">error, todo</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (error) &#123;</span><br><span class="line">      res.<span class="title function_">send</span>(error);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">findAllTodosByUser</span>(req, res);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Elimina un Todo por su ID</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  &#123;<span class="type">Object</span>&#125; req request</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  &#123;<span class="type">Object</span>&#125; res response</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="type">Object</span>&#125;     Lista de todos</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="built_in">exports</span>.<span class="property">deleteTodo</span> = <span class="keyword">function</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">  <span class="title class_">Todo</span>.<span class="title function_">remove</span>(&#123;</span><br><span class="line">    <span class="attr">_id</span>: req.<span class="property">params</span>.<span class="property">todo_id</span></span><br><span class="line">  &#125;, <span class="keyword">function</span>(<span class="params">error, todo</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (error) &#123;</span><br><span class="line">      res.<span class="title function_">send</span>(error);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">findAllTodosByUser</span>(req, res);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Este controlador expone la API REST con la que se comunicará la pagina principal, haciendo llamadas <em>ajax</em> a los distintos métodos. En esta pieza se hace un <em>require</em> de otro script que representa el <strong>Model</strong>, en este caso es un <em>document</em> para <strong>MongoDB</strong>.</p><h1 id="Model-con-mongoose"><a href="#Model-con-mongoose" class="headerlink" title="Model con mongoose"></a>Model con mongoose</h1><p>Aquí mostraré como se modeló el documento principal de la aplicación <strong>Todo</strong></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> mongoose = <span class="built_in">require</span>(<span class="string">&#x27;mongoose&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> <span class="title class_">TodoSchema</span> = <span class="keyword">new</span> mongoose.<span class="title class_">Schema</span>(&#123;</span><br><span class="line">    <span class="attr">text</span>: <span class="title class_">String</span>,</span><br><span class="line">    <span class="attr">date</span>: &#123;</span><br><span class="line">        <span class="attr">type</span>: <span class="title class_">Date</span>,</span><br><span class="line">        <span class="attr">default</span>: <span class="title class_">Date</span>.<span class="property">now</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">done</span>: &#123;</span><br><span class="line">        <span class="attr">type</span>: <span class="title class_">Boolean</span>,</span><br><span class="line">        <span class="attr">default</span>: <span class="literal">false</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">creator</span>: &#123;</span><br><span class="line">        <span class="attr">type</span>: mongoose.<span class="property">Schema</span>.<span class="property">Types</span>.<span class="property">ObjectId</span>,</span><br><span class="line">        <span class="attr">ref</span>: <span class="string">&#x27;User&#x27;</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> <span class="title class_">TodoModel</span> = mongoose.<span class="title function_">model</span>(<span class="string">&#x27;Todo&#x27;</span>, <span class="title class_">TodoSchema</span>);</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="title class_">TodoModel</span>;</span><br></pre></td></tr></table></figure><p>Primero se incluye el módulo de <strong>mongoose</strong> que nos permitirá modelar los documentos para MongoDB. Luego se crea un <strong>schema</strong> para modelar y se le agregan los atributos que va a poseer y sus respectivas validaciones. Por ejemplo, el atributo <em>date</em> es de tipo <strong>Date</strong> y valor por omisión la fecha de hoy.</p><p>Además este <strong>schema</strong> contiene una referencia a otra <strong>Collection</strong> para dejar relacionado el usuario creador en sus Todos.</p><h1 id="Route-y-manejo-de-URLs"><a href="#Route-y-manejo-de-URLs" class="headerlink" title="Route y manejo de URLs"></a>Route y manejo de URLs</h1><p>Finalmente para que la aplicación funcioné, hay que indicarle a node.js que las urls que se soliciten hay que enviarlas a alguien que las atienda, en este caso, los controladores y sus funciones.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/login&#x27;</span>, <span class="keyword">function</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">  res.<span class="title function_">render</span>(<span class="string">&#x27;login&#x27;</span>, &#123;&#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/login&#x27;</span>, passport.<span class="title function_">authenticate</span>(<span class="string">&#x27;local&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">successRedirect</span>: <span class="string">&#x27;/todos&#x27;</span>,</span><br><span class="line">  <span class="attr">failureRedirect</span>: <span class="string">&#x27;/login&#x27;</span></span><br><span class="line">&#125;));</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/logout&#x27;</span>, <span class="keyword">function</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">  req.<span class="title function_">logout</span>();</span><br><span class="line">  res.<span class="title function_">redirect</span>(<span class="string">&#x27;/login&#x27;</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/&#x27;</span>, <span class="keyword">function</span>(<span class="params">req, res</span>) &#123;</span><br><span class="line">  res.<span class="title function_">redirect</span>(<span class="string">&#x27;/login&#x27;</span>)</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/register&#x27;</span>, registerController.<span class="property">index</span>);</span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/register&#x27;</span>, registerController.<span class="property">registerUser</span>);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">all</span>(<span class="string">&#x27;/api/*&#x27;</span>, security.<span class="property">ensureAuthenticated</span>);</span><br><span class="line">app.<span class="title function_">all</span>(<span class="string">&#x27;/todos&#x27;</span>, security.<span class="property">ensureAuthenticated</span>);</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/todos&#x27;</span>, indexController.<span class="property">index</span>);</span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">&#x27;/api/todos&#x27;</span>, todosController.<span class="property">allTodos</span>);</span><br><span class="line">app.<span class="title function_">post</span>(<span class="string">&#x27;/api/todos&#x27;</span>, todosController.<span class="property">createTodo</span>);</span><br><span class="line">app.<span class="title function_">delete</span>(<span class="string">&#x27;/api/todos/:todo_id&#x27;</span>, todosController.<span class="property">deleteTodo</span>);</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>No hay mucho que explicar, <em>a buen programador pocas lineas de código</em>, las urls que ahi aparecen son <em>ruteadas</em> a los controladores o se implementa el <em>callback inline</em>, como por ejemplo las urls de <strong>login</strong> y <strong>logout</strong>. Los controller que digan <em>security</em> o <em>passport</em>, serán materia del próximo post.</p><p>Quedan algunos temas sin tocar en este capítulo, falta que revisemos la integración con <strong>AngularJS</strong>, el despliegue de los templates con <strong>EJS</strong> y la integración con <strong>passport</strong> para autenticar y autorizar los request.</p><p>Si tienen preguntas, bienvenidas sean.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Llevo un tiempo estudiando y haciendo algunas cosas con &lt;a href=&quot;http://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; y me he llevado una grata impresión con </summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    <category term="JavaScript" scheme="https://blog.pcollaog.cl/categories/Programming/JavaScript/"/>
    
    
    <category term="javascript" scheme="https://blog.pcollaog.cl/tags/javascript/"/>
    
    <category term="nodejs" scheme="https://blog.pcollaog.cl/tags/nodejs/"/>
    
    <category term="expressjs" scheme="https://blog.pcollaog.cl/tags/expressjs/"/>
    
    <category term="mongoose" scheme="https://blog.pcollaog.cl/tags/mongoose/"/>
    
    <category term="angular" scheme="https://blog.pcollaog.cl/tags/angular/"/>
    
    <category term="passportjs" scheme="https://blog.pcollaog.cl/tags/passportjs/"/>
    
    <category term="ejs" scheme="https://blog.pcollaog.cl/tags/ejs/"/>
    
  </entry>
  
  <entry>
    <title>Instalación de Node.js con NVM</title>
    <link href="https://blog.pcollaog.cl/2013/11/26/instalacion-de-nodejs-con-nvm/"/>
    <id>https://blog.pcollaog.cl/2013/11/26/instalacion-de-nodejs-con-nvm/</id>
    <published>2013-11-26T03:00:00.000Z</published>
    <updated>2025-11-01T19:36:46.062Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Instalar-NVM"><a href="#Instalar-NVM" class="headerlink" title="Instalar NVM"></a>Instalar NVM</h1><p>Primero instalaremos las herramientas que nos permitan administrar distintas versiones de nodejs. Una muy buena alternativa es instalar <a href="https://github.com/creationix/nvm">nvm</a> (node version manager) algo siminar a <a href="https://rvm.io/">rvm</a> (ruby version manager).</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ curl https://raw.github.com/creationix/nvm/master/install.sh | sh</span><br></pre></td></tr></table></figure><p>Este script instala nvm en el directorio <strong>$HOME&#x2F;.nvm</strong> , luego se deben asegurar que los scripts de <strong>nvm</strong> se inicien con el terminal o shell que usen. En mi caso uso <strong>zsh</strong> y debo agregar la siguiente linea al final del archivo <strong>.zshrc</strong> (si usas bash debes agregarla en el archivo <strong>.bashrc</strong>):</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[[ -s <span class="variable">$HOME</span>/.nvm/nvm.sh ]] &amp;&amp; . <span class="variable">$HOME</span>/.nvm/nvm.sh <span class="comment"># This loads NVM</span></span><br></pre></td></tr></table></figure><p>Luego reiniciar la consola o cargar tu archivo de inicio:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">source</span> ~/.zshrc </span><br></pre></td></tr></table></figure><p>ó</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">source</span> ~/.bashrc</span><br></pre></td></tr></table></figure><h2 id="Comprobar-la-instalacion-de-nvm"><a href="#Comprobar-la-instalacion-de-nvm" class="headerlink" title="Comprobar la instalación de nvm"></a>Comprobar la instalación de nvm</h2><p>Ejecutamos los siguientes comandos para comprobar que <strong>nvm</strong> funciona correctamente.</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">$ nvm</span><br><span class="line"></span><br><span class="line">Node Version Manager</span><br><span class="line"></span><br><span class="line">Usage:</span><br><span class="line">    nvm help                    Show this message</span><br><span class="line">    nvm install [-s] &lt;version&gt;  Download and install a &lt;version&gt;</span><br><span class="line">    nvm uninstall &lt;version&gt;     Uninstall a version</span><br><span class="line">    nvm use &lt;version&gt;           Modify PATH to use &lt;version&gt;</span><br><span class="line">    nvm run &lt;version&gt; [&lt;args&gt;]  Run &lt;version&gt; with &lt;args&gt; as arguments</span><br><span class="line">    nvm ls                      List installed versions</span><br><span class="line">    nvm ls &lt;version&gt;            List versions matching a given description</span><br><span class="line">    nvm ls-remote               List remote versions available for install</span><br><span class="line">    nvm deactivate              Undo effects of NVM on current shell</span><br><span class="line">    nvm alias [&lt;pattern&gt;]       Show all aliases beginning with &lt;pattern&gt;</span><br><span class="line">    nvm alias &lt;name&gt; &lt;version&gt;  Set an alias named &lt;name&gt; pointing to &lt;version&gt;</span><br><span class="line">    nvm unalias &lt;name&gt;          Deletes the alias named &lt;name&gt;</span><br><span class="line">    nvm copy-packages &lt;version&gt; Install global NPM packages contained in &lt;version&gt; to current version</span><br><span class="line"></span><br><span class="line">Example:</span><br><span class="line">    nvm install v0.4.12         Install a specific version number</span><br><span class="line">    nvm use 0.2                 Use the latest available 0.2.x release</span><br><span class="line">    nvm run 0.4.12 myApp.js     Run myApp.js using node v0.4.12</span><br><span class="line">    nvm alias default 0.4       Auto use the latest installed v0.4.x version</span><br></pre></td></tr></table></figure><h1 id="Instalar-node-js"><a href="#Instalar-node-js" class="headerlink" title="Instalar node.js"></a>Instalar node.js</h1><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">$ nvm ls-remote</span><br><span class="line"></span><br><span class="line">v0.11.0</span><br><span class="line">v0.11.1</span><br><span class="line">v0.11.2</span><br><span class="line">v0.11.3</span><br><span class="line">v0.11.4</span><br><span class="line">v0.11.5</span><br><span class="line">v0.11.6</span><br><span class="line">v0.11.7</span><br><span class="line">v0.11.8</span><br><span class="line">v0.11.9</span><br></pre></td></tr></table></figure><p>##Instalar la versión <strong>v0.11.8</strong> de <strong>node.js</strong> </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ nvm install v0.11.8</span><br></pre></td></tr></table></figure><p>##Comprobar la instalación de node.js</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ node --version</span><br><span class="line"></span><br><span class="line">v0.11.8</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Instalar-NVM&quot;&gt;&lt;a href=&quot;#Instalar-NVM&quot; class=&quot;headerlink&quot; title=&quot;Instalar NVM&quot;&gt;&lt;/a&gt;Instalar NVM&lt;/h1&gt;&lt;p&gt;Primero instalaremos las herra</summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    
    <category term="javascript" scheme="https://blog.pcollaog.cl/tags/javascript/"/>
    
    <category term="nodejs" scheme="https://blog.pcollaog.cl/tags/nodejs/"/>
    
    <category term="nvm" scheme="https://blog.pcollaog.cl/tags/nvm/"/>
    
  </entry>
  
  <entry>
    <title>Deja tu huella en la vida</title>
    <link href="https://blog.pcollaog.cl/2013/10/06/deja-tu-huella-en-la-vida/"/>
    <id>https://blog.pcollaog.cl/2013/10/06/deja-tu-huella-en-la-vida/</id>
    <published>2013-10-06T03:00:00.000Z</published>
    <updated>2025-11-01T19:36:46.061Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Siembra-ensenanza…-cosecha-Inclusion"><a href="#Siembra-ensenanza…-cosecha-Inclusion" class="headerlink" title="Siembra enseñanza… cosecha Inclusión"></a>Siembra enseñanza… cosecha Inclusión</h1><p>Este es le mes (Octubre) de la <strong>Concientización del Síndrome de Down</strong>. Esta es una campaña impulsada por <a href="https://www.facebook.com/HappyDownChile">Happy Down Chile</a>.</p><blockquote><p>Happy Down Chile es una red de apoyo, orientación e información para todas aquellas familias que tienen una PERSONA con Síndrome de Down en su núcleo.</p></blockquote><img src="/images/2013/campaing_sindrome_down.png" class=""><p>Apoya la campaña y si quieres… ayuda a <strong>educar</strong> a tus cercanos sobre el <strong>Síndrome de Down</strong>, de ésta forma ayudaremos a que la inclusión de estas <strong>personas</strong> sea mas fácil.</p><p>Les dejo los datos de la campaña para que la sigan en <a href="https://www.facebook.com/HappyDownChile">Facebook</a> y <a href="https://twitter.com/HappyDownChile">Twitter</a></p><img src="/images/2013/campaing_sindrome_down2.png" class="">]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Siembra-ensenanza…-cosecha-Inclusion&quot;&gt;&lt;a href=&quot;#Siembra-ensenanza…-cosecha-Inclusion&quot; class=&quot;headerlink&quot; title=&quot;Siembra enseñanza… c</summary>
      
    
    
    
    <category term="Personal" scheme="https://blog.pcollaog.cl/categories/Personal/"/>
    
    
    <category term="familia" scheme="https://blog.pcollaog.cl/tags/familia/"/>
    
    <category term="síndrome de down" scheme="https://blog.pcollaog.cl/tags/sindrome-de-down/"/>
    
  </entry>
  
  <entry>
    <title>Un Arquitecto de Software</title>
    <link href="https://blog.pcollaog.cl/2013/08/14/un-arquitecto-de-software/"/>
    <id>https://blog.pcollaog.cl/2013/08/14/un-arquitecto-de-software/</id>
    <published>2013-08-14T04:00:00.000Z</published>
    <updated>2025-11-01T19:36:46.061Z</updated>
    
    <content type="html"><![CDATA[<blockquote><ul><li>Un Arquitecto de Software vive para servir al equipo de ingeniería, no al revés.</li><li>Un Arquitecto de Software es un mentor.</li><li>Un Arquitecto de Software es un estudioso.</li><li>Un Arquitecto de Software es como un conserje. Barriendo felizmente después de que la gran fiesta terminó.</li><li>Un Arquitecto de Software ayuda a poner orden donde hay caos, orientación donde hay ambigüedad, y toma decisiones en caso de desacuerdos.</li><li>Un Arquitecto de Software escribe el código de las partes mas preciadas y las entiende hasta la médula.</li><li>Un Arquitecto de Software crea un vocabulario que permite la comunicación eficaz a través de toda la compañía.</li><li>Un Arquitecto de Software lee mucho más código del que escribe, capturando errores antes de que éstos se manifiesten como cambios en el sistema.</li><li>Un Arquitecto de Software proporciona la visión tecnológica y de producto sin perder de vista las necesidades actuales.</li><li>Un Arquitecto de Software admite cuando está equivocado y no alardea cuando esta en lo cierto.</li><li>Un Arquitecto de Software da crédito cuando es debido y se enorgullece por un trabajo bien hecho.</li></ul><footer><strong>Chris Eppstein en Coderwall</strong></footer></blockquote><p>Versión en inglés en <a href="https://coderwall.com/p/lbda2q">Chris Eppstein en Coderwall</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;&lt;ul&gt;
&lt;li&gt;Un Arquitecto de Software vive para servir al equipo de ingeniería, no al revés.&lt;/li&gt;
&lt;li&gt;Un Arquitecto de Software es </summary>
      
    
    
    
    <category term="Programming" scheme="https://blog.pcollaog.cl/categories/Programming/"/>
    
    
    <category term="citas" scheme="https://blog.pcollaog.cl/tags/citas/"/>
    
    <category term="software" scheme="https://blog.pcollaog.cl/tags/software/"/>
    
    <category term="arquitectura" scheme="https://blog.pcollaog.cl/tags/arquitectura/"/>
    
    <category term="architect" scheme="https://blog.pcollaog.cl/tags/architect/"/>
    
    <category term="software development" scheme="https://blog.pcollaog.cl/tags/software-development/"/>
    
    <category term="software architect" scheme="https://blog.pcollaog.cl/tags/software-architect/"/>
    
    <category term="desarrollo de software" scheme="https://blog.pcollaog.cl/tags/desarrollo-de-software/"/>
    
    <category term="developer team" scheme="https://blog.pcollaog.cl/tags/developer-team/"/>
    
  </entry>
  
</feed>
