<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Luis E. Alvarado - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Descubre miles de cursos de programación escritos por expertos. Aprende Desarrollo Web, Ciencia de Datos, DevOps, Seguridad y obtén asesoramiento profesional para desarrolladores. ]]>
        </description>
        <link>https://www.freecodecamp.org/espanol/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Luis E. Alvarado - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 14 May 2026 04:08:40 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/author/luis-e-a/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Node.js Streams: Todo lo que necesitas saber ]]>
                </title>
                <description>
                    <![CDATA[ > Actualización: Este artículo es ahora parte de mi libro "Node.js Beyond The Basics". Lee la versión actualizada de este contenido y más sobre Node en  jscomplete.com/node-beyond-basics [https://github.com/samerbuna/efficient-node]. Los flujos de Node.js (streams)tienen la reputación de ser difíciles de trabajar, y aún más difíciles de entender. Bueno, tengo buenas ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/node-js-streams-todo-lo-que-necesitas-saber/</link>
                <guid isPermaLink="false">63c06ae5700708073437a503</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Luis E. Alvarado ]]>
                </dc:creator>
                <pubDate>Thu, 02 Mar 2023 20:23:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/01/node_js_streams.gif" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/node-js-streams-everything-you-need-to-know-c9141306be93/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Node.js Streams: Everything you need to know</a>
      </p><blockquote>Actualización: Este artículo es ahora parte de mi libro "Node.js Beyond The Basics".<br><br>Lee la versión actualizada de este contenido y más sobre Node en <a href="https://github.com/samerbuna/efficient-node">jscomplete.com/node-beyond-basics</a>.</blockquote><p>Los flujos de Node.js (<em>streams</em>)tienen la reputación de ser difíciles de trabajar, y aún más difíciles de entender. Bueno, tengo buenas noticias para ti - ese ya no es el caso.</p><p>A lo largo de los años, los desarrolladores han creado montones de paquetes con el único propósito de facilitar el trabajo con flujos. Pero en este artículo, voy a centrarme en la API nativa de <a href="https://nodejs.org/api/stream.html">flujos de Node.js</a>.</p><blockquote>“Los flujos son la mejor y más incomprendida idea de Node.”<br><br>— Dominic Tarr</blockquote><h3 id="-qu-son-exactamente-los-flujos">¿Qué son exactamente los flujos?</h3><p>Los flujos son colecciones de datos, como las matrices o las cadenas de texto. La diferencia es que estos pueden no estar disponibles todos a la vez y no tienen por qué caber en la memoria. Esto hace que sean realmente potentes cuando se trabaja con grandes cantidades de datos, o con datos que vienen de una fuente externa de uno en uno.</p><p>Sin embargo, los flujos no sólo sirven para trabajar con grandes cantidades de datos. También nos ofrecen la posibilidad de componer nuestro código. Al igual que podemos componer poderosos comandos de Linux mediante la canalización de otros comandos más pequeños, podemos hacer exactamente lo mismo en Node con los flujos.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*Fp3dyVZckIUjPFOp58x-zQ.png" class="kg-image" alt="1*Fp3dyVZckIUjPFOp58x-zQ" width="800" height="102" loading="lazy"><figcaption>Compatibilidad con comandos Linux</figcaption></figure><pre><code class="language-js">const grep = ... // Un flujo para la salida de grep
const wc = ... // A stream for the wc input

grep.pipe(wc)</code></pre><p>Muchos de los módulos incorporados en Node implementan la interfaz de <em>streaming</em>:</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*lhOvZiDrVbzF8_l8QX3ACw.png" class="kg-image" alt="1*lhOvZiDrVbzF8_l8QX3ACw" width="800" height="473" loading="lazy"></figure><p>La lista anterior tiene algunos ejemplos de objetos nativos de Node.js que también son flujos legibles y escribibles. Algunos de estos objetos son flujos tanto legibles como escribibles, como los <em>sockets</em> TCP, zlib y flujos <em>crypto</em>.</p><p>Observa que los objetos también están estrechamente relacionados. Mientras que una respuesta HTTP es un flujo legible en el cliente, es un flujo escribible en el servidor. Esto se debe a que en el caso HTTP, básicamente leemos de un objeto (<code>http.IncomingMessage</code>) y escribimos en el otro (<code>http.ServerResponse</code>).</p><p>Observe también cómo los flujos <code>stdio</code> ( <code>stdin</code>, <code>stdout</code>, <code>stderr</code>) tienen los tipos de flujo inversos cuando se trata de procesos hijo. Esto permite una manera realmente fácil de canalizar hacia y desde estos flujos desde los flujos <code>stdio</code> del proceso principal.</p><h3 id="un-ejemplo-pr-ctico-de-flujos">Un ejemplo práctico de flujos</h3><p>La teoría está muy bien, pero a menudo no convence al 100%. Veamos un ejemplo que demuestra la diferencia que pueden marcar los flujos en el código en lo que respecta al consumo de memoria.</p><p>Primero vamos a crear un archivo grande:</p><pre><code class="language-js">const fs = require('fs');
const archivo = fs.createWriteStream('./big.file');

for(let i=0; i&lt;= 1e6; i++) {
  file.write('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n');
}

file.end();</code></pre><p>Mira lo que usé para crear ese gran archivo. ¡Un stream escribible!</p><p>El módulo <code>fs</code> se puede utilizar para leer y escribir en archivos utilizando una interfaz de flujo. En el ejemplo anterior, estamos escribiendo en ese <code>big.file</code> a través de un flujo escribible de 1 millón de líneas con un bucle.</p><p>Ejecutando el <em>script </em>de arriba se genera un archivo de unos ~400 MB.</p><p>Aquí hay un simple servidor web Node diseñado para servir exclusivamente el <code>big.file</code>:</p><pre><code class="language-js">const fs = require('fs');
const servidor = require('http').createServer();

servidor.on('request', (peticion, respuesta) =&gt; {
  fs.readFile('./big.file', (error, data) =&gt; {
    if (error) throw error;
  
    respuesta.end(data);
  });
});

servidor.listen(8000);</code></pre><p>Cuando el servidor reciba una petición, servirá el archivo grande usando el método asíncrono, <code>fs.readFile</code>. Pero bueno, no es que estemos bloqueando el bucle de eventos ni nada. Todo va genial, ¿verdad? ¿Verdad?</p><p>Bueno, veamos qué pasa cuando ejecutamos el servidor, nos conectamos a él, y monitorizamos la memoria mientras lo hacemos.</p><p>Cuando ejecuté el servidor, empezó con una cantidad normal de memoria, 8.7 MB:</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*125_8HQ4KzJkeBcj1LcEiQ.png" class="kg-image" alt="1*125_8HQ4KzJkeBcj1LcEiQ" width="800" height="422" loading="lazy"></figure><p>Luego me conecté al servidor. Observe lo que ocurrió con la memoria consumida:</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*SGJw31T5Q9Zfsk24l2yirg.gif" class="kg-image" alt="1*SGJw31T5Q9Zfsk24l2yirg" width="800" height="614" loading="lazy"></figure><p>Vaya, el consumo de memoria ha subido a 434,8 MB.</p><p>Básicamente ponemos todo el <code>big.file</code> en memoria antes de escribirlo en el objeto de respuesta. Esto es muy ineficiente.</p><p>El objeto de respuesta HTTP (<code>res</code> &nbsp;el objeto de respuesta HTTP) es también un flujo escribible. Esto significa que si tenemos un flujo legible que representa el contenido de <code>big.file</code>, podemos superponerlas y obtener prácticamente el mismo resultado sin consumir ~400 MB de memoria.</p><p>El módulo <code>fs</code> de Node puede proporcionarnos un flujo legible para cualquier archivo utilizando el método <code>createReadStream</code>. Podemos enviarlo al objeto de respuesta:</p><pre><code class="language-js">const fs = require('fs');
const servidor = require('http').createServer();

servidor.on('request', (peticion, respuesta) =&gt; {
  const src = fs.createReadStream('./big.file');
  src.pipe(respuesta);
});

servidor.listen(8000);</code></pre><p>Ahora, cuando te conectas a este servidor, ocurre algo mágico (fíjate en el consumo de memoria):</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*iWNNIMhF9QmD25Vho6-fRQ.gif" class="kg-image" alt="1*iWNNIMhF9QmD25Vho6-fRQ" width="800" height="615" loading="lazy"></figure><p>¿Qué es lo que ocurre?</p><p>Cuando un cliente pide un archivo tan grande, lo transmitimos de uno en uno, lo que significa que no lo almacenamos en memoria. El uso de memoria creció unos 25 MB y eso es todo.</p><p>Puedes llevar este ejemplo al límite. Regenera el archivo <code>big.file</code> con cinco millones de líneas en lugar de sólo un millón, lo que llevaría el archivo a más de 2 GB, y eso es realmente más grande que el límite de búfer por defecto en Node.</p><p>Si intentas servir ese archivo utilizando <code>fs.readFile</code>, simplemente no puedes, por defecto (puedes cambiar los límites). Pero con <code>fs.createReadStream</code>, no hay ningún problema en transmitir 2 GB de datos al solicitante, y lo mejor de todo es que el uso de memoria del proceso será aproximadamente el mismo.</p><p>¿Listo para aprender sobre flujos ahora?</p><h3 id="flujos-101"><strong>Flujos<strong> 101</strong></strong></h3><p>Hay cuatro tipos fundamentales de flujos en Node.js: Lectura, escritura, dúplex, y transformación de flujos.</p><ul><li>Un flujo legible es una abstracción de una fuente desde la que se pueden consumir datos. Un ejemplo de ello es el método <code>fs.createReadStream</code>.</li><li>Un flujo escribible es una abstracción de un destino en el que se pueden escribir datos. Un ejemplo de ello es el método <code>fs.createWriteStream</code>.</li><li>Un flujo dúplex es tanto legible como escribible. Un ejemplo de ello es un socket TCP.</li><li>Un flujo de transformación es básicamente un flujo dúplex que puede utilizarse para modificar o transformar los datos a medida que se escriben y se leen. Un ejemplo de ello es el flujo <code>zlib.createGzip</code> para comprimir los datos usando "gzip". Puedes pensar en un flujo de transformación como una función en la que la entrada es la parte del flujo que se puede escribir y la salida es la parte del flujo que se puede leer. También puedes oír referirse a los flujos de transformación como "flujos pasantes".</li></ul><p>Todos los flujos son instancias de <code>EventEmitter</code>. Emiten eventos que pueden utilizarse para leer y escribir datos. Sin embargo, podemos consumir los datos en los flujos de una forma más sencilla utilizando el método <code>pipe</code>.</p><h4 id="el-m-todo-pipe"><strong>El método "pipe"</strong></h4><p>Esta es la línea mágica que debes recordar:</p><pre><code class="language-js">fuenteLegible.pipe(destinoEscribible)</code></pre><p>En esta simple línea, estamos canalizando la salida de un flujo legible - la fuente de datos, como la entrada de un flujo escribible - el destino. La fuente tiene que ser un flujo legible y el destino uno escribible. Por supuesto, ambos pueden ser también flujos dúplex/transformados. De hecho, si estamos canalizando a un flujo dúplex, podemos encadenar llamadas de canalización como hacemos en Linux:</p><pre><code class="language-js">fuenteLegible
  .pipe(transformarFlujo1)
  .pipe(transformarFlujo2)
  .pipe(destinoEscribibleFinal)</code></pre><p>El método <code>pipe</code> &nbsp;retorna el flujo de destino, lo que nos permitió hacer el encadenamiento anterior. Para flujos <code>a</code> (legible), <code>b</code> and <code>c</code> (duplex), and <code>d</code> (escribible), podemos:</p><pre><code class="language-js">a.pipe(b).pipe(c).pipe(d)

# Que es equivalente a:
a.pipe(b)
b.pipe(c)
c.pipe(d)

# Que, en Linux, es equivalente a:
$ a | b | c | d</code></pre><p>El método <code>pipe</code> es la forma más sencilla de consumir flujos. Por lo general, se recomienda utilizar el método <code>pipe</code> o consumir flujos con eventos, pero evite mezclar estos dos. Usualmente cuando estás usando el método <code>pipe</code> no es necesario utilizar eventos, pero si necesita consumir los flujos de forma más personalizada, los eventos serían el camino a seguir.</p><h3 id="eventos-de-flujo">Eventos de flujo</h3><p>Además de leer de una fuente legible y escribir en un destino escribible, el método <code>pipe</code> gestiona automáticamente algunas cosas por el camino. Por ejemplo, gestiona los errores, el fin de los archivos y los casos en los que un flujo es más lento o más rápido que el otro.</p><p>Sin embargo, los flujos también se pueden consumir con eventos directamente. A continuación se muestra el código simplificado equivalente a un evento de lo que el método <code>pipe</code>hace principalmente para leer y escribir información:</p><pre><code class="language-js"># legible.pipe(escribible)

legible.on('data', (trozo) =&gt; {
  escribible.write(trozo);
});

legible.on('end', () =&gt; {
  escribible.end();
});</code></pre><p>He aquí una lista de los eventos y funciones importantes que pueden utilizarse con flujos legibles y escribibles:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*HGXpeiF5-hJrOk_8tT2jFA.png" class="kg-image" alt="1*HGXpeiF5-hJrOk_8tT2jFA" width="800" height="459" loading="lazy"><figcaption>Node.js avanzado</figcaption></figure><p>Los eventos y las funciones están relacionados de algún modo porque suelen utilizarse juntos.</p><p>Los eventos más importantes en un flujo legible son:</p><ul><li>El evento <code>data</code>, que se emite cada vez que el flujo pasa un trozo de datos al consumidor.</li><li>El evento <code>end</code>, que se emite cuando no hay más datos que consumir del flujo.</li></ul><p>Los eventos más importantes en un flujo escribible son:</p><ul><li>El evento <code>drain</code>, que es una señal de que el flujo escribible puede recibir más datos.</li><li>El evento <code>finish</code>, que se emite cuando todos los datos se han vaciado en el sistema subyacente.</li></ul><p>Los eventos y las funciones pueden combinarse para hacer un uso personalizado y optimizado de los flujos. Para consumir un flujo legible, podemos utilizar los métodos <code>pipe</code>/<code>unpipe</code>, o los métodos <code>read</code>/<code>unshift</code>/<code>resume</code>. Para consumir un flujo escribible, podemos convertirlo en el destino de <code>pipe</code>/<code>unpipe</code>, o simplemente escribir en él con la función <code>write</code> y llame al método <code>end</code> cuando hayamos terminado.</p><h4 id="modos-de-pausa-y-fluyente-en-flujos-legibles">Modos de pausa y fluyente en flujos legibles</h4><p>Los flujos legibles tienen dos modos principales que afectan a la forma en que podemos consumirlos:</p><ul><li>Puede estar en modo <strong>pausa</strong>.</li><li>O en <strong>modo fluido</strong>.</li></ul><p>Estos modos se denominan a veces "pull" y "push".</p><p>Todos los flujos legibles se inician por defecto en el modo pausado, pero pueden cambiarse fácilmente a fluido y de nuevo a pausado cuando sea necesario. A veces, el cambio se produce automáticamente.</p><p>Cuando un flujo legible está en modo de pausa, podemos utilizar la función <code>read()</code>para leer del flujo bajo demanda, sin embargo, para un flujo legible en el modo de flujo, los datos fluyen continuamente y tenemos que escuchar los eventos para consumirlos.</p><p>En el modo de flujo, los datos pueden perderse si no hay consumidores disponibles para manejarlos. Esta es la razón por la que, cuando tenemos un flujo legible en modo de flujo, necesitamos un manejador de eventos para la <code>data</code>. De hecho, solo añadiendo un manejador de eventos para la <code>data</code> cambia un flujo en pausa al modo de flujo y eliminar el manejador vuelve a poner el flujo en modo pausa. Parte de esto se hace por compatibilidad con la antigua interfaz de flujos de Node.</p><p>Para cambiar manualmente entre estos dos modos de flujo, puede utilizar la función <code>resume()</code> y <code>pause()</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*HI-mtispQ13qm8ib5yey3g.png" class="kg-image" alt="1*HI-mtispQ13qm8ib5yey3g" width="800" height="445" loading="lazy"><figcaption>Node.js avanzado</figcaption></figure><p>Al consumir flujos legibles mediante la función <code>pipe</code>, no tenemos que preocuparnos de estos modos ya que <code>pipe</code> los gestiona automáticamente.</p><h3 id="implementando-flujos"><strong><strong>Implemen</strong>tando flujos</strong></h3><p>Cuando hablamos de streams en Node.js, hay dos tareas principales diferentes:</p><ul><li>La tarea de <strong>implantar</strong> los flujos.</li><li>La tarea de <strong>consumirlos</strong>.</li></ul><p>Hasta ahora sólo hemos hablado de consumir flujos. ¡Pongamos algunos en práctica!</p><p>Los ejecutores de los flujos suelen ser los que <code>requiere</code> el módulo <code>stream</code>.</p><h4 id="implementando-un-flujo-escribible"><strong><strong>Implement</strong>ando un flujo escribible</strong></h4><p>Para implementar un flujo con capacidad de escritura, necesitamos utilizar la función <code>Writable</code> del módulo de flujo.</p><pre><code>const { Escribible } = require('flujo');</code></pre><p>Podemos implementar un flujo escribible de muchas maneras. Podemos, por ejemplo, extender el constructor <code>Writable</code> si queremos:</p><pre><code class="language-js">class miFlujoEscribible extends Escribible {
}</code></pre><p>Sin embargo, prefiero el enfoque más simple del constructor. Simplemente creamos un objeto a partir del constructor <code>Writable</code> y pasarle una serie de opciones. La única opción obligatoria es la función <code>write</code> que expone el trozo de datos que se va a escribir.</p><pre><code class="language-js">const { Escribible } = require('flujo');

const outStream = new Escribible({
  write(trozo, codificacion, callback) {
    console.log(trozo.toString());
    callback();
  }
});

process.stdin.pipe(outStream);</code></pre><p>This write method takes three arguments.</p><ul><li>El trozo suele ser un <em>buffer </em>a no ser que configuremos el flujo de otra manera.</li><li>El argumento de codificación es necesario en ese caso, pero normalmente podemos ignorarlo.</li><li>El callback es una función que necesitamos llamar después de que hayamos terminado de procesar el trozo de datos. Es lo que señala si la escritura fue exitosa o no. Para señalar un fallo, llame a la devolución de llamada con un objeto de error.</li></ul><p>En <code>outStream</code>, nosotros simplemente imprimimos con la función <code>console.log</code> el trozo como una cadena y llamar a la devolución de llamada después de que sin un error para indicar el éxito. Este es un flujo de eco muy simple y probablemente no tan útil. Se hará eco de todo lo que reciba.</p><p>Para consumir este flujo, podemos utilizarlo simplemente con <code>process.stdin</code>, que es un flujo legible, por lo que podemos simplemente canalizar <code>process.stdin</code> hacia nuestro <code>outStream</code>.</p><p>Cuando ejecutamos el código anterior, cualquier cosa que escribamos en <code>process.stdin</code> se devolverá utilizando el método <code>outStream</code> <code>console.log</code>.</p><p>No es un flujo muy útil de implementar porque en realidad ya está implementado e incorporado. Esto es muy equivalente a <code>process.stdout</code>. Podemos canalizar <code>stdin</code> hacia <code>stdout</code> y obtendremos exactamente la misma función de eco con esta única línea:</p><pre><code class="language-js">process.stdin.pipe(process.stdout);</code></pre><h3 id="implementa-un-flujo-legible">Implementa un flujo legible</h3><p>Para implementar un flujo legible, necesitamos la interfaz <code>Readable</code>, y construir un objeto a partir de él, e implementar un método <code>read()</code> en el parámetro de configuración del flujo:</p><pre><code class="language-js">const { Legible } = require('flujo');

const enFlujo = new Legible({
  read() {}
});</code></pre><p>Hay una forma sencilla de implementar flujos legibles. Podemos utilizar directamente <strong><code>push</code> </strong>para insertar los datos que queremos que consuman los consumidores.</p><pre><code class="language-js">const { Legible } = require('flujo'); 

const enFlujo = new Legible({
  read() {}
});

enFlujo.push('ABCDEFGHIJKLM');
enFlujo.push('NOPQRSTUVWXYZ');

enFlujo.push(null); // No más datos

enFlujo.pipe(process.stdout);</code></pre><p>Cuando usamos <code>push</code> en un objeto <code>null</code>, que significa que queremos señalar que el flujo no tiene más datos.</p><p>Para consumir este simple flujo de lectura, podemos simplemente canalizarlo en el flujo de escritura <code>process.stdout</code>.</p><p>Cuando ejecutemos el código anterior, estaremos leyendo todos los datos de <code>enFlujo</code> y enviarlo a la salida estándar. Muy sencillo, pero también poco eficiente.</p><p>Básicamente estamos empujando todos los datos en el flujo antes de canalizarlos a <code>process.stdout</code>. La mejor manera de hacerlo es enviar los datos a petición del consumidor. Podemos hacerlo implementando la función <code>read()</code>en el objeto de configuración:</p><pre><code class="language-js">const enFlujo = new Legible({
  read(tamaño) {
    // hay una demanda de datos... alguien desea leerlos.
  }
});</code></pre><p>Cuando se llama al método de lectura en un flujo legible, la implementación puede enviar datos parciales a la cola. Por ejemplo, podemos empujar una letra a la vez, comenzando con el código de carácter 65 (que representa A), y el aumento que en cada empuje:</p><pre><code class="language-js">const enFlujo = new Legible({
  read(tamaño) {
    this.push(String.fromCharCode(this.currentCharCode++));
    if (this.currentCharCode &gt; 90) {
      this.push(null);
    }
  }
});

enFlujo.currentCharCode = 65;

enFlujo.pipe(process.stdout);</code></pre><p>Mientras el consumidor está leyendo un flujo legible, el método <code>read</code> continuará disparándose, y empujaremos más letras. Tenemos que detener este ciclo en algún lugar, y es por eso que una sentencia if para empujar <em>null </em>cuando el currentCharCode (código de carácter actual) es mayor que 90 (que representa Z).</p><p>Este código es equivalente al más simple con el que empezamos, pero ahora estamos empujando los datos bajo demanda cuando el consumidor lo pide. Usted siempre debe hacer eso.</p><h4 id="implementando-flujos-d-plex-transformaci-n"><strong><strong>Implement</strong>ando flujos Dúplex/Transformación</strong></h4><p>Con los flujos dúplex, podemos implementar tanto flujos de lectura como de escritura con el mismo objeto. Es como si heredáramos de ambas interfaces.</p><p>A continuación se muestra un ejemplo de flujo dúplex que combina los dos ejemplos de escritura y lectura implementados anteriormente:</p><pre><code class="language-js">const { Duplex } = require('flujo');

const inoutStream = new Duplex({
  write(trozo, codificacion, callback) {
    console.log(trozo.toString());
    callback();
  },

  read(tamaño) {
    this.push(String.fromCharCode(this.currentCharCode++));
    if (this.currentCharCode &gt; 90) {
      this.push(null);
    }
  }
});

inoutStream.currentCharCode = 65;

process.stdin.pipe(inoutStream).pipe(process.stdout);</code></pre><p>Combinando los métodos, podemos utilizar este flujo dúplex para leer las letras de la A a la Z y también podemos utilizarlo por su función de eco. Canalizamos el flujo legible <code>stdin</code> en este flujo dúplex para utilizar la función de eco y canalizamos el propio flujo dúplex en el archivo escribible <code>stdout</code> para ver las letras de la A a la Z.</p><p>Es importante entender que los lados legible y grabable de un flujo dúplex funcionan de forma completamente independiente el uno del otro. Se trata simplemente de una agrupación de dos características en un objeto.</p><p>Un flujo de transformación es el flujo dúplex más interesante porque su salida se calcula a partir de su entrada.</p><p>Para un flujo de transformación, no tenemos que implementar la función <code>read</code> o <code>write</code>, sólo necesitamos implementar un método <code>transform</code>, que combina ambos. Tiene la firma del método <code>write</code> y podemos utilizarlo para insertar con <code>push</code> los datos también.</p><p>Aquí tienes un simple flujo de transformación que devuelve cualquier cosa que escribas en él después de transformarla a formato de mayúsculas:</p><pre><code class="language-js">const { Transform } = require('flujo');

const aMayuscula = new Transform({
  transform(trozo, codificacion, callback) {
    this.push(trozo.toString().toUpperCase());
    callback();
  }
});

process.stdin.pipe(aMayuscula).pipe(process.stdout);</code></pre><p>En este flujo de transformación, que estamos consumiendo exactamente igual que en el ejemplo anterior de flujo dúplex, sólo implementamos el método <code>transform()</code>. En ese método, convertimos el <code>trozo</code> en su versión en mayúsculas y, a continuación, se usa el método <code>push</code> en esa versión como la parte legible.</p><h4 id="modo-de-flujos-como-objeto">Modo de flujos como objeto</h4><p>Por defecto, los flujos esperan valores <em>Buffer</em>/<em>String</em>. Hay un marcador <code>objectMode</code> que podemos configurar para que el flujo acepte cualquier objeto JavaScript.</p><p>He aquí un ejemplo sencillo para demostrarlo. La siguiente combinación de flujos de transformación permite mapear una cadena de valores separados por comas en un objeto JavaScript. Así <code>“a,b,c,d”</code> se cionvierte a <code>{a: b, c: d}</code>.</p><pre><code class="language-js">const { Transform } = require('flujo');

const separadorDeComa = new Transform({
  modoDeLecturaObjeto: true,
  
  transform(trozo, codificacion, callback) {
    this.push(trozo.toString().trim().split(','));
    callback();
  }
});

const arrayAObjeto = new Transform({
  modoDeLecturaObjeto: true,
  modoDeEscrituraObjeto: true,
  
  transform(trozo, codificacion, callback) {
    const objeto = {};
    for(let i=0; i &lt; trozo.length; i+=2) {
      objeto[trozo[i]] = trozo[i+1];
    }
    this.push(objeto);
    callback();
  }
});

const objetoAString = new Transform({
  modoDeEscrituraObjeto: true,
  
  transform(trozo, codificacion, callback) {
    this.push(JSON.stringify(trozo) + '\n');
    callback();
  }
});

process.stdin
  .pipe(separadorDeComa)
  .pipe(arrayAObjeto)
  .pipe(objetoAString)
  .pipe(process.stdout)</code></pre><p>Pasamos la cadena de entrada (por ejemplo, <code>“a,b,c,d”</code>) a través de <code>separadorDeComa</code> que empuja un array como sus datos legibles (<code>[“a”, “b”, “c”, “d”]</code>). Añadir el marcador <code>modoDeEscrituraObjeto</code> en ese flujo es necesario porque estamos empujando un objeto allí, no una cadena.</p><p>A continuación, tomamos la matriz y la introducimos en el archivo <code>arrayAObjeto</code>. Necesitamos un marcador <code>modoDeEscrituraObjeto</code>para hacer que ese flujo acepte un objeto. También empujará un objeto (el array de entrada mapeado en un objeto) y por eso también necesitábamos el marcador <code>modoDeLecturaObjeto</code> ahí también. El último flujo <code>objetoAString</code> acepta un objeto pero expulsa una cadena, y por eso sólo necesitábamos un botón <code>modoDeEscrituraObjeto</code> ahí. La parte legible es una cadena normal (el objeto que se convirtió a <em>string</em>).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*u2kQzUD0ruPpt-xx0UOHoA.png" class="kg-image" alt="1*u2kQzUD0ruPpt-xx0UOHoA" width="482" height="210" loading="lazy"><figcaption>Uso del ejemplo anterior</figcaption></figure><h4 id="los-flujos-de-transformaci-n-incorporados-en-node-js">Los flujos de transformación incorporados en Node.js</h4><p>Node tiene algunos flujos de transformación incorporados muy útiles. A saber, los flujos "zlib" y "crypto".</p><p>He aquí un ejemplo que utiliza la función <code>zlib.createGzip()</code> combinados con los flujos <code>fs</code> que se pueden leer y escribir para crear un código para comprimir archivos:</p><pre><code class="language-js">const fs = require('fs');
const zlib = require('zlib');
const archivo = process.argv[2];

fs.crearFlujoDeLectura(archivo)
  .pipe(zlib.crearGzip())
  .pipe(fs.crearFlujoDeEscritura(archivo + '.gz'));</code></pre><p>Puedes usar este <em>script </em>para comprimir cualquier archivo que pases como argumento. Estamos canalizando un flujo legible para ese archivo en el flujo de transformación incorporado en "zlib" y luego en un flujo de escritura para el nuevo archivo comprimido. Simple.</p><p>Lo bueno de usar tuberías es que podemos combinarlas con eventos si lo necesitamos. Digamos, por ejemplo, que quiero que el usuario vea un indicador de progreso mientras el script está trabajando y un mensaje de "Hecho" cuando el script haya terminado. Ya que el método <code>pipe</code> devuelve el flujo de destino, podemos encadenar también el registro de manejadores de eventos:</p><pre><code class="language-js">const fs = require('fs');
const zlib = require('zlib');
const archivo = process.argv[2];

fs.crearFlujoDeLectura(archivo)
  .pipe(zlib.crearGzip())
  .on('data', () =&gt; process.stdout.write('.'))
  .pipe(fs.crearFlujoDeEscritura(archivo + '.zz'))
  .on('finish', () =&gt; console.log('Hecho'));</code></pre><p>Así que con el método <code>pipe</code>, conseguimos consumir flujos fácilmente, pero aún podemos personalizar más nuestra interacción con esos flujos utilizando eventos cuando sea necesario.</p><p>Lo que es genial del método <code>pipe</code> es que podemos utilizarlo para componer nuestro programa pieza a pieza, de una forma mucho más legible. Por ejemplo, en lugar de escuchar el evento <code>data</code> más arriba, podemos simplemente crear un flujo de transformación para informar del progreso, y reemplazar el método <code>.on()</code> &nbsp;con otra invocación del método <code>.pipe()</code>:</p><pre><code class="language-js">const fs = require('fs');
const zlib = require('zlib');
const archivo = process.argv[2];

const { Transform } = require('flujo');

const reportarProgreso = new Transform({
  transform(trozo, encoding, callback) {
    process.stdout.write('.');
    callback(null, trozo);
  }
});

fs.crearFlujoDeLectura(archivo)
  .pipe(zlib.crearGzip())
  .pipe(reportarProgreso)
  .pipe(fs.crearFlujoDeLectura(archivo + '.zz'))
  .on('finish', () =&gt; console.log('Hecho'));</code></pre><p>El flujo <code>reportProgress</code> es un simple flujo de paso, pero también informa del progreso a la salida estándar. Fíjate en cómo he utilizado el segundo argumento en el método <code>callback()</code> para empujar los datos dentro del método <code>transform()</code>. Esto equivale a empujar primero los datos.</p><p>Las aplicaciones de combinar flujos son infinitas. Por ejemplo, si necesitamos encriptar el archivo antes o después de gziparlo, todo lo que tenemos que hacer es canalizar otro flujo de transformación en ese orden exacto que necesitábamos. Podemos utilizar el módulo <code>crypto</code> de Node para eso:</p><pre><code class="language-js">const crypto = require('crypto');
// ...

fs.crearFluejoDeLectura(archivo)
  .pipe(zlib.crearGzip())
  .pipe(crypto.crearCipher('aes192', 'a_secret'))
  .pipe(reportarProgreso)
  .pipe(fs.crearFlujoDeEscritura(archivo + '.zz'))
  .on('finish', () =&gt; console.log('Hecho'));</code></pre><p>El <em>script </em>anterior comprime y luego encripta el archivo pasado y sólo aquellos que tienen el secreto pueden utilizar el archivo de salida. No podemos descomprimir este archivo con las utilidades normales de descompresión porque está cifrado.</p><p>Para poder descomprimir cualquier cosa comprimida con el <em>script </em>anterior, necesitamos utilizar los flujos opuestos para "crypto" y "zlib" en orden inverso, lo cual es sencillo:</p><pre><code class="language-js">fs.crearFlujoDeLectura(archivo)
  .pipe(crypto.crearDecifrador('aes192', 'a_secret'))
  .pipe(zlib.crearGunzip())
  .pipe(reportarProgreso)
  .pipe(fs.crearFlujoDeLectura(archivo.slice(0, -3)))
  .on('finish', () =&gt; console.log('Hecho'));</code></pre><p>Asumiendo que el archivo pasado es la versión comprimida, el código anterior creará un flujo de lectura a partir de él, lo canalizará en el flujo de "crypto" <code>createDecipher()</code> (utilizando el mismo secreto), canalice la salida de éste archivo en el flujo "fzlib" <code>createGunzip()</code>, y luego escribir las cosas de nuevo a un archivo sin la parte de la extensión.</p><p>Eso es todo lo que tengo para este tema. Gracias por leernos. Hasta la próxima.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Guía del SDLC: Fases y metodologías del ciclo de vida del desarrollo de software ]]>
                </title>
                <description>
                    <![CDATA[ Cuando decidí aprender a programar por mí mismo hace casi cuatro años, nunca había oído hablar del ciclo de vida del desarrollo de software, y mucho menos pensado en él. Como un recién desarrollador, estaba enfocado en aprender las tecnologías que me ayudaran a obtener ese codiciado primer trabajo como ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/guia-del-sdlc-fases-y-metodologias-del-ciclo-de-vida-del-desarrollo-de-software/</link>
                <guid isPermaLink="false">633b3080d632c3088e4f1b71</guid>
                
                    <category>
                        <![CDATA[ software ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Luis E. Alvarado ]]>
                </dc:creator>
                <pubDate>Thu, 17 Nov 2022 06:23:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/10/suzanne-d-williams-VMKBFR6r_jg-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/get-a-basic-understanding-of-the-life-cycles-of-software-development/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">SDLC Guide – Software Development Life Cycle Phases and Methodologies</a>
      </p><p>Cuando decidí aprender a programar por mí mismo hace casi cuatro años, nunca había oído hablar del ciclo de vida del desarrollo de software, y mucho menos pensado en él.</p><p>Como un recién desarrollador, estaba enfocado en aprender las tecnologías que me ayudaran a obtener ese codiciado primer trabajo como desarrollador, no los matices de cómo esos equipos operaban.</p><p>Cuando en efecto aprendí sobre ellos, pensé que serían inservibles para mí porque me consideraba a mí mismo como un desarrollador <em>web</em>, no un desarrollador de <em>software</em>.</p><p>Desde entonces he aprendido que esto no podría estar más alejado de la realidad, y estos principios/prácticas juegan un rol muy importante en las actividades de mi día a día (ya sea que me dé cuenta o no).</p><p>Soy lo bastante afortunado de ver cómo el código que escribo, las características que construyo, y los "<em>bugs</em>" que inadvertidamente creo (más de los que me importa admitir) afectan al usuario final y su experiencia. Esa experiencia me ha ayudado a dar forma a lo que pienso acerca del proceso de construir productos y resolver problemas para mis usuarios.</p><p>He tenido algo de tiempo para pensar acerca de las diferencias (y similitudes) que cada uno de estos acercamientos ofrece. En su núcleo, cada uno está concentrado en entregar <em>software </em>de alta calidad, tan eficiente como lo eficientemente costoso como sea posible.</p><p>Profesionalmente, solo he usado una o dos de estas metodologías. Pero aún encuentro valor valor, en al menos un entendimiento básico de todas ellas.</p><p>Todas estas metodologías siguen una serie de fases similares a este diagrama:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/02/SDLC_-_Software_Development_Life_Cycle.jpg" class="kg-image" alt="SDLC_-_Software_Development_Life_Cycle" width="600" height="400" loading="lazy"><figcaption>Requirement Analysis -&gt; Design -&gt; Implementation -&gt; Testing -&gt; Evolution</figcaption></figure><p>Entonces, aquí están los métodos para el ciclo de vida del <em>software </em>(sin ningún orden en particular):</p><ul><li><em><a href="https://es.wikipedia.org/wiki/Lean_software_development">Lean</a></em></li><li><em><a href="https://www.agilealliance.org/agile101/">Agile</a></em></li><li><em><a href="https://es.wikipedia.org/wiki/Waterfall_model">Waterfall</a></em></li><li><em><a href="https://es.wikipedia.org/wiki/Iterative_and_incremental_development">Iterative</a></em></li><li><em><a href="https://es.wikipedia.org/wiki/Spiral_model">Spiral</a></em></li><li><em><a href="https://es.wikipedia.org/wiki/DevOps">Dev Ops</a></em></li></ul><p>Ahondemos en las diferencias y similitudes de cada método.</p><h2 id="lean"><strong><strong>Lean</strong></strong></h2><p>La metodología <em>Lean </em>se apoya fuertemente y se compone de siete principios.</p><p>Sin especificar el orden estos son:</p><ol><li>Eliminar el desperdicio</li><li>Amplificar el aprendizaje</li><li>Decidir tan tarde como sea posible</li><li>Entregar tan rápido como sea posible</li><li>Empoderar al equipo</li><li>Construir integridad</li><li>Ver/Optimizar el panorama general</li></ol><p>Cada principio tiene un propósito específico con beneficios que se complementan uno al otro.</p><p><strong>Eliminar el desperdicio </strong>(características extra, trabajo incompleto, compromiso gerencial, etc) crea más valor para el cliente que, a cambio, aumenta su satisfacción.</p><p><strong>Amplificar el aprendizaje</strong> permite a los equipos reinvertir en su habilidad productos a los clientes.</p><p><strong>Decidir tan tarde como sea posible</strong> se refiere a todas las grandes decisiones, dando a los equipos un acercamiento basado en opciones o en conjuntos. &nbsp;Estos permite a los equipos reunir hechos en lugar de opiniones que ayude a influir las decisiones cuando sean tomadas.</p><p><strong>Entregar lo más rápido posible</strong> se explica por sí mismo: construya el producto lo más rápido posible para entregarlo a los clientes para su evaluación/iteración.</p><p>En un escenario típico, los gerentes reparten tareas/trabajos a los desarrolladores. Con la metodología <em>Lean </em>los desarrolladores "enseñan" a los gerentes cómo escuchar a los que "están en las trincheras" por lo tanto, influenciando en las decisiones/elecciones de la gerencia.</p><p>Esto ayuda a que los equipos se sientan más empoderados a que se expresen sobre las ideas y soluciones.</p><p>Haciendo de la <strong>integridad </strong>una regla en vez de una excepción significa que el cliente puede confiar en que el sistema está siendo construido. El cliente sabe que el sistema se construye para resistir la cantidad apropiada de crecimiento y "estiramiento" si lo necesita.</p><p>Me gusta pensar de la integridad como algo con los mismos lineamientos al sentarse en una silla. Cuando te sientas en la silla crees que está hecha con el mejor material que te aguantará cada vez que te sientes en ella por el resto de su vida útil. El cliente necesita de esa misma confianza en el producto construido.</p><p>Por último, <strong>ver y optimizar el panorama general</strong> se refiere al total del sistema construido. Al optimizar "el todo" miramos al <em>software </em>no como a la suma de varios componentes, sino como a una entidad grande que se optimiza para eficiencia.</p><p>Esto significa que durante el desarrollo, &nbsp;el producto es dividido en piezas manejables y que los "<em>bugs</em>" inadvertidos no solo son descubiertos, sino además resueltos rápidamente.</p><h2 id="agile"><strong><strong>Agile</strong></strong></h2><p>Este es el acercamiento "falla rápido" para el desarrollo de <em>software</em>.</p><p>Hace énfasis en pequeños e incrementales lanzamientos con ciclos de lanzamiento andando. Con cada iteración los equipos apuntan a identificar y localizar pequeños problemas antes de que se hagan grandes.</p><p>Estos también significa que los equipos deben involucrar a las partes interesadas (gente/organizaciones que el código puede afectar en última instancia tales como gerentes, líderes técnicos, CTO's, y clientes) para obtener su retroalimentación.</p><p>Si eres <em>freelance</em>, las partes interesadas serían tus clientes - ultimadamente necesitas asegurar su satisfacción con el trabajo antes de continuar.</p><p>La metodología <em>Agile </em>es técnicamente una ramificación de la metodología <em>Lean</em>, con algunas diferencias notables - principalmente prioriza a la satisfacción del cliente desde el comienzo y permite a los equipos responder rápidamente a la retroalimentación del cliente.</p><p>Aunque está más allá de la pertinencia de este artículo, hay un marco de trabajo más complejo dentro de <em>Agile </em>llamado <a href="https://es.wikipedia.org/wiki/Scrum_%28software_development%29">SCRUM</a>. Esta metodología es usada por grandes, extremadamente complejos proyectos y ha sido usado incluso fuera del desarrollo de software.</p><h2 id="waterfall"><strong><strong>Waterfall</strong></strong></h2><p>La metodología <em>Waterfall </em>es, por mucho, la más antigua de todas. Nunca se supuso que fuera un modelo para el desarrollo de <em>software </em>y tuvo sus inicios en los mundos de la construcción y la manufactura.</p><p>Este acercamiento es simple en su estructura - concluye todas las partes de una fase antes de continuar con la siguiente fase con más impulso hacia el final del proyecto conforme las etapas son completadas. El inicio y la conclusión de cada etapa (excepto en la primera) depende de la finalización/transferencia de información de la etapa anterior.</p><p>Bajo el enfoque <em>Waterfall</em>, cada etapa tiene su propio plan de proyecto rígido que termina con pruebas para el trabajo completado previamente. Cabe señalar que este enfoque no se recomienda para proyectos más grandes o de mayor duración debido a la rigidez antes mencionada.</p><p>Piensa en la génesis de esta metodología y la entenderás más. Proviene del mundo de la construcción/fabricación donde es común completar una fase a la vez. Durante la construcción de una casa, no comenzaría a instalar la plomería antes de que se haya colocado el marco.</p><p>Esa no es la forma en que funciona el desarrollo de <em>software </em>en general. Como todos sabemos, a veces se hace necesario volver a visitar una fase que antes se creía terminada.</p><h2 id="iterative"><strong><strong>Iterative</strong></strong></h2><p>Esto se conoce como el "enfoque repetitivo" o el enfoque de "hacerlo mejor la próxima vez" debido a las diferentes oportunidades que brinda para mejorar el producto con cada iteración del ciclo.</p><p>No lo sé todo (como todos :D), pero este es mi ciclo de vida favorito para el desarrollo. Creo que funciona mejor para mi situación actual tanto en mi carrera como <em>freelance </em>porque me permite "avanzar constantemente mientras mejoro las cosas".</p><p>Con el enfoque iterativo, los equipos implementan una solución, la prueban, evalúan su eficacia/rendimiento y luego identifican otras áreas de mejora. Esto sucede para cada ciclo (iteración) del proceso de desarrollo.</p><p>Con cada versión lanzada viene otra iteración hasta que el producto final se completa y está listo para su implementación a los usuarios.</p><p>Una de las grandes características del enfoque iterativo es que tú y su equipo obtienen una versión funcional del <em>software </em>desde el principio del proceso de desarrollo. Esto puede ser especialmente útil para mostrar a las partes interesadas para medir su respuesta/retroalimentación.</p><p>Uno de los grandes inconvenientes de este enfoque es que puede consumir una gran cantidad de recursos muy rápidamente. Imagine todas las personas, las horas, las correcciones de errores y los salarios que se incluyen en cada iteración del ciclo de desarrollo y obtendrá una buena imagen del uso de los recursos.</p><p>Dentro de este enfoque hay un subconjunto de principios desarrollado por <em>Rational Software Corporation </em>(comprado por IBM) llamado <em><a href="https://es.wikipedia.org/wiki/Proceso_Unificado_de_Rational">Rational Unified Process</a> </em>(RUP) que consta de 4 fases:</p><ul><li>Comienzo</li><li>Elaboración</li><li>Construcción</li><li>Transición (lanzamiento del producto)</li></ul><p>Este conjunto de principios pretende ser flexible y adaptarse a las necesidades de cada equipo que lo utilice.</p><h2 id="spiral"><strong><strong>Spiral</strong></strong></h2><p>La metodología espiral es probablemente la más flexible de las seis. Es una metodología basada en riesgos: identificarlos y negarlos. El riesgo (identificación y aversión) impulsa cada decisión en este modelo. Se divide en cuatro sub-fases:</p><ul><li>Planeación (objetivos)</li><li>Análisis de riesgos (identificar posibles obstáculos)</li><li>Desarrollo y Testeo (la versión actual y la siguiente)</li><li>Evaluación (inspección de la fase actual y planificar la siguiente)</li></ul><p>Cada iteración de cada fase comienza con la planificación de la siguiente fase. De esta manera, los riesgos potenciales se identifican antes de que se encuentren. Esto también permite tener un plan de acción cuando surgen dichos riesgos.</p><p>Durante las fases, los equipos también trabajan para mitigar estos riesgos y su impacto en futuras iteraciones del desarrollo en espiral.</p><p>A medida que continúa el proceso de desarrollo, cada una de estas cuatro sub-fases se repite en forma de espiral. Esto permite múltiples rondas de refinamiento para cada sub-fase hasta su finalización.</p><h2 id="dev-ops"><strong><strong>Dev Ops</strong></strong></h2><p>Si realiza una búsqueda rápida, no encontrará escasez de información sobre este método de ciclo de vida de desarrollo. Es el chico nuevo en el vecindario que une a los equipos de desarrollo de <em>software </em>y operaciones de tecnología de la información.</p><p>Estos equipos trabajan en conjunto para proporcionar actualizaciones pequeñas, pero impactantes a los productos que se presentan con frecuencia. A su vez, esto crea un ciclo continuo de retroalimentación y mejora que impulsa el desarrollo.</p><p>Esta metodología particular también es conocida por automatizar las partes manuales del desarrollo (piense en la implementación).</p><p>El objetivo general de esta metodología es, como la mayoría de las otras, acortar el ciclo de vida de desarrollo y proporcionar productos de calidad.</p><p>Uno de los inconvenientes de esta metodología es la mentalidad significativa y los cambios culturales dentro de una organización. Los equipos que pueden haber estado acostumbrados a trabajar en muchas cosas encuentran que sus tareas se reducen a solo una o dos.</p><p>Por ejemplo, un desarrollador de propósito general puede descubrir que ahora solo se le asigna la parte de testeo o la parte de experiencia del usuario final.</p><h2 id="trayendo-todo-a-casa"><strong>Trayendo todo a casa</strong></h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://jonathansexton.me/blog/wp-content/uploads/2020/02/clever-visuals-iMwiPZNX3SI-unsplash-1024x690.jpg" class="kg-image" alt="a light bulb on a book" width="600" height="400" loading="lazy"><figcaption>Photo by <a href="https://unsplash.com/@clever_visuals?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" style="box-sizing: inherit; color: var(--darkreader-text--gray90); margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 22px; vertical-align: baseline; background-color: transparent; text-decoration: underline; cursor: pointer; word-break: break-word;">Clever Visuals</a> on <a href="https://unsplash.com/s/photos/bright-idea?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" style="box-sizing: inherit; color: var(--darkreader-text--gray90); margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 22px; vertical-align: baseline; background-color: transparent; text-decoration: underline; cursor: pointer; word-break: break-word;">Unsplash</a></figcaption></figure><p>Espero que ahora puedas ver la importancia y los beneficios de cada una de estas metodologías. Cada uno de estos posee sus propias fortalezas y debilidades.</p><p>Son, en su nivel más básico, un conjunto de pautas y principios que buscan entregar un trabajo eficiente y de alta calidad a las partes interesadas.</p><p>Cuando empecé a aprender a programar no tenía un mentor. Al compartir lo que he aprendido, espero ayudar a aquellos que están aprendiendo a programar cuando y donde puedan.</p><p>Quiero compartir tanta información y experiencia como me sea posible con otros desarrolladores. Si estás aprendiendo a programar por tu cuenta o si eres un desarrollador experimentado, espero que este artículo te ayude, aunque sea un poco.</p><p>Echa un vistazo a mi <em><a href="https://jonathansexton.me/blog">blog</a> </em>donde con frecuencia publico artículos sobre desarrollo web.</p><p>Mientras estás allí, ¿por qué no te suscribes a mi <em>newsletter </em>de noticias? Puede hacerlo en la parte superior derecha de la página principal del blog. Me gusta enviar artículos interesantes (los míos y de otros), recursos y herramientas para desarrolladores de vez en cuando.</p><p>Si tienes preguntas sobre este artículo o, en general, mis DM están abiertos -- ven a saludarme en <a href="https://twitter.com/jj_goose">Twitter</a> o en cualquiera de mis otras cuentas de redes sociales que puedes encontrar debajo del <em>newsletter</em>, regístrate en la página principal o en mi perfil aquí :)</p><p>!Que tengas un día increíble y feliz <em>coding</em>, amig@!</p><hr> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
