<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Las chorradas de Juanjo</title>
    <description>Unas veces hablo de ingeniería de software, otras de los libros que leo o apuntes míos. Básicamente, intento explicarme a mí mismo cómo funciona el mundo del software sin que me explote la cabeza.</description>
    <link>https://blog.juanjorequena.com/</link>
    <language>es</language>
    <atom:link href="https://blog.juanjorequena.com/feed.xml" rel="self" type="application/rss+xml" />
    <lastBuildDate>Sat, 31 Oct 2026 12:11:44 +0100</lastBuildDate>
    
      <item>
        <title>📚 Hacer software es como… &gt; Lecciones de Code That Fits In Your Head</title>
        <dc:creator><![CDATA[Juanjo Requena]]></dc:creator>
        <description>¿Por qué he leído este libro? Poco antes de terminar 2025, alcancé la cifra de 14 libros leídos, de los cuales 4 eran de desarrollo de software. Casi todos se centraban en arquitectura y diseño de alto nivel, así que buscaba algo más práctico a la hora de escribir código...</description>
        <content:encoded><![CDATA[<h2 id="por-qué-he-leído-este-libro">¿Por qué he leído este libro?</h2>

<p>Poco antes de terminar 2025, alcancé la cifra de 14 libros leídos, de los cuales 4 eran de desarrollo de software. Casi todos se centraban en arquitectura y diseño de alto nivel, así que buscaba algo más práctico a la hora de escribir código y con una perspectiva reciente.</p>

<p><strong>Code That Fits In Your Head</strong> salió en 2021 y, como sabemos, nuestra industria cambia a pasos de gigante cada año. Este terminó siendo mi libro número 15 del año, las ideas que propone me parecieron tan interesantes que decidí que no podían quedarse solo en mi libreta de notas, así que ahí va este blog post.</p>

<p>🔗 Link al libro: <a href="https://www.goodreads.com/book/show/57345272-code-that-fits-in-your-head">https://www.goodreads.com/book/show/57345272-code-that-fits-in-your-head</a></p>

<p>📢 <strong>RECOMENDACIÓN PARA EL LECTOR:</strong> si esta leyendo esto, te sugiero que te leas los puntos 1,2,3 y 5 (como mucho). Si te gustan las ideas que contiene, prueba a leer el libro.</p>

<hr />

<h2 id="1-la-realidad-de-nuestra-industria-capítulos-1-2">1. La realidad de nuestra industria (capítulos 1-2)</h2>

<p>El libro comienza rompiendo mitos sobre qué es realmente el desarrollo de software.</p>

<ul>
  <li>
    <p>⭐ <strong>Hacer software no es ni como construir una casa ni cuidar un jardín:</strong> Cuando la gente compara hacer software con construir una casa o cuidar un jardín, esas metáforas son muy lejanas a la realidad. La industria del desarrollo del software no se asemeja a ninguna disciplina en la ingeniería. Aún no tenemos metodologías replicables que puedan ofrecer resultados de manera consistente.</p>
  </li>
  <li>
    <p>⭐ “<strong>A mí me funciona cuando hago las cosas así”:</strong> En el desarrollo de software actual, el ‘cada maestro tiene su librillo’ se ha convertido en una excusa para el subjetivismo. A diferencia de otras ingenierías, parecemos atrapados en un ciclo de experiencias individuales y contextos aislados. Este libro nace para buscar las leyes fundamentales que rigen nuestra disciplina, transformando la intuición personal en una ingeniería basada en principios (en lo que sea posible).</p>
  </li>
  <li>
    <p><strong><em>El futuro ya está aquí, solo que no está distribuido de manera uniforme:</em></strong> Hay unas pocas empresas que están haciendo muy buen software y la mayoría, que siguen haciendo churros.</p>
  </li>
  <li>
    <p>📝 <strong>Warnings como errores:</strong> Trata los warnings del linter o compilador como errores. Al principio frustra, pero mejora radicalmente la calidad de tu código y te hace mejor programador.</p>
  </li>
</ul>

<hr />

<h2 id="2-el-código-es-para-ser-leído-y-mantenido-capítulo-3">2. El código es para ser leído y mantenido (capítulo 3)</h2>

<p>Uno de los pilares del libro es la <strong>legibilidad</strong> y <strong>sostenibilidad de tu código</strong>.</p>

<ul>
  <li>
    <p>Un ordenador no es como un cerebro. Con tu cerebro puedes tener como 7 cosas en contexto en la cabeza, la RAM de un ordenador puede tener miles.</p>
  </li>
  <li>
    <p>⭐️ <strong>Sostenibilidad:</strong> El software engineering debería de hacer el proceso de desarrollo de software más uniforme. Debería de mantener a la organización que hay detrás. Algunos programadores nunca consideran si el código que están escribiendo tiene valor o no. Otros tienen dificultades viendo resultados cuantificables que no sean inmediatos. La sostenibilidad es un punto intermedio.</p>
  </li>
  <li>
    <p>⭐ <strong>Optimiza para la lectura:</strong> Pasas más tiempo leyendo el código que escribiéndolo. Cuando escribes código, tienes todo el contexto en la cabeza. Piensa que quien lee tu código no lo tiene, tienes que hacer que su lectura sea lo más fácil y comprensible posible.</p>
  </li>
  <li>
    <p>⭐ <strong>¿Cómo escribo código legible?:</strong> No puedes confiar en tu intuición. Necesitas algo que puedas poner en práctica como el uso de heurísticas y checklists, eso es software engineering.</p>
  </li>
</ul>

<hr />

<h2 id="3-más-allá-de-hacer-código-que-funciona-capítulo-4">3. Más allá de hacer código que funciona (capítulo 4)</h2>

<ul>
  <li>
    <p>⭐️ <strong>La documentación debería de priorizar explicar el por qué una decisión se ha tomado</strong>. Antes que la decisión que se ha tomado.</p>
  </li>
  <li>
    <p>⭐️ <strong>El objetivo no es escribir código rápido</strong>. El objetivo es crear software fácil de mantener.</p>
  </li>
  <li>
    <p>⭐️ <strong>No utilices encapsulamiento con los DTOs:</strong> El rol de un DTO es capturar los datos que llegan a una estructurar de datos, o ayudarnos a transformar una estructuras de datos a output. No deberías de utilizarlo para ninguna otra cosa.</p>
  </li>
  <li>
    <p>Está muy bien el análisis de código estático pero los falsos positivos vienen con dicho territorio. Está bien deshabilitar o suprimir avisos específicos pero no lo hagas a la ligera. Al menos, documenta por qué lo has hecho y si puedes, obtén feedback respecto a la decisión</p>
  </li>
  <li>
    <p><strong>⭐️ Smoke tests:</strong> Aunque debas de estar a favor de crear tests automáticos, no deberías de olvidar los tests manuales. De vez en cuando, levanta el sistema y mira si echa fuego.</p>
  </li>
  <li>
    <p>📝 Cuando el código de tus tests es muy grande, eso es un code smell.</p>
  </li>
</ul>

<hr />

<h2 id="4-es-el-tdd-una-ciencia-capítulos-5-y-6">4. ¿Es el TDD una ciencia? (capítulos 5 y 6)</h2>

<ul>
  <li>
    <p>Al escribir tests, utilizamos el método <strong>Red - Green - Refactor</strong>:</p>

    <ul>
      <li>
        <p>🔴 <strong>Red</strong>: escribe un test que falle</p>
      </li>
      <li>
        <p>🟢 <strong>Green</strong>: escribe el mínimo código posible para que el test pase</p>
      </li>
      <li>
        <p>🛠️ <strong>Refactor</strong>: mejora el código sin cambiar su comportamiento</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>¿Por qué TDD es lo más parecido que tenemos a una ciencia?</strong></p>

    <ul>
      <li>
        <p>En el método científico, primero formulas una hipótesis en la forma de una predicción de un resultado no demostrado. Entonces realizas un experimento y mides el resultado. Finalmente, compruebas el resultado con la predicción que hiciste.</p>
      </li>
      <li>
        <p>¿No te recuerda a patrón <strong>Arrange - Act - Assert</strong> de los tests en programación?</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>⭐ Los tests te avisan cuando el sistema está funcionando como no queremos:</strong> Cuando haces modificaciones al código, ¿cómo sabes que no estas cambiando el comportamiento externo? Es muy difícil probar que todos los casos posibles funcionan igual. Pero es muy fácil probar que un caso ya no funciona bien.Si un test automático que has hecho deja de funcionar después de un cambio, ya sabes que has roto algo.</p>
  </li>
  <li>
    <p>Cuantos más tests añadas, mejor describes el sistema que estás probando. Es como ir añadiendo puntos de coordenadas en un mapa para determinar la ubicación del objetivo. Pero para que funcione, tienes que cambiar tu perspectiva con cada medida.</p>
  </li>
  <li>
    <p><strong>⭐ La encapsulación es la idea de que deberías poder interactuar con un objeto sin tener conocimiento de sus detalles de implementación.</strong> Esto te permite hacer cambios en la implementación, es decir, hacer refactor y pensar en el objeto de una forma abstracta.</p>

    <ul>
      <li><strong>⭐ La noción más importante es que un objeto debería de garantizar que nunca va a estar en un estado inválido. Cuya responsabilidad no es de quien lo llama, sino del mismo objeto</strong>, pues es él mismo quien mejor sabe lo que significa que sea válido y cómo garantizarlo</li>
    </ul>
  </li>
  <li>
    <p>️<strong>⭐ La ley de Postel</strong>: <strong>Cuando diseñas la interacción con un objeto, tienes que ser flexible con lo que recibes y conservador con lo que devuelves.</strong> Tienes:</p>

    <ul>
      <li>
        <p>Pre-condiciones: estas son las condiciones que el cliente debe de cumplir antes de interactuar con el objeto. Son sus obligaciones.</p>
      </li>
      <li>
        <p>Post-condiciones: estas son las garantías que el objeto ofrece tras haber interactuado con él. Cuanto mejores sean, mejor.</p>
      </li>
    </ul>
  </li>
</ul>

<hr />

<h2 id="5-la-regla-del-7-capítulo-7">5. La regla del 7 (capítulo 7)</h2>

<ul>
  <li>
    <p>⭐️ <strong>La regla del 7:</strong> Ante la premisa de que los humanos solo pueden tener 7 cosas en la cabeza, es decir, en contexto, deberíamos crear piezas de código que no hagan más de 7 cosas. Decimos 7, pero podrían ser 10 o el número que sea, siempre que se utilice el mismo número.</p>

    <ul>
      <li>Así pues, podríamos acordar una complejidad ciclomática (cyclomatic complexity) de 7, cada vez que un cambio la exceda, lo rechazas.</li>
    </ul>
  </li>
  <li>
    <p>⭐ <strong>Cuantas más lineas de código, peor es el código:</strong> Cuantas más líneas de código añadas, más líneas de código tendrán otras personas que ser capaces de leer y entender.</p>
  </li>
  <li>
    <p><strong>¿Qué es la cohesión en OOP?:</strong> Las cosas que cambian con la misma frecuencia deberían ir juntas. Las cosas que cambian con diferente frecuencia van separadas.</p>

    <ul>
      <li>Piensa en los campos de una instancia de una clase. La mayor cohesión se consigue cuando todos los métodos de la clase utilizan todos los campos de la instancia</li>
    </ul>
  </li>
  <li>
    <p>Se presenta un ejemplo donde un metodo <code class="language-plaintext highlighter-rouge">Validate</code> convierte un dto en una entidad <code class="language-plaintext highlighter-rouge">Reservation</code>. El método <code class="language-plaintext highlighter-rouge">Validate</code> es quien utiliza todo el contexto del dto para checkear (más bien parsear) dicho objeto y si todo va bien, te devuelve un <code class="language-plaintext highlighter-rouge">Reservation</code>, una representación más fuerte de los mismos datos</p>
  </li>
</ul>

<hr />

<h2 id="6-diseño-de-apis-y-cómo-evitar-comentarios-capítulo-8">6. Diseño de APIs y cómo evitar comentarios (capítulo 8)</h2>

<ul>
  <li>
    <p>⭐️ <strong>Diseña APIs de tal forma que sea difícil usarlas mal:</strong> No diseñes una navaja suiza.</p>
  </li>
  <li>
    <p>⭐️ <strong>No digas algo con un comentario cuando lo puedes decir con el nombre de un método:</strong></p>

    <ul>
      <li>
        <p>A ser posible, reemplaza un comentario con un método con un nombre que sea útil.</p>
      </li>
      <li>
        <p>Al igual que los comentarios se vuelven obsoletos rápidamente, también lo hacen los nombres de los métodos. Cuando modifiques la implementación de un método, no olvides actualizar el nombre si es necesario.</p>
      </li>
    </ul>
  </li>
  <li>
    <p>⭐️ <strong>No digas algo con el nombre de un método cuando lo puedes decir con el tipado:</strong> Los nombres de los métodos son útiles pero no tienes que repetir lo que ya te dice el tipado del método.</p>

    <ul>
      <li>
        <ul>
          <li>
            <p><code class="language-plaintext highlighter-rouge">getReservationOrNull(): Reservation?</code> ❌</p>

            <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>* `getReservation(): Reservation?` ✅
</code></pre></div>            </div>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>
    <p>️⭐️ <strong>Hay casos en los que un buen nombre de un método no va a ser suficiente para comunicar toda la intención</strong></p>

    <ul>
      <li>
        <p><strong>Utiliza comentarios</strong> si quieres incluir por qué has decidido implementar el código de una forma en concreto.</p>
      </li>
      <li>
        <p><strong>Utiliza el mensaje del commit</strong> si quieres incluir las consideraciones que has tenido al realizar un cambio en el código.</p>
      </li>
      <li>
        <p><strong>Utiliza documentación o el README</strong> si quieres incluir cómo hacer set up del entorno de desarrollo o la misión que tiene dicho repositorio.</p>
      </li>
    </ul>
  </li>
  <li>
    <p>🚬 Cualquier tonto puede escribir código que una computadora pueda entender. Los buenos programadores escriben código que los humanos puedan entender.</p>
  </li>
  <li>
    <p>⭐️ Hay una forma de hacer código que es <strong><em>Command Query Separation (CQS)</em></strong> que se basa en mantener separados tus Comandos y tus Queries. Así, no devuelves datos en los métodos que tienen side effects y no causas side effects en tus métodos que devuelven datos.</p>
  </li>
</ul>

<hr />

<h2 id="7-mejores-commits-y-las-pull-requests-capítulo-9">7. Mejores commits y las pull requests (capítulo 9)</h2>

<ul>
  <li>
    <p>⭐️ <strong>Los mensajes de commit son el mejor sitio para explicar el porqué un cambio se ha hecho o por qué se ha hecho así.</strong></p>

    <ul>
      <li>
        <p>Pon el mensaje del commit en imperativo.</p>
      </li>
      <li>
        <p>Deja una línea en blanco y pon el resto en la descripción.</p>
      </li>
      <li>
        <p>Regla 50/72: dejar el <em>summary</em> de 50 caracteres y cada línea de la descripción en 72 caracteres.</p>
      </li>
      <li>
        <p>Ejemplo:</p>
      </li>
    </ul>
  </li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Introduce TimeOfDay struct

This makes the roles of the constructor parameters to MaitreD clearer.
A large part of the TimeOfDay type was autogenerated by Visual Studio
</code></pre></div></div>

<ul>
  <li>
    <p>La pregunta principal a la que tiene que contestar una pull request es esta: <strong>¿me parecerá bien tener que mantener estos cambios?</strong></p>
  </li>
  <li>
    <p>⭐️ <strong>Rechaza pull requests grandes.</strong></p>
  </li>
  <li>
    <p>⭐️ <strong>Revisar una pull request entre autor y reviewer no es una buena práctica, porque el reviewer debería ser capaz de leer el código y entenderlo sin ayuda alguna.</strong></p>
  </li>
  <li>
    <p>⭐️ Se puede trabajar tanto en pair programming (2 personas) como en mob programming (3 o más). Esto hace que el código que escribís sea código con el que más de una persona del equipo está de acuerdo, y no reduce la productividad.</p>
  </li>
</ul>

<hr />

<h2 id="8-versionado-e-integración-capítulo-10">8. Versionado e integración (capítulo 10)</h2>

<ul>
  <li>
    <p>⭐️ <strong>Hazte un favor y leete la especificación el Semantic Versioning Specification:</strong> Si, entero. No tardas más de 5 minutos. En resumen, utiliza el esquema <code class="language-plaintext highlighter-rouge">major.minor.patch</code>.</p>

    <ul>
      <li>
        <p>Solo incrementa la <code class="language-plaintext highlighter-rouge">major</code> cuando introduzcas <em>breaking changes</em>.</p>
      </li>
      <li>
        <p>Incrementa la <code class="language-plaintext highlighter-rouge">minor</code> para indicar que has introducido una nueva <em>feature</em>.</p>
      </li>
      <li>
        <p>Incrementar la <code class="language-plaintext highlighter-rouge">patch</code> indica que has arreglado un bug.</p>
      </li>
    </ul>
  </li>
  <li>
    <p>Si estás trabajando en una <em>feature</em> que toma mucho tiempo implementar, te verás tentado a desarrollarla en una <em>feature branch</em>.</p>

    <ul>
      <li>
        <p>No hagas eso, acabarás teniendo lo que se llama un <em>merge hell</em> 🔥</p>
      </li>
      <li>
        <p>En vez de eso, esconde la <em>feature</em> tras un <em>feature flag</em> 🚩 e integra frecuentemente</p>
      </li>
    </ul>
  </li>
</ul>

<hr />

<h2 id="9-técnicas-para-arreglar-bugs-capítulos-11-12">9. Técnicas para arreglar bugs (capítulos 11-12)</h2>

<ul>
  <li>
    <p>Hacer refactor del código en tests es más difícil que hacer refactor del código en producción. Con el código en producción sabes que tus tests cubren la lógica de negocio. Al cambiar los tests tienes que llevar más cuidado porque estas cambiando el comportamiento de tu sistema (sin tener tests que te protejan).</p>
  </li>
  <li>
    <p>⭐️ <strong>Para entender por qué ocurre un problema hay diferentes técnicas:</strong></p>

    <ul>
      <li>
        <p><strong>Utiliza un pato de goma:</strong> explica el problema a un patito. Al explicarlo, quizás encuentras la solución. O mejor aún, pregunta en Stack Overflow.</p>
      </li>
      <li>
        <p><strong>Date un descanso, ve a por café o a por aire fresco</strong>. Muchas veces ese reseteo despeja la mente y vuelves con un enfoque fresco.</p>
      </li>
    </ul>
  </li>
  <li>
    <p>En el desarrollo de software, “más tarde” significa nunca. Cuando aparece un bug, identificarlo debería ser tu prioridad. Para lo que estés haciendo y arréglalo.</p>
  </li>
  <li>
    <p>⭐️ <strong>Utiliza la técnica de bisection para arreglar bugs:</strong></p>

    <ol>
      <li>
        <p>Encuentra una manera de detectar o reproducir el problema.</p>
      </li>
      <li>
        <p>Quita la mitad del código.</p>
      </li>
      <li>
        <p>Si el problema aún está presente, repite el paso 2</p>
      </li>
      <li>
        <p>Si el problema desaparece, restaura el código que has quitado.</p>
      </li>
    </ol>
  </li>
  <li>
    <p>⭐️ <code class="language-plaintext highlighter-rouge">git bisect</code>: Comando súper útil al que le das un rango (<code class="language-plaintext highlighter-rouge">git bad</code> y <code class="language-plaintext highlighter-rouge">git good</code>) e itera en los commits intermedios para localizar el error.</p>
  </li>
  <li>
    <p>⭐️ <strong>Aprende y utiliza estas prácticas universales, ya que no puedes utilizar herramientas de debugging en el entorno de producción.</strong></p>
  </li>
</ul>

<hr />

<h2 id="10-cqrs-funciones-puras-y-buenos-logs-capítulo-13">10. CQRS, funciones puras y buenos logs (capítulo 13)</h2>

<ul>
  <li>
    <p>Cuanto más compones objetos mediante anidamiento, menor parte de esta composición cabe en tu cerebro al mismo tiempo.</p>

    <p><img src="/assets/img/posts/code-that-fits-in-your-head/c7ade05a-6f45-4307-8877-0cdd20014fe5.png" alt="" /></p>
  </li>
  <li>
    <p>⭐️ <strong>Sigue el principio de Command Query Separation. No dejes que tus queries tengan efectos secundarios. Si tu función es</strong> <code class="language-plaintext highlighter-rouge">TrySave</code>, lo cual indica que es un comando, no dejes que devuelva un boolean “por la cara”.</p>
  </li>
  <li>
    <p>⭐️ <strong>Los métodos deterministas son aquellos en los que puedes calcular el resultado con solo saber el input (funciones puras).</strong></p>

    <ul>
      <li>
        <p>Tienen propiedades muy deseadas: puedes abstraerte de lo que hace la función y solo preocuparte del resultado cuando leas el código.</p>
      </li>
      <li>
        <p>⭐️ <strong>Para funciones puras, la programación orientada a funciones es el rey.</strong></p>
      </li>
    </ul>
  </li>
  <li>
    <p>⭐️ <strong>Mantén las queries no-deterministas y con efectos colaterales cerca de la frontera de tu sistema y haz uso de funciones puras para escribir lógica compleja.</strong></p>
  </li>
  <li>
    <p>⭐️ <strong>En cuanto a los logs:</strong></p>

    <ul>
      <li>
        <p><strong>Loguea los detalles de cada petición HTTP y su respuesta.</strong> También toda interacción con la base de datos, incluyendo los inputs y el resultado entero.</p>
      </li>
      <li>
        <p><strong>Loguea todas las funciones impuras pero nada más.</strong> Loguea todo aquello que no puedas reproducir: fechas, hora local, números aleatorios, lectura de ficheros, etc.vi</p>
      </li>
    </ul>
  </li>
</ul>

<hr />

<h2 id="11-las-dailys-los-descansos-y-escribir-documentación-capítulo-14">11. Las dailys, los descansos y escribir documentación (capítulo 14)</h2>

<ul>
  <li>
    <p><strong>Las dailys deberían ser:</strong> qué hice ayer, qué voy a hacer hoy y si tengo algún bloqueo.</p>
  </li>
  <li>
    <p>⭐️ <strong>Trabaja en intervalos de tiempo delimitados como de 25 minutos con descansos de 5.</strong> No, no es exactamente el método pomodoro 🍅</p>

    <ul>
      <li>
        <p>Es importante que al tomarte estos descansos te levantes, des una vuelta si puedes o lo que sea</p>
      </li>
      <li>
        <p>Las ideas o los eureka! Suelen pasar cuando estas haciendo deporte, corriendo o fregando los platos. No suelen ocurrir delante de la pantalla, sino cuando estás de pie</p>
      </li>
    </ul>
  </li>
  <li>
    <p>⭐️ <strong>Las reuniones no escalan, la documentación sí:</strong> En vez de poner una reunión cada vez que tengas que transferir conocimiento, escríbelo en un documento.</p>
  </li>
  <li>
    <p>El autor recomienda actualizar las dependencias regularmente, y así evitar actualizaciones grandes que tengan muchos breaking changes.</p>
  </li>
  <li>
    <p>Ley de Conway: cualquier organización que diseñe un sistema producirá inevitablemente un diseño que es copia de la estructura de comunicación de la organización.</p>
  </li>
</ul>

<hr />

<h2 id="12-seguridad-y-property-based-testing-capítulo-15">12. Seguridad y property-based testing (capítulo 15)</h2>

<ul>
  <li>
    <p>⭐️ <strong>La seguridad en el software es como los seguros:</strong> no quieres pagar por uno hasta que te arrepientes de no tenerlo.</p>
  </li>
  <li>
    <p>Usa el acrónimo <strong>STRIDE</strong> como checklist: <em>Spoofing, Tampering, Repudiation, Information disclosure, Denial of service y Elevation of privilege</em>.</p>
  </li>
  <li>
    <p>⭐️ <strong>Property-based testing:</strong> testear campos por sus propiedades y no por valores concretos.</p>

    <ul>
      <li>
        <p>Si quieres incluir un test donde se pruebe con un valor negativo, ¿por qué utilizar el valor -1 en concreto?</p>
      </li>
      <li>
        <p>¿Qué pasaría si hubiese un framework que pudiese producir números negativos arbitrarios?</p>
      </li>
      <li>
        <p>Eso es el property-based testing (e.g: FsCheck lib)</p>
      </li>
    </ul>
  </li>
  <li>
    <p>⭐ <strong>Behavioural Code Analysis:</strong> extrae información de Git para identificar patrones y problemas visibles solo con el transcurso del tiempo.</p>
  </li>
</ul>

<hr />

<h2 id="13-organización-de-directorios-en-un-proyecto-capítulo-16">13. Organización de directorios en un proyecto (capítulo 16)</h2>

<ul>
  <li>
    <p>⭐️ <strong>¿Cómo debería organizar los ficheros?</strong></p>

    <ul>
      <li>
        <p>➡️ <strong>Simplemente pon todos los ficheros en una carpeta.</strong></p>
      </li>
      <li>
        <p>Utiliza subcarpetas sencillamente para organizar el código</p>
      </li>
      <li>
        <p>Los sistemas de ficheros son jerarquías (árboles) donde cada nodo solo puede tener un padre. Si pones algo en <code class="language-plaintext highlighter-rouge">Controllers</code>, no puede estar a la vez en <code class="language-plaintext highlighter-rouge">Calendar</code>.</p>
      </li>
    </ul>
  </li>
  <li>
    <p>Si quieres encontrar ficheros, utiliza las funcionalidades de navegación de tu IDE.</p>
  </li>
</ul>

<hr />

<h2 id="conclusión-personal">Conclusión personal</h2>

<p>No espero que este sea el post más entretenido que he escrito jamás, es más, ¡espero que nadie esté perdiendo el tiempo leyendo esto! Aunque aún me falta mucha experiencia por ganar en el desarrollo del software, hay ideas en este libro que me han cautivado por completo:</p>

<ul>
  <li>
    <p><strong>El código como documento:</strong> Enfocarlo todo a una buena lectura tiene todo el sentido del mundo. Al fin y al cabo, el código es un documento que alguien va a leer y debe entender qué está pasando sin esfuerzo.</p>
  </li>
  <li>
    <p><strong>La regla de las 7 cosas:</strong> Esta limitación cognitiva me parece una de las lecciones más potentes. Resuena mucho con lo que se enseña en otras áreas, por ejemplo, en bibliografía sobre cómo mejorar presentaciones, se recomienda no mostrar más de 4 elementos en pantalla para no saturar a la audiencia. En el código, igual.</p>
  </li>
  <li>
    <p><strong>El</strong> <strong>Property-based testing:</strong> había escuchado sobre este pero nunca lo he visto en los proyectos en los que he trabajado. Tengo ganas de probarlo en algún repo que tenga por ahí.</p>
  </li>
</ul>

<p>Las ideas de Mark Seemann resuenan con mi manera de entender el software y creo que de ahí nace mi entusiasmo por este libro. Si algo de esto te ha hecho clic, te invito a que le des una oportunidad a la lectura completa.</p>

<p>Si me quieres comentar cualquier cosa o conectar conmigo: <a href="https://www.linkedin.com/in/juanjorequena/">https://www.linkedin.com/in/juanjorequena/</a></p>
]]></content:encoded>
        <pubDate>Sun, 11 Jan 2026 15:29:19 +0100</pubDate>
        <link>https://blog.juanjorequena.com/code-that-fits-in-your-head/</link>
        <guid isPermaLink="true">https://blog.juanjorequena.com/code-that-fits-in-your-head/</guid>
        <category>coding</category>
      </item>
    
      <item>
        <title>💾Qué son las transacciones ACID y por qué siguen importando</title>
        <dc:creator><![CDATA[Juanjo Requena]]></dc:creator>
        <description>Repaso de las propiedades ACID en bases de datos y qué sistemas las implementan hoy en día. - 🗒️Repaso: propiedades ACID en bases de datos Lo primero que debemos aclarar es que ACID no son propiedades de la base de datos en sí, sino de las transacciones que esta gestiona. Una transacción en una base de datos es una secuencia de operaciones que podemos tratar como una sola...</description>
        <content:encoded><![CDATA[<h2 id="️repaso-propiedades-acid-en-bases-de-datos">🗒️Repaso: propiedades ACID en bases de datos</h2>

<p>Lo primero que debemos aclarar es que <strong>ACID no son propiedades de la base de datos en sí, sino de las transacciones que esta gestiona.</strong> Una transacción en una base de datos es una secuencia de operaciones que podemos tratar como una sola unidad indivisible. Pues bien, las transacciones ACID van a cumplir con las siguientes propiedades:</p>

<h3 id="atomicidad-atomicity">🟣Atomicidad (atomicity)</h3>

<p>Cuando se ejecuta una transacción, esta va a ser realizada por completo. Si no es ejecutada por completo por algún problema, entonces será rechazada y revertida. Por lo tanto, si tenemos que una operación dentro de nuestra transacción falla, cada operación realizada va a ser revertida. Todo o nada.</p>

<p>➡️ Imagina que estás reservando un vuelo. Esta operación consisten en dos pasos:</p>

<ol>
  <li>
    <p>Crear la reserva del vuelo.</p>
  </li>
  <li>
    <p>Restar -1 asiento al número de asientos disponibles.</p>
  </li>
</ol>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">BEGIN</span><span class="p">;</span>
  <span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">bookings</span> <span class="p">(</span><span class="n">flight_id</span><span class="p">,</span> <span class="n">passenger_id</span><span class="p">,</span> <span class="n">seat</span><span class="p">)</span> <span class="k">VALUES</span> <span class="p">(</span><span class="s1">'IB123'</span><span class="p">,</span> <span class="mi">42</span><span class="p">,</span> <span class="s1">'12A'</span><span class="p">);</span>
  <span class="k">UPDATE</span> <span class="n">flights</span> <span class="k">SET</span> <span class="n">available_seats</span> <span class="o">=</span> <span class="n">available_seats</span> <span class="o">-</span> <span class="mi">1</span> <span class="k">WHERE</span> <span class="n">flight_id</span> <span class="o">=</span> <span class="s1">'IB123'</span><span class="p">;</span>
<span class="k">COMMIT</span><span class="p">;</span>
</code></pre></div></div>

<p>La atomicidad asegura que o se ejecutan ambas operaciones o que ninguna lo hace. Si el sistema se cae justo después de crear la reserva pero antes de reducir el número de asientos disponibles, la base de datos revertirá la transacción entera.</p>

<h3 id="consistencia-consistency">🔵Consistencia (consistency)</h3>

<p>Las transacciones transforman el conjunto de datos de un estado consistente a otro, garantizando que cuando se complete, se cumplan todas las restricciones definidas en el sistema.</p>

<p>➡️ Por ejemplo, digamos que tenemos una regla en nuestra base de datos para que el número de asientos disponibles en un vuelo nunca sea negativo:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">flights</span> <span class="p">(</span>
    <span class="n">flight_id</span> <span class="nb">TEXT</span> <span class="k">PRIMARY</span> <span class="k">KEY</span><span class="p">,</span>
    <span class="n">available_seats</span> <span class="nb">INT</span> <span class="k">CHECK</span> <span class="p">(</span><span class="n">available_seats</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Si la transacción hiciese que el número de asientos disponibles fuese negativo, la base de datos rechazaría la transacción completa.</p>

<div class="callout"><span class="callout-emoji">🤔</span><div class="callout-text">Pero ¿esta consistencia no tiene nada que ver con la del <a href="/cap/">teorema CAP</a>? ¡En efecto! Es muy confuso pero se utiliza el mismo término para diferentes definiciones. En ACID, la consistencia quiere decir que la base de datos siempre seguirá ciertas reglas y restricciones. En el teorema CAP, la consistencia quiere decir que la base de datos siempre devolverá el resultado correcto, incluso si eso significa sacrificar la disponibilidad o tolerancia a particiones.</div></div>

<h3 id="aislamiento-isolation">🟢<strong>Aislamiento (isolation)</strong></h3>

<p>Las transacciones pueden ejecutarse en paralelo sin afectar la una a la otra. Es decir, una transacción no puede acceder a los cambios intermedios de otra mientras se ejecuta.</p>

<div class="callout"><span class="callout-emoji">⚠</span><div class="callout-text"><strong>¡Cuidado! </strong>Hemos dicho que las transacciones <strong>pueden </strong>ejecutarse en paralelo sin afectar la una a la otra. Eso no quiere decir que este vaya a ser el comportamiento por defecto para las transacciones en dicha base de datos. Tendrás que elegir el nivel de aislamiento que quieras para las transacciones para que esto se cumpla.</div></div>

<p>La mayoría de bases de datos permiten 4 niveles diferentes de aislamiento:</p>

<ul>
  <li>
    <p><strong>READ UNCOMMITED</strong>: pueden ver cambios de otras transacciones que aún no han hecho commit (se usa raras veces).</p>
  </li>
  <li>
    <p><strong>READ COMMITED</strong>: solo pueden ver cambios de transacciones commiteadas (por defecto en PostgreSQL).</p>
  </li>
  <li>
    <p><strong>REPEATABLE READ</strong>: si lees el mismo dato varias veces, aunque otra transacción haga un cambio y commit, seguirá leyendo el mismo dato (por defecto en MySQL).</p>
  </li>
  <li>
    <p><strong>SERIALIZABLE</strong>: provee del aislamiento más fuerte, las transacciones se ejecutan una tras otra en orden.</p>
  </li>
</ul>

<p><img src="/assets/img/posts/acid/5725f8d3-eb70-49e1-bb08-750e8c0c08c9.png" alt="" /></p>

<p>➡️ En nuestro ejemplo de reservas de vuelos, supongamos que solo queda <strong>un asiento disponible</strong> para el vuelo <code class="language-plaintext highlighter-rouge">IB123</code>.</p>

<table>
  <thead>
    <tr>
      <th>flight_id</th>
      <th>available_seats</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>IB123</td>
      <td>1</td>
    </tr>
  </tbody>
</table>

<p>Con un nivel de aislamiento <strong>READ COMMITTED</strong>, podría ocurrir que dos transacciones intenten reservar ese asiento al mismo tiempo. Ambas leen que el asiento está disponible. La primera transacción termina primero y hace commit, reduciendo el número de asientos disponibles a 0.</p>

<p>Al hacer commit, la segunda transacción también disminuye el contador de asientos a 0, provocando un <strong>overbooking</strong>: el mismo asiento se ha vendido dos veces.</p>

<p><img src="/assets/img/posts/acid/71992814-8d99-43b4-9d46-b2e7d163fa61.png" alt="" /></p>

<p>Si en su lugar usamos un aislamiento <strong>SERIALIZABLE</strong>, la base de datos evita automáticamente este conflicto: aborta una de las transacciones que interfiere con la otra. La transacción abortada puede ser reintentada de manera segura, asegurando que nunca se reserve más de un asiento de los disponibles.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">BEGIN</span><span class="p">;</span>
<span class="k">SET</span> <span class="n">TRANSACTION</span> <span class="k">ISOLATION</span> <span class="k">LEVEL</span> <span class="k">SERIALIZABLE</span><span class="p">;</span>
<span class="c1">-- o REPEATABLE READ</span>
<span class="c1">-- o SERIALIZABLE</span>
<span class="k">COMMIT</span><span class="p">;</span>
</code></pre></div></div>

<p>Esto no significa que sea la mejor solución para este caso, ya que habilitar el modo SERIALIZABLE puede afectar el rendimiento. Sin embargo, en este caso sí garantizaría que la operación funcione de forma segura.</p>

<h3 id="durabilidad-durability">🟠Durabilidad (durability)</h3>

<p>Cuando una transacción es completada, los datos deben persistir en el sistema aunque haya un fallo en el servidor. Los datos nunca pueden perderse.</p>

<p>➡️ En nuestro sistema de reserva de vuelos, si la transacción se completa, el asiento queda reservado incluso si el servidor se apaga después. La confirmación del <code class="language-plaintext highlighter-rouge">COMMIT</code> asegura que la reserva esté escrita en disco.</p>

<h2 id="por-qué-acid-sigue-importando">📢Por qué ACID sigue importando</h2>

<p>Al elegir qué base de datos utilizar para tu sistema, es importante valorar si priorizamos más la <strong>disponibilidad</strong> o la <strong>consistencia</strong>. Como vimos en <a href="/cap/"><em>¿Qué es el teorema CAP?</em></a>, en sistemas distribuidos normalmente hay que priorizar una propiedad sobre la otra, al menos en cierta parte del sistema. Por ello, elegir una base de datos que <strong>cumpla con las propiedades ACID</strong> es una excelente opción cuando la <strong>consistencia</strong> es vital (tal como se define en el teorema CAP).</p>

<p>Considera los siguientes escenarios:</p>

<ul>
  <li>
    <p><strong>Transacciones financieras:</strong> aquí es imprescindible contar con ACID para evitar perder transacciones de dinero o realizar dos veces el mismo pago.</p>
  </li>
  <li>
    <p><strong>Los likes en redes sociales:</strong> seguramente una <a href="https://en.wikipedia.org/wiki/Eventual_consistency">eventual consistency</a> será suficiente, ya que por perder un like no va a pasar nada.</p>
  </li>
  <li>
    <p><strong>Autenticación de usuarios:</strong> probablemente requieras ACID para prevenir problemas de seguridad.</p>
  </li>
  <li>
    <p><strong>Análisis de datos:</strong> aquí quizás quieras priorizar el performance antes que una fuerte consistencia.</p>
  </li>
</ul>

<p><strong>Así que la respuesta es: sí, ACID sigue importando.</strong> Cuando te encuentres en un caso donde priorices la consistencia de los datos, piensa en ACID como una herramienta que te va a ayudar a conseguir esa fuerte consistencia.</p>

<h2 id="bases-de-datos-que-soportan-acid-hoy-en-día">📅Bases de datos que soportan ACID hoy en día</h2>

<p>Tradicionalmente, soportar las propiedades ACID era una característica de muchas bases de datos relacionales como <strong>MySQL o PostgreSQL</strong>. Sin embargo, en los últimos años, muchas bases de datos NoSQL también han comenzado a dar soporte parcial o completo a transacciones ACID. Entre las más famosas:</p>

<ul>
  <li>
    <p><strong>Cassandra</strong>: ofrece transacciones atómicas, aisladas y duraderas con una consistencia a elegir entre eventual o fuerte según como se quieran las transacciones.</p>
  </li>
  <li>
    <p><strong>DynamoDB</strong>: ofrece transacciones ACID desde 2018.</p>
  </li>
  <li>
    <p><strong>CockroachDB</strong>: tiene soporte complete para transacciones ACID distribuidas.</p>
  </li>
  <li>
    <p><strong>MongoDB</strong>: ofrece transacciones multi-document.</p>
  </li>
</ul>

<p>Así que no pienses que si quieres transacciones que cumplan con propiedades ACID te tengas que ir a una base de datos relacional, porque muchas NoSQL también lo soportan.</p>

<h3 id="fuentes">Fuentes:</h3>

<ul>
  <li>
    <p><a href="https://www.goodreads.com/book/show/23463279-designing-data-intensive-applications">Kleppmann, Martin. <em>Designing Data-Intensive Applications : The Big Ideas behind Reliable, Scalable, and Maintainable Systems</em>. Sebastopol, CA, O’Reilly Media, 2017.</a></p>
  </li>
  <li>
    <p><a href="https://www.hellointerview.com/learn/system-design/deep-dives/postgres">https://www.hellointerview.com/learn/system-design/deep-dives/postgres</a></p>
  </li>
</ul>
]]></content:encoded>
        <pubDate>Thu, 21 Aug 2025 01:03:38 +0200</pubDate>
        <link>https://blog.juanjorequena.com/acid/</link>
        <guid isPermaLink="true">https://blog.juanjorequena.com/acid/</guid>
        <category>ACID Transactions</category><category>Databases</category>
      </item>
    
      <item>
        <title>⚖️¿Qué es Consistent Hashing?</title>
        <dc:creator><![CDATA[Juanjo Requena]]></dc:creator>
        <description>La técnica que utilizan Cassandra y DynamoDB para rebalancear datos en sistemas distribuidos - Un poco de contexto Conforme pasa el tiempo, surgen problemas que afrontar en nuestra base de datos: La cantidad de queries por segundo aumenta, con lo que necesitas añadir más CPUs para poder aguantar la carga. La cantidad de datos aumenta, con lo que necesitas añadir más almacenamiento en discos...</description>
        <content:encoded><![CDATA[<h3 id="un-poco-de-contexto">Un poco de contexto</h3>

<p>Conforme pasa el tiempo, surgen problemas que afrontar en nuestra base de datos:</p>

<ul>
  <li>
    <p>La cantidad de queries por segundo aumenta, con lo que necesitas añadir más CPUs para poder aguantar la carga.</p>
  </li>
  <li>
    <p>La cantidad de datos aumenta, con lo que necesitas añadir más almacenamiento en discos o RAM.</p>
  </li>
  <li>
    <p>Cuando un servidor falla y es necesario que otros servidores asuman sus responsabilidades. Para ello tendremos que mover todos esos datos y peticiones de un nodo a otro nuevo.</p>
  </li>
</ul>

<p>➡️ <strong>El proceso de mover toda esta carga de un nodo a otro dentro del clúster se conoce como rebalanceo.</strong></p>

<p>No importa el esquema que hayas utilizado partición de la base de datos, hay una serie de requisitos mínimos que se buscan al hacer dicho rebalanceo:</p>

<ul>
  <li>
    <p>Después del rebalanceo, la carga (datos, peticiones de lectura y escritura) debe de ser distribuida de manera equitativa entre los nodos del clúster.</p>
  </li>
  <li>
    <p>Mientras ocurre el rebalanceo, la base de datos debe de seguir aceptando peticiones de lectura y escritura.</p>
  </li>
  <li>
    <p><strong>No deberían de moverse más datos de los necesarios al realizar el balanceo. Así conseguiremos un rebalanceo más rápido y minimizaremos la carga por operaciones de E/S en disco y de red.</strong></p>
  </li>
</ul>

<p>Sabiendo que estas son las cualidades que se buscan para rebalancear, vamos ahora a introducir un ejemplo.</p>

<p>Imaginemos que tienes un sistema montado con tu cliente, servidor y base de datos. Pero tu plataforma se ha hecho muy popular y tus servidores pueden escalar horizontalmente tranquilamente, pero tu base de datos ya no da abasto. Tienes que distribuir los datos que había en la base de datos entre diferentes nodos, vamos, lo que se conoce como sharding.</p>

<p>Este sistema se vería tal que así:</p>

<p><img src="/assets/img/posts/consistent-hashing/d232b752-5315-4b27-9dd5-ef6b1ee62710.png" alt="" /></p>

<p>Lo que tenía antes en una sola instancia de mi base de datos, ahora lo tengo que repartir en 3 nodos separados. ¿Cómo lo hago? ¿Qué criterio utilizo para saber en qué base de datos tengo que guardar un dato u otro? Es decir:</p>

<h2 id="qué-estrategia-de-rebalanceo-utilizo">¿Qué estrategia de rebalanceo utilizo?</h2>

<h3 id="un-primer-intento-módulo-n">Un primer intento: módulo N</h3>

<p>El método más simple sería calcular el módulo (%) del hash de la key. Por ejemplo, si nuestra función para calcular el hash de una key devuelve un número en base 10, podríamos calcular el módulo N de ese número, siendo N el número de nodos que tenemos en total.</p>

<p>El algoritmo se vería tal que así:</p>

<ul>
  <li>
    <p>Primero, cogemos el id de la entidad y lo pasamos por la función hash que tenemos, lo cual lo convierte a un número.</p>
  </li>
  <li>
    <p>Ahora, cogemos ese número y calculamos el módulo (%) según el número de nodos que tengamos en nuestra base de datos.</p>
  </li>
  <li>
    <p>El resultado nos indica donde guardar dicho dato.</p>
  </li>
</ul>

<p>Un ejemplo donde queremos calcular donde van 3 keys y tenemos 3 bases de datos sería:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ID #15→ hash(15)→ 32→ 32 % 3 = 2 → Database 2
ID #99→ hash(99)→ 27→ 27 % 3 = 1 → Database 1
ID #66→ hash(66)→ 69→ 69 % 3 = 0 → Database 0
</code></pre></div></div>

<p>El problema con esta manera de particionar la base de datos es que si el número de nodos cambia, es decir, si la N cambia, vamos a tener que mover la mayor parte de las keys.</p>

<p>Por ejemplo, digamos que hash(12345)= 6. Si tenemos 3 nodos como en nuestro ejemplo, la key se asignará a la base de datos número 0 (porque 6 mod 3 = 0). Cuando añadas una base de datos más y tengas 4, tendrás que mover dicha key al nodo 2 (6 mod 4 = 2). Pero es que cuando añadas otra instancia más y tengas 5 nodos, tendrás que moverla al nodo 1 (6 mod 5 = 1). Y no es solo esa key, tendrás que mover de un lado a otro las keys de diferentes nodos cada vez que añadas o quites una base de datos.</p>

<p>Esto hace que el rebalanceo sea muy costoso y hace que movamos más datos de los necesarios durante el rebalanceo.</p>

<h3 id="tener-un-número-fijo-de-particiones">Tener un número fijo de particiones</h3>

<p>Una solución común es crear más particiones que número de nodos, y asignar varias particiones a cada nodo. Por ejemplo, nuestro clúster de 3 nodos podríamos dividirlo en 300 particiones y así se le asignarían 100 a cada nodo. Esto va a hacer que sea mucho más fácil rebalancear los datos cuando se añadan o eliminen nodos.</p>

<p>Cuando añadas un nodo, dicho nodo va a simplemente robar unas cuantas particiones del cluster. Y cuando quites un nodo, pues lo mismo pero al contrario. Tienes que redistribuir las particiones entre los nodos existentes.</p>

<p><img src="/assets/img/posts/consistent-hashing/541a426f-9b11-45c0-9022-387071afb393.png" alt="" /></p>

<p>Solo las particiones enteras van a ser movidas entre nodos. El número de particiones no cambia, como tampoco cambia la partición que tiene asignada cada key. Mientras se hace la migración, las operaciones funcionan como en la configuración antigua hasta que se finaliza el cambio.</p>

<p>Aunque existe la posibilidad de dividir o combinar particiones, en la práctica muchas bases de datos eligen tener un número de particiones fijas desde que montas el sistema. Lo complicado es saber el número de particiones que vas a necesitar cuando tu sistema crezca. Pocas y largas particiones van a dificultar el balanceo, muchas particiones cortas van a generar mucho overhead. Lo ideal claro está, es encontrar un punto intermedio intentando predecir cómo va a crecer tu sistema.</p>

<p>Esta estrategia de balanceo es la que utilizan sistemas como Elasticsearch y Couchbase.</p>

<h2 id="consistent-hashing">Consistent hashing</h2>

<p>La última estrategia que vamos a presentar y en la que nos vamos a centrar se denomina <strong>consistent hashing</strong>. La clave principal es que vamos a distribuir nuestros datos y las bases de datos que disponemos en un anillo circular.</p>

<ol>
  <li>Supongamos que, al aplicar el hashing a nuestras keys, los valores resultantes puede ir del 0 al 100.</li>
</ol>

<p><img src="/assets/img/posts/consistent-hashing/21948f4d-b55f-49cf-8ad5-f7fd6c8e4cef.png" alt="" /></p>

<ol>
  <li>Cuando ponemos dichos valores en un anillo circular, donde la posición final va justo antes de la primera posición, nos quedaría algo así.</li>
</ol>

<p><img src="/assets/img/posts/consistent-hashing/15558848-0489-4d99-8716-3a49b8ddf192.png" alt="" /></p>

<ol>
  <li>Ahora, distribuimos nuestros nodos de bases de datos a lo largo del anillo. Como tenemos 3 nodos, vamos a colocarlos en las posiciones 0, 33 y 66.</li>
</ol>

<p><img src="/assets/img/posts/consistent-hashing/b157cf17-580a-43cd-b421-253f45f783fb.png" alt="" /></p>

<ol>
  <li>Y finalmente, solo nos queda distribuir nuestros datos. Para saber en qué nodo van nuestros datos, tenemos que calcular el hash de dicho dato y, en vez de hacer el mod 3 de dicho resultado, buscaremos el valor de dicho hash en el anillo y nos movemos siguiendo el sentido de las agujas del reloj hasta que encontremos un nodo. Si tenemos una key = 115 y hash(115) = 93, el nodo donde irá dicho dato es la base de datos 1.</li>
</ol>

<p><img src="/assets/img/posts/consistent-hashing/b750965f-317a-40cf-8634-a246fec66213.png" alt="" /></p>

<h3 id="cómo-añadir-y-quitar-nodos">Cómo añadir y quitar nodos</h3>

<p>Vimos anteriormente que con la estrategia módulo N, al quitar o añadir nodos tendríamos que mover la mayoría de keys de sitio. Ahora que utilizamos consistent hashing, esto no va a ser así. Dado que cada servidor va a ser responsable de un arco de la circunferencia, añadir un servidor va a ser tan simple como mover ligeramente cada servidor en el anillo. De esta manera, solo un pequeño subconjunto de keys van serán reasignadas a un servidor diferente del que estaban.</p>

<p><img src="/assets/img/posts/consistent-hashing/82abd3d0-3164-464d-8ee1-e78fd00b1fd0.png" alt="" /></p>

<p>Así, conseguiremos reducir el número de datos que se mueven durante el rebalanceo y, por lo tanto, disminuirán el número de cache misses durante este. Quitar un nodo del anillo será la misma operación que añadir un nodo pero a la inversa.</p>

<p>Esta solución ya es mucho mejor a lo que teníamos con la estrategia de modulo N. Pero hay una manera incluso mejor de repartir los nodos, una forma que al realizar el rebalanceo, consigue una redistribución más uniforme de las keys y generar un menor impacto en nuestro anillo.</p>

<p>Y esa manera es:</p>

<h3 id="virtual-nodes">Virtual nodes</h3>

<p>Los nodos virtuales (virtual nodes) son una extensión del consistent hashing que hace el sistema más resistente a distribuciones desequilibradas de datos en el anillo. La idea consiste en que cada base de datos va a ser representada por más de un nodo en el anillo. Esto lo podríamos conseguir con cualquiera de las siguientes 2 maneras:</p>

<ul>
  <li>
    <p>Añadiendo un prefijo a la base de datos al calcular su hash. Así, sin nodos virtuales estábamos calculando hash(DB 1), pero ahora tendríamos que calcular hash(DB 1_0), hash(DB 1_1), hash(DB 1_2), etc.</p>
  </li>
  <li>
    <p>Calcular la posición de los nodos de cada base de datos aplicando más de una función hash. Es decir, para saber la posición “*_0” utilizaríamos una función hash, para la posición “*_1” utilizaríamos otra función diferente y así.</p>
  </li>
</ul>

<p><img src="/assets/img/posts/consistent-hashing/08765a23-403b-4b4d-a901-a4a21864bd08.png" alt="" /></p>

<p>En el caso de que la base de datos 4 falle:</p>

<ul>
  <li>
    <p>Las keys en “BD 4_1” serán distribuidas al nodo “2_2” así que irán a la base de datos 2.</p>
  </li>
  <li>
    <p>Las keys en “BD 4_3” serán distribuidas al nodo “3_2” así que irán a la base de datos 3.</p>
  </li>
  <li>
    <p>Las keys en “BD 4_2” serán distribuidas al nodo “1_3” así que irán a la base de datos 1.</p>
  </li>
  <li>
    <p>Las keys en “BD 4_0” serán distribuidas al nodo “1_2” así que irán a la base de datos 1.</p>
  </li>
</ul>

<p>Como vemos, esto hace que la carga de una base de datos caída se distribuya de manera más equitativa entre los diferentes nodos físicos. Cuantos más nodos virtuales uses por base de datos, más uniforme será la redistribución de la carga.</p>

<h2 id="conclusión">Conclusión</h2>

<p>Con la llegada de los sistemas distribuidos, el consistent hashing es uno de esos algoritmos que solucionó un problema fundamental de manera elegante: cómo distribuir las carga entre bases de datos para luego minimizar la cantidad de datos que se redistribuyen al cambiar el número de servidores. Y todo esto simplemente poniendo los servidores en un anillo y siguiendo el sentido de las agujas del reloj.</p>

<p>Este algoritmo está integrado a día de hoy en tecnologías que utilizamos como Cassandra, DynamoDB o CDNs. Quizás no tendremos que implementarlo en los sistemas que construyamos en nuestro día a día, pero saber cómo funciona por adentro nos ayuda a tomar mejores decisiones cuando diseñemos sistemas distribuidos donde necesitemos particionar los datos.</p>

<h3 id="fuentes">Fuentes</h3>

<ul>
  <li>
    <p><a href="https://www.hellointerview.com/learn/system-design/deep-dives/consistent-hashing">https://www.hellointerview.com/learn/system-design/deep-dives/consistent-hashing</a></p>
  </li>
  <li>
    <p><a href="https://www.goodreads.com/book/show/23615147-web-scalability-for-startup-engineers">Artur Ejsmont. <em>Web Scalability for Startup Engineers : Tips &amp; Techniques for Scaling Your Web Application</em>. New York, Mcgraw-Hill Education, 2015.</a></p>
  </li>
  <li>
    <p><a href="https://www.goodreads.com/book/show/54109255-system-design-interview-an-insider-s-guide">Xu, Alex. System Design Interview : An Insider’s Guide. 2020.</a></p>
  </li>
  <li>
    <p><a href="https://www.goodreads.com/book/show/23463279-designing-data-intensive-applications">Kleppmann, Martin. <em>Designing Data-Intensive Applications : The Big Ideas behind Reliable, Scalable, and Maintainable Systems</em>. Sebastopol, CA, O’Reilly Media, 2017.</a></p>
  </li>
</ul>
]]></content:encoded>
        <pubDate>Thu, 07 Aug 2025 07:55:46 +0200</pubDate>
        <link>https://blog.juanjorequena.com/consistent-hashing/</link>
        <guid isPermaLink="true">https://blog.juanjorequena.com/consistent-hashing/</guid>
        <category>consistent hashing</category><category>rebalancing</category><category>distributed system</category>
      </item>
    
      <item>
        <title>📊¿Qué es el teorema CAP?</title>
        <dc:creator><![CDATA[Juanjo Requena]]></dc:creator>
        <description>Este teorema dice que un sistema distribuido solo puedes garantizar simultáneamente dos de estas tres propiedades: Consistency (consistencia) Availability (disponibilidad) Partition tolerance (tolerancia a particiones) ¿Pero qué significan estas propiedades? Consistencia Todos los nodos/usuarios del sistema ven los mismos datos al mismo tiempo. Cuando una escritura se realiza en un...</description>
        <content:encoded><![CDATA[<p>Este teorema dice que un sistema distribuido solo puedes garantizar simultáneamente dos de estas tres propiedades:</p>

<ul>
  <li>
    <p><strong>Consistency</strong> (consistencia)</p>
  </li>
  <li>
    <p><strong>Availability</strong> (disponibilidad)</p>
  </li>
  <li>
    <p><strong>Partition tolerance</strong> (tolerancia a particiones)</p>
  </li>
</ul>

<h3 id="pero-qué-significan-estas-propiedades">¿Pero qué significan estas propiedades?</h3>

<h4 id="consistencia">Consistencia</h4>

<p>Todos los nodos/usuarios del sistema ven los mismos datos al mismo tiempo. Cuando una escritura se realiza en un nodo, todas las lecturas siguientes van a devolver el valor actualizado.</p>

<h4 id="disponibilidad">Disponibilidad</h4>

<p>Cada petición realizada a un nodo disponible recibe una respuesta. Sin tener la garantía de que contenga la versión más actualizada de los datos.</p>

<h4 id="tolerancia-a-particiones">Tolerancia a particiones</h4>

<p>El sistema puede seguir en funcionamiento aunque parte de la red esté caída o parte de los mensajes se pierdan.</p>

<div class="callout"><span class="callout-emoji">⚠</span><div class="callout-text">Nótese que la definición de consistencia en el contexto de CAP es diferente a la de consistencia en bases de datos ACID. Un poco confuso todo, la verdad.</div></div>

<h3 id="dónde-está-la-trampa">¿Dónde está la trampa?</h3>

<p>Pues que, a no ser que estemos trabajando con una arquitectura monolito, seguramente estemos ante un sistema distribuido y, por lo tanto, la tolerancia a particiones es obligatoria. Por lo tanto, ya hemos elegido una de las dos propiedades que podemos tener.</p>

<p>Así que la pregunta clave termina siendo:</p>

<h2 id="cuando-ocurre-una-partición-en-la-red-queremos-priorizar-la-disponibilidad-o-la-consistencia">Cuando ocurre una partición en la red, ¿queremos priorizar la disponibilidad o la consistencia?</h2>

<p>Imaginémonos el siguiente caso por un momento: nuestro sistema es una aplicación web que se utiliza en todo el mundo y tenemos una base de datos con todos los usuarios de nuestra aplicación en el mundo y, desplegadas, hay una instancia en Estados Unidos y otra en Europa. Dichas bases de datos son una réplica la una de la otra y están sincronizadas.</p>

<p><img src="/assets/img/posts/cap/a0f455d9-6df4-476b-a93b-b6278a19f1a6.png" alt="" /></p>

<p>Pues ahora va John y quiere actualizar su perfil, por ejemplo, cambiar la biografía que aparece. Justo después de esto, va Paco y quiere leer la información que tiene John en su perfil. Ocurriría algo así:</p>

<ol>
  <li>
    <p>John se conecta al servidor de Estados Unidos y actualiza su biografía.</p>
  </li>
  <li>
    <p>La base de datos de Europa se sincroniza con la de EEUU y se trae los cambios.</p>
  </li>
  <li>
    <p>Cuando Paco ve el perfil de John, ve su biografía actualizada.</p>
  </li>
</ol>

<p><img src="/assets/img/posts/cap/23d0c597-5ded-42af-8790-0a00a2ecb474.png" alt="" /></p>

<p>Todo funciona de maravilla hasta que nos encontramos con una partición en la red. La conexión entre el clúster de Estadios Unidos y el de Europa se rompe.</p>

<p><img src="/assets/img/posts/cap/d28f6ce0-659d-4061-a778-194d78e2d633.png" alt="" /></p>

<p>Ahora bien, si consideramos el ejemplo anterior de nuevo, pero con esta partición de red, ¿qué deberíamos hacer?</p>

<ul>
  <li>
    <p>Opción A: devolver un error porque no podemos garantizar que nuestros datos estén actualizados (elegimos consistencia)</p>
  </li>
  <li>
    <p>Opción B: devolver datos que podrían estar desactualizados (elegimos disponibilidad)</p>
  </li>
</ul>

<p>Pues esta es la clave del teorema de CAP, la respuesta a esta pregunta definirá si esta parte de tu sistema prioriza la consistencia o la disponibilidad.</p>

<p>En este caso está claro, devolveríamos la biografía del usuario John, aunque no podamos asegurar que sea la versión más actualizada.</p>

<h2 id="cuándo-elijo-consistencia-y-cuando-disponibilidad">¿Cuándo elijo consistencia y cuando disponibilidad?</h2>

<p>La realidad es que en la mayoría de sistemas van a tolerar algo de inconsistencia y deberían priorizar la disponibilidad. En estos casos lo que se llama <a href="https://en.wikipedia.org/wiki/Eventual_consistency">eventual consistency</a> es suficiente. Esto quiere decir que el sistema llegará eventualmente en algún punto a ser consistente, pero puede tardar segundos o incluso minutos.</p>

<h4 id="elegiremos-consistencia-en-sistemas-como">Elegiremos consistencia en sistemas como:</h4>

<ul>
  <li>
    <p><strong>Un sistema que tenga reserva de tickets (Ticketmaster, Skyscanner):</strong> imagínate que hemos comprado tickets para un vuelo, pero a la hora de comprarlos hubo una partición de red y otra persona también los vio disponibles y compró los mismos tickets. Al aeropuerto llegarán dos personas con el mismo ticket.</p>
  </li>
  <li>
    <p><strong>Inventario de una tienda e-commerce:</strong> si en una tienda como Amazon aparece que queda una sola Nintendo Switch 2 y la compras cuando hay una partición de red, quizás más de un usuario ha comprado la última unidad y alguien se queda sin ella.</p>
  </li>
  <li>
    <p><strong>Sistemas de finanzas:</strong> los sistemas relacionados con stocks tienen que enseñar los últimos datos actualizados o si no, podrían haber problemas relacionados con los precios a los que se compraron o vendieron acciones.</p>
  </li>
</ul>

<h4 id="elegiremos-disponibilidad-en-sistemas-como">Elegiremos disponibilidad en sistemas como:</h4>

<ul>
  <li>
    <p><strong>Redes sociales (Instagram):</strong> si un usuario actualiza su biografía, no pasa nada si otro usuario tarda un poquito más en verla actualizada.</p>
  </li>
  <li>
    <p><strong>Plataformas de contenido (Netflix o Youtube):</strong> si alguien actualiza el nombre de una película en otro idioma, no pasa nada porque el título antiguo aparezca un poco más de tiempo.</p>
  </li>
  <li>
    <p><strong>Páginas de reseñas (Google Maps):</strong> si un restaurante actualiza su horario, es mejor enseñar el horario antiguo que no enseñar nada.</p>
  </li>
</ul>

<p>Así que, de nuevo, ya para terminar, la pregunta que uno se tiene que preguntar es:</p>

<h2 id="sería-un-desastre-si-los-usuarios-viesen-datos-inconsistentes-durante-un-rato">¿Sería un desastre si los usuarios viesen datos inconsistentes durante un rato?</h2>

<p>Si la respuesta es sí, elige consistencia. Si es no, elige disponibilidad.</p>

<h3 id="fuentes">Fuentes:</h3>

<ul>
  <li>
    <p><a href="https://www.hellointerview.com/learn/system-design/deep-dives/cap-theorem">https://www.hellointerview.com/learn/system-design/deep-dives/cap-theorem</a>.</p>
  </li>
  <li>
    <p><a href="https://www.goodreads.com/book/show/23463279-designing-data-intensive-applications">Kleppmann, M. (2017). Designing Data-Intensive Applications. O’Reilly Media.</a></p>
  </li>
  <li>
    <p><a href="https://www.goodreads.com/book/show/23615147-web-scalability-for-startup-engineers">Ejsmont, A. (2015). <em>Web Scalability for Startup Engineers</em>. Apress.</a></p>
  </li>
</ul>
]]></content:encoded>
        <pubDate>Fri, 01 Aug 2025 00:03:56 +0200</pubDate>
        <link>https://blog.juanjorequena.com/cap/</link>
        <guid isPermaLink="true">https://blog.juanjorequena.com/cap/</guid>
        <category>CAP</category>
      </item>
    
      <item>
        <title>⚙️Motores de bases de datos: OLTP vs OLAP</title>
        <dc:creator><![CDATA[Juanjo Requena]]></dc:creator>
        <description>Hoy vamos a hablar de algo un poco más amplio: los motores de bases de datos. A grandes rasgos, los podemos dividir en dos grandes categorías: OLTP (procesamiento de transacciones online): los que están optimizados para procesar transacciones. OLAP (procesamiento analítico online): los que están optimizados para analíticas. Y sí,...</description>
        <content:encoded><![CDATA[<p>Hoy vamos a hablar de algo un poco más amplio: los motores de bases de datos. A grandes rasgos, los podemos dividir en dos grandes categorías:</p>

<ul>
  <li>
    <p><strong>OLTP</strong> (procesamiento de transacciones online): los que están <strong>optimizados para procesar transacciones</strong>.</p>
  </li>
  <li>
    <p><strong>OLAP</strong> (procesamiento analítico online): los que están <strong>optimizados para analíticas</strong>.</p>
  </li>
</ul>

<p>Y sí, los patrones de acceso a datos en uno y otro son muy diferentes.</p>

<h2 id="oltp-lo-que-maneja-el-usuario">OLTP: lo que maneja el usuario</h2>

<p>Los sistemas OLTP suelen ser los que están de cara al usuario. Tienen que manejar muchas peticiones a la vez, así que las queries suelen pedir pocos registros, casi siempre por clave, para que el motor pueda usar un índice y responder rápido.</p>

<p>Aquí el cuello de botella suele estar en <strong>el tiempo que tarda el disco en buscar el dato exacto</strong>.</p>

<p>Dentro de este mundo OLTP hay dos formas comunes de organizar el almacenamiento:</p>

<ul>
  <li>
    <p><strong>Estructura tipo log</strong>: no se sobreescriben ficheros, solo se añaden. Luego se eliminan ficheros obsoletos. Ejemplos: <strong>SSTables, LSM-trees, LevelDB, Cassandra, HBase, Lucene</strong>…</p>
  </li>
  <li>
    <p><strong>Update-in-place</strong>: se sobreescriben páginas concretas en disco. El ejemplo clásico: <strong>B-trees</strong>, usados en la mayoría de bases de datos relacionales y muchas no relacionales también.</p>
  </li>
</ul>

<p>La ventaja de las estructuras tipo log es que convierten escrituras aleatorias en <strong>escrituras secuenciales</strong>, lo que es mucho más eficiente para escrituras en discos y SSDs. Por eso han ido ganando fama en los últimos años.</p>

<p><strong>Si la estructura tipo log va a ofrecer un mejor rendimiento en las escrituras, la estructura con update-in-place va a hacerlo en lecturas.</strong></p>

<h2 id="olap-lo-que-manejan-los-analistas">OLAP: lo que manejan los analistas</h2>

<p>Aquí ya no estamos hablando de miles de usuarios haciendo clics, sino de almacenes de datos o <em>warehouses</em> y otros sistemas de analíticas menos conocidos que utilizan los analistas de negocios. Los sistemas OLAP manejan muchas menos queries, pero cada una escanea millones de filas.</p>

<p>En estos casos el cuello de botella no es el tiempo de búsqueda, sino el <strong>ancho de banda del disco</strong>: cuántos datos puedes leer por segundo.</p>

<h3 id="y-qué-pasa-con-los-índices">¿Y qué pasa con los índices?</h3>

<p>Cuando tus queries requieren escanear secuencialmente una gran cantidad de filas, los índices dejan de ser tan relevantes. En cambio, se convierte mucho más valioso el poder <strong>codificar los datos de forma compacta</strong> y así poder minimizar la cantidad de datos que necesita la query leer del disco.</p>

<p>Por eso, en estos sistemas ha triunfado el <strong>almacenamiento por columnas</strong>. Permite leer solo las columnas necesarias, y además compactar los datos. Dado que en una misma columna van a haber muchos registros con el mismo valor, es mucho más facil compactar dichos datos. Esto hace que las queries vayan mucho más rápido.</p>

<p>Así quedaría una base de datos en base a columnas en vez de filas:</p>

<p><img src="/assets/img/posts/motores-de-bases-de-datos/7f9b8a67-8651-4a44-9047-ead809519788.png" alt="" /></p>

<p>Y así quedaría comprimida utilizando <strong>bitmap encoding</strong> para una sola columna:</p>

<p><img src="/assets/img/posts/motores-de-bases-de-datos/86a384c5-d139-4d2d-bd4f-5f56d67f7028.png" alt="" /></p>

<h2 id="tabla-resumen">Tabla resumen</h2>

<table>
  <thead>
    <tr>
      <th>Característica</th>
      <th>OLTP</th>
      <th>OLAP</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Casos de uso</td>
      <td>Apps de usuario, web, móviles</td>
      <td>Análisis de negocio, reporting</td>
    </tr>
    <tr>
      <td>Nº de queries</td>
      <td>Muy alto</td>
      <td>Bajo</td>
    </tr>
    <tr>
      <td>Datos por query</td>
      <td>Pocos registros</td>
      <td>Millones de registros</td>
    </tr>
    <tr>
      <td>Patrón de acceso</td>
      <td>Lectura por clave (índice)</td>
      <td>Escaneo secuencial</td>
    </tr>
    <tr>
      <td>Cuello de botella</td>
      <td>Latencia de búsqueda en disco</td>
      <td>Ancho de banda de disco</td>
    </tr>
    <tr>
      <td>Almacenamiento recomendado</td>
      <td>Por filas</td>
      <td>Por columnas</td>
    </tr>
    <tr>
      <td>Ejemplos de motor</td>
      <td>B-trees, LSM trees, LevelDB, PostgreSQL…</td>
      <td>ClickHouse, Redshift, BigQuery, Snowflake…</td>
    </tr>
  </tbody>
</table>
]]></content:encoded>
        <pubDate>Sun, 01 Jun 2025 05:41:33 +0200</pubDate>
        <link>https://blog.juanjorequena.com/motores-de-bases-de-datos/</link>
        <guid isPermaLink="true">https://blog.juanjorequena.com/motores-de-bases-de-datos/</guid>
        <category>Databases</category><category>OLAP</category><category>OLTP</category><category>analytics</category>
      </item>
    
      <item>
        <title>🛠️¿Qué base de datos debería usar?</title>
        <dc:creator><![CDATA[Juanjo Requena]]></dc:creator>
        <description>⚠ATENCIÓN: este artículo está muy desactualizado. No representa realmente todas las opciones que disponemos de bases de datos NoSQL actualmente y los casos de uso han cambiado un poco. No recomiendo leer este documento como guía. Estaba leyendo Designing Data-Intensive Applications de Martin Kleppmann y me acordé de cuando, en...</description>
        <content:encoded><![CDATA[<div class="callout"><span class="callout-emoji">⚠</span><div class="callout-text"><strong>ATENCIÓN:</strong> este artículo está muy desactualizado. No representa realmente todas las opciones que disponemos de bases de datos NoSQL actualmente y los casos de uso han cambiado un poco. No recomiendo leer este documento como guía.</div></div>

<p>Estaba leyendo <a href="https://www.amazon.com/Designing-Data-Intensive-Applications-Reliable-Maintainable/dp/1449373321"><em>Designing Data-Intensive Applications</em></a> de Martin Kleppmann y me acordé de cuando, en mi última empresa, teníamos que elegir una base de datos. Básicamente era: <strong>“vale, a buscar en internet qué base de datos escoger”</strong>.</p>

<p>Pero creo que, en ese momento, me faltaban nociones básicas. Especialmente sobre cómo en el mundo del desarrollo de software hemos llegado hasta los distintos modelos de base de datos que existen ahora. Entender el <strong>por qué</strong> surgieron SQL y NoSQL ayuda bastante a saber <strong>qué decisiones</strong> toman los programadores al elegir una base de datos para su sistema.</p>

<p>En este post voy a comparar brevemente bases de datos <strong>relacionales</strong> y <strong>basadas en documentos</strong> (aunque también mencionaré grafos).</p>

<h3 id="un-repaso-rápido-al-modelo-relacional">Un repaso rápido al modelo relacional</h3>

<p>Creo que todos conocemos el modelo relacional. Cuando sabes los requisitos del sistema, lo típico es empezar a normalizar los datos: es decir, <strong>organizar los datos en tablas</strong>, cada una con sus filas (registros) y columnas (atributos), y definir relaciones entre ellas usando <em>primary keys</em> y <em>foreign keys</em>.</p>

<p>Para interactuar con este tipo de base de datos se utiliza SQL (<em>Structured Query Language</em>), lo cual te permite hacer consultas declarativas como si trabajaras con conjuntos matemáticos.</p>

<h3 id="qué-pasa-con-nosql">¿Qué pasa con NoSQL?</h3>

<p>El “rollo NoSQL” surgió por dos tendencias muy distintas:</p>

<ul>
  <li>
    <p>Bases de datos <strong>basadas en documentos</strong>, donde los datos vienen enteros en un solo documento y las relaciones entre documentos son poco frecuentes.</p>
  </li>
  <li>
    <p>Bases de datos <strong>de grafos</strong>, que van justo al otro extremo: intentan modelar casos donde todo puede estar relacionado con todo.</p>
  </li>
</ul>

<p>A día de hoy, los tres modelos (relacional, documentos y grafos) se usan bastante y <strong>cada uno tiene sentido en su propio dominio</strong>.</p>

<h3 id="qué-hace-especial-al-modelo-basado-en-documentos">¿Qué hace especial al modelo basado en documentos?</h3>

<p>Una base de datos basada en documentos permite <strong>guardar estructuras anidadas</strong> dentro del mismo documento padre. Por ejemplo, imagina un documento <code class="language-plaintext highlighter-rouge">User</code> que incluye un campo <code class="language-plaintext highlighter-rouge">Schools</code>, con una lista de colegios a los que fue ese usuario. Ahí estaríamos modelando una relación 1 a N directamente dentro del mismo documento.</p>

<p>En una base de datos relacional, eso serían dos tablas (<code class="language-plaintext highlighter-rouge">User</code> y <code class="language-plaintext highlighter-rouge">School</code>) relacionadas con una <em>foreign key</em>.</p>

<p>Cuando tienes relaciones simples (1 a 1, o incluso algunas N a N), <strong>ambos modelos pueden funcionar</strong>. La diferencia empieza a notarse cuando necesitas hacer muchas <em>joins</em> o cuando los datos están muy conectados.</p>

<h3 id="pros-y-contras-de-los-modelos">Pros y contras de los modelos</h3>

<p>He de decir que, tras los años, las bases de datos SQL se intentan parecer más a las bases de datos basadas en documentos (permitiendo el uso de JSON en columnas, entre otros), y las bases de datos basadas en documentos se intentan parecer más a las SQL, así ambas consiguen mayor flexibilidad para sus casos de uso.</p>

<p>Aquí te dejo una mini tabla para que te hagas una idea rápida:</p>

<table>
  <thead>
    <tr>
      <th>Característica</th>
      <th>Relacional</th>
      <th>Documentos</th>
      <th>Grafos</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Flexibilidad del esquema</td>
      <td>❌ Baja</td>
      <td>✅ Alta</td>
      <td>✅ Alta</td>
    </tr>
    <tr>
      <td>Relaciones complejas (N a N)</td>
      <td>✅ Natural con joins</td>
      <td>⚠️ Requiere lógica en la aplicación</td>
      <td>✅ Muy natural</td>
    </tr>
    <tr>
      <td>Modelo cercano a tu caso de uso en app</td>
      <td>❌ Menos</td>
      <td>✅ Más cercano</td>
      <td>⚠️ Depende del uso</td>
    </tr>
    <tr>
      <td>Escalabilidad horizontal</td>
      <td>⚠️ Más difícil</td>
      <td>✅ Más fácil</td>
      <td>⚠️ Complejo</td>
    </tr>
  </tbody>
</table>

<h3 id="cosas-que-debes-saber-sobre-las-bases-de-datos-basadas-en-documentos">Cosas que debes saber sobre las bases de datos basadas en documentos</h3>

<ul>
  <li>
    <p><strong>Flexibilidad no significa caos</strong>: aunque no tengas un esquema rígido, sigue siendo tu responsabilidad controlar qué estás metiendo en la base de datos. Se suele decir que en relacional se valida al escribir y en documentos al leer.</p>
  </li>
  <li>
    <p><strong>Evita documentos enormes</strong>: aunque puedes guardar estructuras complejas (JSON, BSON, XML…), eso no significa que debas abusar. Si solo necesitas una parte del documento, la base de datos probablemente cargue todo. Además, cuando actualizas un documento, muchas veces se reescribe entero. Por eso suele recomendarse mantener los documentos <strong>pequeños y bien pensados</strong>.</p>
  </li>
  <li>
    <p><strong>Para relaciones N a N</strong>, las bases de datos de documentos no son lo ideal. Puedes denormalizar, pero entonces mantener la consistencia se vuelve más complicado. Y si usas código en la aplicación para simular <em>joins</em>, el rendimiento baja y la complejidad del código sube.</p>
  </li>
</ul>

<h3 id="conclusión-rápida">Conclusión rápida</h3>

<ul>
  <li>
    <p>¿Tu modelo tiene <strong>datos muy conectados</strong>? → Relacional o grafos.</p>
  </li>
  <li>
    <p>¿Necesitas <strong>flexibilidad</strong>, escalabilidad y acceso rápido a una estructura de datos entera y concreta para tu caso de uso? → Modelo basado en documentos.</p>
  </li>
  <li>
    <p>¿Tienes muchas relaciones complejas N a N? → El modelo en documentos se te va a quedar corto.</p>
  </li>
</ul>

<p>Y como resumen simple:<br />
👉 Para datos <strong>muy interconectados</strong>, el modelo en documento es 💩, el relacional es aceptable, y los grafos son lo más natural.</p>
]]></content:encoded>
        <pubDate>Fri, 30 May 2025 16:59:15 +0200</pubDate>
        <link>https://blog.juanjorequena.com/bases-de-datos/</link>
        <guid isPermaLink="true">https://blog.juanjorequena.com/bases-de-datos/</guid>
        <category>Databases</category><category>NoSQL</category><category>SQL</category>
      </item>
    
      <item>
        <title>📚 The ABCs of NoSQL: lessons from &quot;NoSQL Distilled&quot;</title>
        <dc:creator><![CDATA[Juanjo Requena]]></dc:creator>
        <description>Why did I read this book? Some time ago, I asked my first manager as a software engineer, Andrea Carrozo, to recommend me some books to healp me learn more about databases. Andrea immediately suggested NoSQL Distilled: A Brief Guide to the Emerging World of Polyglot Persistence by Pramod J....</description>
        <content:encoded><![CDATA[<h2 id="why-did-i-read-this-book">Why did I read this book?</h2>

<p>Some time ago, I asked my first manager as a software engineer, <a href="https://www.linkedin.com/in/andreacarrozzo/"><em>Andrea Carrozo</em></a>, to recommend me some books to healp me learn more about databases. Andrea immediately suggested <em>NoSQL Distilled: A Brief Guide to the Emerging World of Polyglot Persistence</em> by Pramod J. Sadalage and Martin Fowler. As I write about it now, I revisited Andrea’s personal website (<a href="https://www.jonnyjava.net/">jonnyjava.net</a>) and noticed that he had even listed it as the first book to read in his recommended <a href="https://www.jonnyjava.net/learning-databases/">databases learning path</a>.</p>

<p>Although I’ve read several programming books, I hadn’t yet explored one focused exclusively on NoSQL databases. So, it felt like the right time to visit my local bookstore and pick up a fresh copy.</p>

<p>I’ll be going through the book chapter by chapter, sharing the key insights and lessons I learn along the way.</p>

<div class="callout"><span class="callout-emoji">📖</span><div class="callout-text">Link to the book: <a href="https://martinfowler.com/books/nosql.html" target="_blank" rel="noopener">https://martinfowler.com/books/nosql.html</a></div></div>

<hr />

<h2 id="chapter-1-relational-databases-and-nosql">Chapter 1: Relational Databases and NoSQL</h2>

<h3 id="relational-databases">Relational Databases:</h3>

<p><strong>What they solve:</strong></p>

<ul>
  <li>
    <p><strong>Getting at Persistent Data:</strong> they allow more flexibility and speed than file systems when getting small bits of information from big amounts of data.</p>
  </li>
  <li>
    <p><strong>They solve concurrency:</strong> the problem of having many people looking at the same data at once and even modifying it. Relational databases help handle this by controlling all access to their data through transactions. This isn’t the cure, you will also get transactional errors. But with transactions, you can make a change, and if an error occurs during the processing of the change you can roll back the transaction to clean things up.</p>
  </li>
  <li>
    <p><strong>Integration:</strong> using one database for multiple applications (integration database)</p>
  </li>
  <li>
    <p><strong>A Standard Model:</strong> the core mechanisms of relational databases is the same. allowing developers to learn it an apply to multiple projects.</p>
  </li>
</ul>

<p><strong>Impedance Mismatch from Relational Databases</strong></p>

<p>Given that the relational data model organizes data into a structure of tables and rows, if you want to use a richer data structure, you have to translate it to that representation. This difference between the relational model and the in-memory data structure is called impedance mismatch and it has been frustrating for application developers.</p>

<h3 id="nosql">NoSQL</h3>

<p><strong>How it appeared</strong></p>

<ol>
  <li>
    <p>➡️ 1990s dot-com bubble</p>
  </li>
  <li>
    <p>➡️ Growth in data from websites</p>
  </li>
  <li>
    <p>➡️ Need more computing resources: use clusters</p>
  </li>
  <li>
    <p>➡️ Relational databases are not designed to be run efficiently on clusters: mismatch</p>
  </li>
  <li>
    <p>➡️ Organizations consider an alternative route to data storage</p>
  </li>
  <li>
    <p>➡️ Google and Amazon (who were the forefront of running large clusters) produce highly influential papers: BigTable from google and Dynamo from Amazon.</p>
  </li>
</ol>

<p><strong>There is no proper definition for NoSQL databases but rather some common characteristics:</strong></p>

<ul>
  <li>
    <p>They don’t use the relational model</p>

    <ul>
      <li>They run well on clusters</li>
    </ul>
  </li>
  <li>
    <p>They are generally open-source projects</p>
  </li>
  <li>
    <p>They are schemaless, allowing you to freely add fields to database records without having to define any changes in structure first.</p>
  </li>
</ul>

<p><strong>The two primary reasons to consider NoSQL are:</strong></p>

<ul>
  <li>
    <p>Handle data access with size and performance that demand a cluster.</p>
  </li>
  <li>
    <p>Improve the productivity of application development by using a more convenient data interaction style.</p>
  </li>
</ul>

<h3 id="extra">Extra</h3>

<blockquote>
  <p>In order to make the polyglot persistence world to work, organizations need to shift from integration databases to application databases.</p>
</blockquote>

<blockquote>
  <p>We don’t generally consider NoSQL databases a good choice for integration databases.</p>
</blockquote>

<h2 id="chapter-2-aggregate-data-models">Chapter 2: Aggregate Data Models</h2>

<p><mark>A </mark> <strong><mark>data model</mark></strong> <mark>is the model through which we perceive and manipulate our data.</mark></p>

<blockquote>
  <p>Agregate orientation takes a different approach. It recognizes that often, you want to operate on data in units that have a more complex structure than a set of tuples.</p>
</blockquote>

<p>➡️ <strong>An aggregate is a collection of data that we interact with as a unit.</strong></p>

<blockquote>
  <p>If we’re running on a cluster, we need to minimize how many nodes we need to query when we are gathering data.</p>
</blockquote>

<p>➡️ <strong>Aggregates make it easier for the database to manage data storage over clusters.</strong></p>

<blockquote>
  <p>It’s often said that NoSQL databases don’t support ACID transactions and thus sacrifice consistency. This is a rather sweeping simplification. In general, it’s true that aggregate-oriented databases don’t have ACID transactions that span multiple aggregates. Instead, they support atomic manipulation of a single aggregate at a time. This means that if we need to manipulate multiple aggregates in an atomic way, we have to manage that ourselves in the application code.</p>
</blockquote>

<p>➡️ <strong>Aggregates form the boundaries for ACID operations with the database.</strong></p>

<p>In practice, we find that most of the time we are able to keep our atomicity needs to within a single aggregate; indeed, that’s part of the consideration for deciding how to divide up our data into aggregates.</p>

<blockquote>
  <p>With key-value databases, we expect to mostly look-up aggregates using a key. With document databases, we mostly expect to submit some form of query based on the internal structure of the document; this might be a key, but it’s more likely to be something else.</p>
</blockquote>

<p>➕ the main difference between key-value and document databases is that in the first one, the aggregate is opaque to the database - just some big blob of mostly meaningless bits. In contrast, a document database is able to see a structure in the aggregate.</p>

<blockquote>
  <p>Column-family models divide the aggregate into column families, allowing the database to treat them as units of data within the row aggregate.</p>
</blockquote>

<h2 id="chapter-3-more-about-data-models">Chapter 3: More about Data Models</h2>

<p><strong>Operating across multiple aggregates and managing lots of relations on NoSQL databases based on aggregates is awkward.</strong></p>

<ul>
  <li>
    <p>If you want to have data based on lots of relationships, you should prefer a relational database. But relational databases aren’t that excellent with complex relationships either.</p>
  </li>
  <li>
    <p><strong>Graph databases</strong> are good doing this. They are based on an opposite model from relational databases: small records with complex interconnections. A graph database allows you to query that network with query operations designed with this kind of graph in mind so making traversal along the relationships is cheap.</p>
  </li>
  <li>
    <p>Agregate-oriented databases often compute <strong>materialized views</strong> to provide data organized differently from their primary aggregates. This is often done with map-reduce computations.</p>
  </li>
</ul>

<h3 id="schemaless-databases">Schemaless databases</h3>

<ul>
  <li>
    <p>A common factor between all the forms of NoSQL databases is that they are <strong>schemaless</strong>.</p>
  </li>
  <li>
    <p>This means that when you want to store data, you dont need to define schema for it. This allows you to easily change your data storage as you learn more about your project.</p>
  </li>
  <li>
    <p>It also facilitates handling <strong>non-uniform data</strong>: data where each record has a different set of fields.</p>
  </li>
  <li>
    <p>Schemaless databases althought appealing, they bring problems of their own like:</p>

    <ul>
      <li>
        <p>Whenever we write a program that accesses data, the program relies on some form of implicit schema and assume something about the type of data stored within that field. So, however schemaless our database is, there is an implicit schema. This <strong>implicit schema</strong> is a set of assumptions about the data’s structure in the code to manipulate the data.</p>

        <ul>
          <li>
            <p>With an implicit schema it means that to understand what data there is present, you have to dig into the application code.</p>
          </li>
          <li>
            <p>The database remains ignorant of the schema and it can’t use it to help it decide how to store and retrieve data.</p>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li>
    <p>So, although NoSQL fans often criticize relational schemas for having to be defined front and being inflexible, that’s not really true. Relational schemas can be changed at any time with standard SQL commands.</p>
  </li>
</ul>

<h2 id="chapter-4-distribution-models">Chapter 4: Distribution Models</h2>

<p>These are the following ways of running a database on a cluster of servers:</p>

<ul>
  <li>
    <p><strong>Single Server</strong>. The simplest distribution option and the one the authors of the book would most often recommend - no distribution at all. It consists of just running the database on a single machine that handles all the reads and writes to the data store. It is prefered because it eliminates all the complexities that all the other options introduce.</p>
  </li>
  <li>
    <p><strong>Sharding</strong>. It distributes different data across multiple servers, so each server acts as the single source for a subset of data.</p>
  </li>
  <li>
    <p><strong>Replication</strong>. Copies data across multiple servers, so each bit of data can be found in multiple places. Replication comes in two forms:</p>

    <ul>
      <li>
        <p><strong>Master-Slave Replication</strong>. Makes one node the authoritative copy that handles writes while slaves synchronize with the master and may handle reads.</p>
      </li>
      <li>
        <p><strong>Peer-to-Peer Replication</strong>. Allows writes to any node and the nodes coordinate to syncrhonize their copies of the data.</p>
      </li>
      <li>
        <p>Master-slave replication reduces the chance of update conflicts, but peer-to-peer replication avoids loading all writes onto a singles point of failure.</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>Combining Sharding and Replication</strong>. These strategies can be combined to gain benefits from both of them like master-slave replication and sharding or peer-to-peer replication with sharding which is common strategy for column-family databases.</p>
  </li>
</ul>

<h2 id="chapter-5-consistency">Chapter 5: Consistency</h2>

<p><strong><mark>One of the biggest changes from a centralized relational database to a cluster-oriented NoSQL database is in how you think about consistency. Relational databases try to exhibit strong consistency by avoiding all the various incosistencies introduced below.</mark></strong></p>

<blockquote>
  <p><strong>Write-write conflicts</strong> occur when two clients try to write the same data at the same time. <strong>Read-write conflicts</strong> occur when one client reads incosistent data in the middle of another client’s write.</p>
</blockquote>

<p><strong>Approaches for maintaining consistency in the face of concurrency as often described as pessimistic or optimistic:</strong></p>

<ul>
  <li>
    <p><strong>Pessimistic approaches</strong> works by preventing conflicts from occurring. It lock data records to prevent conflicts.</p>
  </li>
  <li>
    <p><strong>Optimistic approaches</strong> lets conflicts occur, but detects them and takes action to sort them out.</p>
  </li>
</ul>

<blockquote>
  <p>Often, when people first encounter these issues, their reaction is to prefer pessimistic concurrency because they are determined toa void conflicts. While in some cases this is the right answer, there is always a <strong>tradeoff</strong>. Concurrent programming involves a fundamental tradeoff between <strong>safety</strong> (avoiding errors such as update conflicts) and <strong>liveness</strong> (responding quickly to clients). <strong>Pessimistic approaches often severely degrade the responsiveness of a system to the degree that it becomes unfit for its purpose.</strong></p>
</blockquote>

<p>Some claims about NoSQL databases and the consistency on its updates.</p>

<blockquote>
  <p>A common claim we hear is that NoSQL databases don’t support transactions and thus can’t be consistent. Such claim is mostly wrong because it glosses over lots of important details. Out first clarification is that any statement about lack of transactions usually only applies to some NoSQL databases, in particular the aggregate-oriented ones. In contrast, graph databases tend to support ACID transactions just the same as relational databases.</p>

  <p>Secondly, aggregate-oriented databases do support atomic updates, but only within a single aggregate. This means that you will have logical consistency within an aggregate but not between aggregates.</p>
</blockquote>

<p><strong>Data that is out of date is generally referred to as stale.</strong></p>

<blockquote>
  <p>The basic statement of the <strong>CAP theorem</strong> is that, <strong>given the three properties of Consistency, Availability, and Partition tolerance, you can only get two.</strong></p>

  <p>The CAP theorem states that if you get a network partition, you have to trade off availability versus consistency.</p>
</blockquote>

<ul>
  <li>
    <p>Distributed systems see read-write conflicts due to some nodes having received updates while other nodes have not. Eventual consistency means that at some point the system will become consistent once all the writes have propagated to all the nodes.</p>
  </li>
  <li>
    <p>To get good consistency, you need to involve many nodes in data operations, but this increases latency. So you often have to trade off consistency versus latency.</p>
  </li>
  <li>
    <p>Durability can also be traded off against latency, particularly if you want to survive failures with replicated data.</p>
  </li>
  <li>
    <p>You do not need to contact all replicants to preserver strong consistency with replication. You just need a large enough quorum.</p>
  </li>
</ul>

<h2 id="chapter-6-version-stamps">Chapter 6: Version Stamps</h2>

<p><strong><mark>Version stamps help you drect concurrency conflicts. When you read and then update data, you can check the version stamp to ensure nobody updates the data beteween your read and write.</mark></strong></p>

<p><strong>Implementations of version stamps are:</strong></p>

<ul>
  <li>
    <p>Counters</p>
  </li>
  <li>
    <p>GUIDs</p>
  </li>
  <li>
    <p>Content hashes</p>
  </li>
  <li>
    <p>Timestamps</p>
  </li>
  <li>
    <p>A combination of these</p>
  </li>
</ul>

<p>Timestamps are simple but problematic because is difficult to ensure that all the nodes have a consistent notion of time. A counter is usually better than timestamps.</p>

<p>The most common approach use by peer-to-peer NoSQL systems is a vector stamp. It would look like [blue: 43, green: 54, black: 5]</p>

<h2 id="chapter-7-map-reduce">Chapter 7: Map-Reduce</h2>

<p><strong><mark>A map-reduce is a pattern to allow computations to be parallelized over a cluster. It is composes of a map function, which performs filtering and sorting, and a reduce method, which performs a summary operation.</mark></strong></p>

<ul>
  <li>
    <p>The <strong>map task</strong> reads data from an aggregate and summarizes it to relevant <strong>key-value pairs</strong>. Maps only read a single record at a time and can thus be parallelized and run on the node that stores the record.</p>
  </li>
  <li>
    <p><strong>Reduce tasks</strong> take <strong>many values for a single key output</strong> from map tasks and <strong>summarize them into a single output</strong>. Each reducer operates on the result of a single key, so it can be parallelized by key.</p>
  </li>
  <li>
    <p>Reducers that have the same form for input and output can be combined into <strong>pipelines</strong>. This improves parallelism and reduces the amount of data to be transferred.</p>
  </li>
  <li>
    <p><strong>Map-reduce operations can be composed into pipelines where the output of one reduce is the input to another operation’s map.</strong></p>
  </li>
  <li>
    <p>If the result of a map-reduce computation is widely used, it can be stored as a <strong>materialized view</strong>.</p>

    <ul>
      <li><strong>Materialized views</strong> can be updated through incremental map-reduce operations that only compute changes to the view instead of computing again everything from scratch.</li>
    </ul>
  </li>
</ul>

<hr />

<div class="callout"><span class="callout-emoji">📣</span><div class="callout-text">This article is getting too long, so I’ll cover the second part in a separate post.</div></div>
]]></content:encoded>
        <pubDate>Sat, 21 Sep 2024 07:43:53 +0200</pubDate>
        <link>https://blog.juanjorequena.com/nosql-distilled/</link>
        <guid isPermaLink="true">https://blog.juanjorequena.com/nosql-distilled/</guid>
        <category>Databases</category><category>NoSQL</category>
      </item>
    
      <item>
        <title>📚 Success through giving: lessons from &quot;Give and Take&quot;</title>
        <dc:creator><![CDATA[Juanjo Requena]]></dc:creator>
        <description>Why did I read this book? Recently, my mentor in employment and work culture in Korea, Minhee Jung, recommended this book to me to better understand the ways in which we can make connections. At first, I was not sure if the content of the book would clash too much...</description>
        <content:encoded><![CDATA[<h2 id="why-did-i-read-this-book">Why did I read this book?</h2>

<p>Recently, my mentor in employment and work culture in Korea, <a href="https://www.linkedin.com/in/minheejung"><em>Minhee Jung</em></a>, recommended this book to me to better understand the ways in which we can make connections. At first, I was not sure if the content of the book would clash too much with my way of thinking.</p>

<p>I come from a Spanish family where Christian values such as generosity are implicit in my culture. This, combined with a strong sense of helping others passed on to me by my parents, fueled my childhood dream of becoming a policeman, and later, a fireman. However, my aspirations changed and ended up changing my dreams again to become a software engineer. I believe that my life experiences have shaped my perspective, and sometimes restrained my ability to fully embody those giving values.</p>

<p>This book has offered me a new perspective on something that has always brought me fulfillment: helping others. It has reawakened this desire in me again as well as showing me how successful people achieve their dreams while helping others.</p>

<p>Below, I have saved quotes and annotations divided by the different themes of the book. This is according to my understanding of the book, your experience may be different and these annotations may or may not be that helpful to you.</p>

<hr />

<h2 id="givers-takers-and-matchers">Givers, takers and matchers</h2>

<p>The main argument in the book is that in a networked world success depends on how we interact with others. The author suggests there are three different styles: <strong>Givers</strong>, those who give to others without an expect for a return; <strong>Matchers</strong>, those who give to get something in return; and <strong>Takers</strong>, those who are only motivated about what they can get from others.</p>

<h2 id="the-giving-mentality">The giving mentality</h2>

<blockquote>
  <p>“I’ll sum up the key to success in one word: <strong>generosity</strong>,” writes Keith Ferrazzi. “If your interactions are ruled by generosity, your rewards will follow suit.”</p>
</blockquote>

<p>The main quality of givers that is described through the read of the whole book is <strong>generosity.</strong> This is the main characteristic of givers that make them what they are, being free in giving or sharing.</p>

<blockquote>
  <p>Instead of aiming to succeed first and give back later, you might decide that giving first is a promising path to succeeding later.</p>
</blockquote>

<p>Giving to get something back is a matcher’s mentality. Givers don’t do things to succeed; if you do, it probably won’t work.</p>

<blockquote>
  <p>The people at the bottom of the ladder are givers, but also the most successful ones.</p>
</blockquote>

<p>The way these both givers operate make the difference between becoming a giver who is treated as a doormat and becoming one who knows how to identify people who want to just take things from them, the takers.</p>

<blockquote>
  <p>This is what I find most magnetic about successful givers: they get to the top without cutting others down, finding ways of expanding the pie that benefit themselves and the people around them. Whereas success is a zero-sum in a group of takers, in groups of givers, it may be true that the whole is greater than the sum of the parts.</p>
</blockquote>

<h3 id="they-way-givers-treat-others">They way givers treat others</h3>

<blockquote>
  <p>When selling, givers ask questions in a way that conveys the desire to help customers, not take advantage to them.</p>
</blockquote>

<p>When selling, givers ask questions and try to understand the client needs. They believe they are there to help their client. That is why clients trust sellers who are givers, because they really care about them and their necessities.</p>

<blockquote>
  <p>But when givers are advocating for someone else, pushing is closely aligned with their values of protecting and promoting the interests of others: givers can chalk it up to caring. And by offering relational accounts, givers do more than just think of themselves as agents advocating for others; they present themselves as agents advocating for others, which is a powerful way to maintain their self-images and social images as givers.</p>
</blockquote>

<p>Givers are open about the fact that they are there to help, pushing themselves to protect and promote the interests of others. That helps them build their image.</p>

<blockquote>
  <p>In my own research, I’ve found that because of their dedication to others, <strong>givers are willing to work harder and longer than takers and matchers.</strong></p>
</blockquote>

<p>Givers are willing to put all their efforts for others, thats why they are also the ones that have to exert their efforts out of a sense of responsibility and work harder than anyone else.</p>

<h3 id="how-givers-think-of-others">How givers think of others</h3>

<blockquote>
  <p>As a giver, Inman built this championship team with an approach that mirrored C. J. Skender’s: <strong>seeing potential in players where others didn’t.</strong></p>
</blockquote>

<p>Often, when people has to give a value to people, they tend to see what the other person can put on the table. Successful givers don’t act like that. They see the potential in the other person and think of how far they can go in the future. They can find diamonds in the rough.</p>

<blockquote>
  <p>“Even when people are well intentioned,” writes LinkedIn founder Reid Hoffman, <strong>“they tend to overvalue their own contributions and undervalues those of others.”</strong></p>
</blockquote>

<p>When we work in groups, our perception makes us to underestimate others’ contributions. We think of a higher estimation for our work than work done by others.</p>

<blockquote>
  <p>Givers like Meyer do this naturally: <strong>they take care to recognize what other people contribute</strong></p>
</blockquote>

<p>Another attribute of givers, they <strong>recognize</strong> other’s people work, they don’t underestimate other’s efforts.</p>

<h2 id="networking-and-relationship-building"><strong>Networking and relationship building</strong></h2>

<blockquote>
  <p>Adam Rifkin believes that we should see networks as a vehicle for creating value for everyone, not just claiming it for ourselves.</p>
</blockquote>

<p>The traditional way of networking is based on the norm of reciprocity, the famous “quid pro quo”, you get something and you give something back. But the giver’s approach is to build networks to be able to generate more value. In other words, give and take back in order to give or help more people.</p>

<blockquote>
  <p>when everyone contributes, the pie is largers, and givers are no longer stuck contributing for more than they get.</p>
</blockquote>

<p>When giving, force the people you are helping to also give so they help other people.</p>

<blockquote>
  <p>Advice seeking is a form of powerless communication that combines expressing vulnerability, asking questions and talking tentatively. When we ask others for advice, we’re posing a question that conveys uncertainty and makes us vulnerable. Instead of confidently projecting that we have all the answers, we’re admitting that others might have superior knowledge.</p>
</blockquote>

<p>Asking others for advice is also a giver’s way of acting.</p>

<h3 id="the-5-minute-rule">The 5-minute rule</h3>

<blockquote>
  <p>His giving is governed by a simple rule: the five-minute favor. “You should be willing to do something that will take you five minutes or less for anybody”</p>
</blockquote>

<p>This is the 5-minute rule. Is not about thinking about what the other person can do for you. Is not about trading value, but adding value to the other person. You shouldn’t be thinking about whether if the people you help will contribute back to you. Be confident that someone else will do something for you down the road.</p>

<h3 id="weak-ties-and-dormant-ties">Weak ties and dormant ties</h3>

<blockquote>
  <p>One of Rifkin’s maxims is “I believe in the strength of weak ties”</p>

  <p>Strong ties are our close friends and colleagues, the people we really trust. Weak tries are our acquaintances, the people we know casually.</p>
</blockquote>

<p><strong>Strong ties</strong> are people who are close to you and somehow share the same social circles. Since <strong>weak ties</strong> are often formed by people who are not close to you, these people get you to know others from different circles that you wouldn’t be able to get to to know. For instance; to land a new employment, weak ties are more likely to help you get there than strong ties with people you know better.</p>

<blockquote>
  <p><strong>Dormant ties</strong> offer the access to novel information that weak ties afford, but without the discomfort.</p>
</blockquote>

<p>When you made some kind of tie with someone, that tie is not lost over the time, it just becomes a <strong>dormant tie</strong>. Dormant ties are very powerful because you have already made an environment of mutual trust we was built a long time ago and makes the conversation today smoother. You just need to reactivate the dormant tie.</p>

<h2 id="balancing-self-interest-and-altruism-otherish-givers"><strong>Balancing self-interest and altruism: otherish givers</strong></h2>

<blockquote>
  <p>If takers are selfish and failed givers are selfless, successful givers are otherish: they care about benefiting others, but they also have ambitious goals for advancing their own interests.</p>
</blockquote>

<p>Be a <strong>otherish</strong>, not a selfless giver. You need to also act for your own interests and avoid becoming a doormat. You need to be a hybrid engine between “self-interest” and “caring for others”.</p>

<blockquote>
  <p>These resilient health care professionals were otherish givers: they reported that they enjoyed helping other people <strong>and often went out of their way to do so, but weren’t afraid to see help when they needed it.</strong></p>
</blockquote>

<p>To be a giver is to go out of your way to help others but also to get help when you need it. This is the moment when you take back what you payed in forward. This help could be for yourself or, again, help others.</p>

<blockquote>
  <p>I’ll also argue that an otherish style helps givers sidestep the land mines of being too empathetic and too timid…</p>
</blockquote>

<p>Successful givers can’t be that empathetic and timid.</p>

<h2 id="adapting-giving-strategies"><strong>Adapting giving strategies</strong></h2>

<blockquote>
  <p>Trust is one reason that givers are so susceptible to the doormat effect: they tend to see the best in everyone, so they operate on the mistaken assumption that everyone is trustworthy.</p>
</blockquote>

<p>Successful givers need to know who’s likely to manipulate them so that they can protect themselves.</p>

<blockquote>
  <p>The most effective negotiators were otherish: they reported high concern for their own interests and high concern for their counterparts’ interests.</p>
</blockquote>

<blockquote>
  <p>The dangers lie less in giving itself, and more in the rigidity of sticking with a single reciprocity style across all interactions and relationships.</p>

  <p>… Although many successful givers start from the default of trusting others’ intentions, they’re also careful to scan their environments to screen for potential takers, always ready to shift from feeling a taker’s emotions to analyzing a taker’s thoughts, and flex from giving unconditionally to a more measured approach of generous tit for that. And when they feel inclined to back down, successful givers are prepared to draw reserves of assertiveness from their commitments to the people who matter to them.</p>
</blockquote>

<p>As a giver, you can’t act the same way with all people. Givers need to change their strategies so they are not used by others. They need to recognize takers and change their strategy.</p>

<h2 id="the-impact-of-giving-in-professional-settings"><strong>The impact of giving in professional settings</strong></h2>

<p>Successful givers get to the top without stepping on others, that is something a taker would do.</p>

<blockquote>
  <p>We spend the majority of our waking hours at work. This means that what we do at work becomes a fundamental part of who we are. If we reserve giver values for our personal lives, what will be missing in our professional lives? By shifting ever so slightly in the giver direction, we might find our waking hours marked by greater success, richer meaning, and more lasting impact.</p>
</blockquote>

<p>We spend most of our lives working. If we want to live as a giver, we should be givers at work too.</p>

<blockquote>
  <p>“Focus attention and energy on making a difference in the lives of others, and success might follow as a by-product.”</p>
</blockquote>

<p>This is the mentality that givers should adopt. Immediate success may not be possible, but by embracing this mindset, success will come sooner or later.</p>
]]></content:encoded>
        <pubDate>Mon, 15 Apr 2024 20:51:46 +0200</pubDate>
        <link>https://blog.juanjorequena.com/give-and-take/</link>
        <guid isPermaLink="true">https://blog.juanjorequena.com/give-and-take/</guid>
        <category>books</category>
      </item>
    
      <item>
        <title>Hi! I&apos;m Juanjo, the creator of this blog</title>
        <dc:creator><![CDATA[Juanjo Requena]]></dc:creator>
        <description>Who am I? Hey there! I’m Juanjo, a 24-year-old software engineer who has been working for an insurtech company for the last 2 and a half years after graduating from university. Actual picture of me: I come from a small city in Spain called Seville that is mostly known for...</description>
        <content:encoded><![CDATA[<h2 id="who-am-i">Who am I?</h2>

<p>Hey there! I’m Juanjo, a 24-year-old software engineer who has been working for an insurtech company for the last 2 and a half years after graduating from university. Actual picture of me:</p>

<p><img src="/assets/img/posts/me/b87ee5ba-e61d-4520-a04b-a4086560a593.webp" alt="" /></p>

<p>I come from a small city in Spain called Seville that is mostly known for our country’s famed traditions like flamenco and bullfighting. However, I personally enjoy my hometown for how welcoming our people are and its food (we’ve got some delicious tapas here ⬇️).</p>

<p><img src="/assets/img/posts/me/03699d7e-d4d7-4d63-a966-362517b930a6.webp" alt="Plaza de España, Seville" /></p>

<p>Food talks aside, as I navigate through the twists and turns of my career in the tech industry, I’ve decided to embark on a new adventure – starting this blog.</p>

<h2 id="my-journey-so-far">My journey so far</h2>

<p>After graduating in Computer Engineering from the University of Seville in 2021, I was contacted by <a href="https://www.linkedin.com/in/joanna-sypniewskaa/">Joanna</a> through LinkedIn for a spot in <a href="https://www.linkedin.com/company/coverwallet/">Coverwallet’s</a> Excellence Fellowship program (an internship program for students with high marks). Little did I know, the real challenges lay ahead as I stepped into the world of tech.</p>

<h2 id="why-this-blog">Why this blog?</h2>

<p>Reflecting on my journey, I realized there were gaps in my knowledge and experience that I hadn’t anticipated. The COVID-19 pandemic disrupted my last university years, leaving me struggling to find my footing in the job market. Due to the impact of the pandemic, I believe that I missed lots of opportunities to make connections and discuss with my colleagues how to continue with our careers as Software Engineers.</p>

<p>Now, with almost three years of industry experience under my belt, I’ve come to appreciate the importance of building a personal brand and sharing insights with fellow tech enthusiasts. I should have started this time ago, but I didn’t even know this was a thing. Late to the party or not, I will give it a try!</p>

<p><img src="/assets/img/posts/me/4b62e537-bd9f-45c7-970d-979bd729a0a6.jpeg" alt="" /></p>

<h2 id="what-to-expect">What to expect</h2>

<p>This blog will be my tech playground, where I’ll share everything from tech tutorials and book reviews to anecdotes about fixing the local flower shop’s website. It’s a work in progress, and I invite you to join me on this journey of self-discovery and growth.</p>

<h2 id="final-thoughts">Final thoughts</h2>

<p>Thank you for joining me on this new chapter 🫶. Whether you’re a seasoned developer or just starting out, I hope you can take something from my experiences or even be inspired by them.</p>

<h2 id="contact">Contact</h2>

<p>Feel free to contact me or send me a LinkedIn message anytime! 😉</p>

<ul>
  <li>
    <p>LinkedIn: <a href="https://www.linkedin.com/in/juanjorequena/">Juanjo Requena</a></p>
  </li>
  <li>
    <p>Email: juanjorek@gmail.com</p>
  </li>
  <li>
    <p>Github: <a href="https://github.com/wuaho">wuaho</a></p>
  </li>
  <li>
    <p>This blog’s profile: @<a href="@juanjorequena">Juanjo Requena</a></p>
  </li>
</ul>
]]></content:encoded>
        <pubDate>Thu, 28 Mar 2024 17:24:42 +0100</pubDate>
        <link>https://blog.juanjorequena.com/me/</link>
        <guid isPermaLink="true">https://blog.juanjorequena.com/me/</guid>
        <category>introduction</category><category>first post</category>
      </item>
    
  </channel>
</rss>

