<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0"><channel><title>Abe Estrada</title><description>Abe Estrada</description><link>https://feed.abeestrada.com</link><pubDate>Wed, 04 Mar 2026 07:52:50 -0700</pubDate><lastBuildDate>Wed, 04 Mar 2026 07:52:50 -0700</lastBuildDate><item><title>Books</title><link>https://abeestrada.com/books/</link><pubDate>Fri, 20 Feb 2026 08:00:00 -0600</pubDate><guid isPermaLink="true">https://abeestrada.com/books/</guid><description>&lt;h4 id="2026"&gt;2026&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://a.co/d/itraz3W" target="_blank" rel="noopener"&gt;Scrum&lt;/a&gt;
 - Jeff Sutherland&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/00RSJ1c0" target="_blank" rel="noopener"&gt;High Output Management&lt;/a&gt;
 - Andrew S. Grove&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/05GvqsXv" target="_blank" rel="noopener"&gt;Staff Engineer&lt;/a&gt;
 - Will Larson&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/0gdJQbGh" target="_blank" rel="noopener"&gt;The Greatest Sentence Ever Written&lt;/a&gt;
 - Walter Isaacson&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/08MtLymI" target="_blank" rel="noopener"&gt;Hands-On Large Language Models&lt;/a&gt;
 - Jay Alammar&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="2025"&gt;2025&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://a.co/d/fVMxisK" target="_blank" rel="noopener"&gt;The Coming Wave&lt;/a&gt;
 - Mustafa Suleyman&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/2SfznF6" target="_blank" rel="noopener"&gt;The Hackers Ethic&lt;/a&gt;
 - Pekka Himanen&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/4rQ4cSw" target="_blank" rel="noopener"&gt;The Elements of Marie Curie&lt;/a&gt;
 - Dava Sobel&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/2kTtQVU" target="_blank" rel="noopener"&gt;Source Code&lt;/a&gt;
 - Bill Gates&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/a3bgBE4" target="_blank" rel="noopener"&gt;Quantum Computing&lt;/a&gt;
 - Brian Clegg&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/84Dk4T8" target="_blank" rel="noopener"&gt;Nexus&lt;/a&gt;
 - Yuval Noah Harari&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/0tljzsg" target="_blank" rel="noopener"&gt;A Vulnerable System&lt;/a&gt;
 - Andrew J. Stewart&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/cgilxzJ" target="_blank" rel="noopener"&gt;Idea Man&lt;/a&gt;
 - Paul Allen&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/8RC6uHd" target="_blank" rel="noopener"&gt;Revolutionary Algorithms&lt;/a&gt;
 - Torey Akers&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/dghDXXj" target="_blank" rel="noopener"&gt;Free Software, Free Society&lt;/a&gt;
 - Richard M. Stallman&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/8FDwcDr" target="_blank" rel="noopener"&gt;Spam Nation&lt;/a&gt;
 - Brian Krebs&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/gabEA28" target="_blank" rel="noopener"&gt;Stealth&lt;/a&gt;
 - Peter Westwick&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/0J1uPZu" target="_blank" rel="noopener"&gt;The Quantum Labyrinth&lt;/a&gt;
 - Paul Halpern&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/cQYNAoI" target="_blank" rel="noopener"&gt;Careless People&lt;/a&gt;
 - Sarah Wynn-Williams&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/3I863CL" target="_blank" rel="noopener"&gt;Quantum Supremacy&lt;/a&gt;
 - Michio Kaku&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/bAHPCjK" target="_blank" rel="noopener"&gt;Quantum Entanglement&lt;/a&gt;
 - Jed Brody&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/dacngzK" target="_blank" rel="noopener"&gt;When the Moon Hits Your Eye&lt;/a&gt;
 - John Scalzi&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/aNKg0OO" target="_blank" rel="noopener"&gt;The Vegetarian&lt;/a&gt;
 - Han Kang&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/7lrMtsv" target="_blank" rel="noopener"&gt;Rare Tongues&lt;/a&gt;
 - Lorna Gibb&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/cP85ZFn" target="_blank" rel="noopener"&gt;Heretic&lt;/a&gt;
 - Catherine Nixey&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/9N0VWtz" target="_blank" rel="noopener"&gt;Crucial Conversations&lt;/a&gt;
 - Joseph Grenny&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/2FoJtOQ" target="_blank" rel="noopener"&gt;Between Two Rivers&lt;/a&gt;
 - Moudhy Al-Rashid&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/3F4JdPw" target="_blank" rel="noopener"&gt;Constituent Service&lt;/a&gt;
 - John Scalzi&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/0lcLbz2" target="_blank" rel="noopener"&gt;Buddhism for Beginners&lt;/a&gt;
 - Thubten Chodron&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/doSsEUD" target="_blank" rel="noopener"&gt;No Better Time&lt;/a&gt;
 - Molly Knight Raskin&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/0pHhXC9" target="_blank" rel="noopener"&gt;La civilización del espectáculo&lt;/a&gt;
 - Mario Vargas Llosa&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/gSZcOmi" target="_blank" rel="noopener"&gt;Jurassic Park&lt;/a&gt;
 - Michael Crichton&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/38aA1VI" target="_blank" rel="noopener"&gt;Pancho Villa&lt;/a&gt;
 - Paco Ignacio Taibo II&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/dQDGGp5" target="_blank" rel="noopener"&gt;Armada&lt;/a&gt;
 - Ernest Cline&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/hD6InYl" target="_blank" rel="noopener"&gt;Never Lost Again&lt;/a&gt;
 - Bill Kilday&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/2fiZ7Cb" target="_blank" rel="noopener"&gt;Empire of AI&lt;/a&gt;
 - Karen Hao&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/bWUQOdT" target="_blank" rel="noopener"&gt;Fundamentals of Software Architecture&lt;/a&gt;
 - Mark Richards, Neal Ford&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/3QZZvjq" target="_blank" rel="noopener"&gt;Software Architecture: The Hard Parts&lt;/a&gt;
 - Pramod Sadalage, Zhamak Dehghani&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/deVUvPo" target="_blank" rel="noopener"&gt;Digital Dharma&lt;/a&gt;
 - Deepak Chopra MD&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/3rHYd8U" target="_blank" rel="noopener"&gt;Engineering Management for the Rest of Us&lt;/a&gt;
 - Sarah Drasner&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/gIIhsbA" target="_blank" rel="noopener"&gt;Accelerate&lt;/a&gt;
 - Nicole Forsgren PhD&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/5POheB9" target="_blank" rel="noopener"&gt;Hell Yeah or No&lt;/a&gt;
 - Derek Sivers&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/e5IkMcR" target="_blank" rel="noopener"&gt;The Manager&amp;rsquo;s Path&lt;/a&gt;
 - Camille Fournier&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/iW8I3Zd" target="_blank" rel="noopener"&gt;An Elegant Puzzle&lt;/a&gt;
 - Will Larson&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/4Lw0HIK" target="_blank" rel="noopener"&gt;Thinking in Systems&lt;/a&gt;
 - Donella H. Meadows&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/bZ2YR5b" target="_blank" rel="noopener"&gt;Fundamentals of Data Engineering&lt;/a&gt;
 - Joe Reis&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/bA9OXOX" target="_blank" rel="noopener"&gt;The Staff Engineer&amp;rsquo;s Path&lt;/a&gt;
 - Tanya Reilly&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="2024"&gt;2024&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://a.co/d/0d0wKqj" target="_blank" rel="noopener"&gt;Artificial Unintelligence&lt;/a&gt;
 — Meredith Broussard&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/dQsPSOO" target="_blank" rel="noopener"&gt;Surfear el espacio-tiempo&lt;/a&gt;
 — Sergio de Régules &amp;amp; Miguel Alcubierre&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/c7J7fz1" target="_blank" rel="noopener"&gt;En agosto nos vemos&lt;/a&gt;
 — Gabriel García Márquez&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/7pYtf0h" target="_blank" rel="noopener"&gt;Filterworld&lt;/a&gt;
 — Kyle Chayka&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/8vQbvA7" target="_blank" rel="noopener"&gt;Airbus A320 Filosofía operacional&lt;/a&gt;
 — Facundo Conforti&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/a3KvCKb" target="_blank" rel="noopener"&gt;Burn Book&lt;/a&gt;
 — Kara Swisher&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/cY0Dwd3" target="_blank" rel="noopener"&gt;How to Make the Best Coffee at Home&lt;/a&gt;
 — James Hoffmann&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/8Wbfo71" target="_blank" rel="noopener"&gt;Starter Villain&lt;/a&gt;
 — John Scalzi&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/eUZXLVh" target="_blank" rel="noopener"&gt;The 37th Parallel&lt;/a&gt;
 — Ben Mezrich&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/fSmRZSp" target="_blank" rel="noopener"&gt;The Great Bridge&lt;/a&gt;
 — David McCullough&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/elXWIZx" target="_blank" rel="noopener"&gt;Dark Wire&lt;/a&gt;
 — Joseph Cox&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/3HLiFIW" target="_blank" rel="noopener"&gt;Pegasus&lt;/a&gt;
 — Laurent Richard &amp;amp; Sandrine Rigaud&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/00NKBcP0" target="_blank" rel="noopener"&gt;The Wright Brothers&lt;/a&gt;
 — David McCullough&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/ae8q6Qc" target="_blank" rel="noopener"&gt;The Singularity Is Nearer&lt;/a&gt;
 — Ray Kurzweil&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/6YlBc1B" target="_blank" rel="noopener"&gt;Gravitational Waves&lt;/a&gt;
 — Brian Clegg&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/3NmECYQ" target="_blank" rel="noopener"&gt;Token Supremacy&lt;/a&gt;
 — Zachary Small&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/eXaNomN" target="_blank" rel="noopener"&gt;Just for Fun&lt;/a&gt;
 — Linus Torvalds &amp;amp; David Diamond&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/6bTJawl" target="_blank" rel="noopener"&gt;Fuego y Sangre&lt;/a&gt;
 — George R.R. Martin&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/1S74n7a" target="_blank" rel="noopener"&gt;Chip War&lt;/a&gt;
 - Chris Miller&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/5el0fb2" target="_blank" rel="noopener"&gt;Tracers in the Dark&lt;/a&gt;
 - Andy Greenberg&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/9XiLoCH" target="_blank" rel="noopener"&gt;Cypherpunks&lt;/a&gt;
 - Julian Assange&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/ajmshG5" target="_blank" rel="noopener"&gt;We Were Yahoo!&lt;/a&gt;
 - Jeremy Ring&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/73oSqbb" target="_blank" rel="noopener"&gt;Mindf*ck&lt;/a&gt;
 - Christopher Wylie&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a.co/d/cKoVzDI" target="_blank" rel="noopener"&gt;How the Internet Happened&lt;/a&gt;
 - Brian McCullough&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="2023"&gt;2023&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B01AYL8VYQ/" target="_blank" rel="noopener"&gt;Cinco Esquinas&lt;/a&gt;
 — Mario Vargas Llosa&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B003LSTK8G/" target="_blank" rel="noopener"&gt;The Big Short&lt;/a&gt;
 — Michael Lewis&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B07P1NNTSD/" target="_blank" rel="noopener"&gt;The Man Who Solved the Market&lt;/a&gt;
 — Gregory Zuckerman&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B09RXQRKTF" target="_blank" rel="noopener"&gt;Like, Comment, Subscribe&lt;/a&gt;
 — Mark Bergen&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B09WJLY9JP" target="_blank" rel="noopener"&gt;The Woman Who Split the Atom&lt;/a&gt;
 — Marissa Moss&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B000OZ0J0W" target="_blank" rel="noopener"&gt;American Prometheus&lt;/a&gt;
 — Kai Bird &amp;amp; Martin J. Sherwin&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B07WHKQWN2" target="_blank" rel="noopener"&gt;And or Not&lt;/a&gt;
 — George Boole&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B0B6YDQJW2" target="_blank" rel="noopener"&gt;Androids&lt;/a&gt;
 — Chet Haase&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B00M284HDO" target="_blank" rel="noopener"&gt;Dataclysm&lt;/a&gt;
 — Christian Rudder&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B0BX4S57GM" target="_blank" rel="noopener"&gt;Elon Musk&lt;/a&gt;
 — Walter Isaacson&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B07VTQT95V" target="_blank" rel="noopener"&gt;Infinite Powers&lt;/a&gt;
 — Steven Strogatz&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B0BWSL6BFL" target="_blank" rel="noopener"&gt;Your Face Belongs to Us&lt;/a&gt;
 — Kashmir Hill&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B0CD8V9SHD" target="_blank" rel="noopener"&gt;Going Infinite&lt;/a&gt;
 — Michael Lewis&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B0C1PQ7MZC" target="_blank" rel="noopener"&gt;Extremely Online&lt;/a&gt;
 — Taylor Lorenz&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B0BTZ51JVH" target="_blank" rel="noopener"&gt;Breaking Twitter&lt;/a&gt;
 — Ben Mezrich&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="2022"&gt;2022&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1627790365/" target="_blank" rel="noopener"&gt;Algorithms to Live By&lt;/a&gt;
 — Tom Griffiths&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B08SH41ZJ9/" target="_blank" rel="noopener"&gt;Quantum Physics for Beginners&lt;/a&gt;
 — Darrell Ason&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.packtpub.com/product/dancing%e2%80%94with%e2%80%94qubits/9781838827366" target="_blank" rel="noopener"&gt;Dancing with Qubits&lt;/a&gt;
 — Robert S. Sutor&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/0063076098/" target="_blank" rel="noopener"&gt;The Storyteller&lt;/a&gt;
 — Dave Grohl&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B0833FBNHV/" target="_blank" rel="noopener"&gt;The Pragmatic Programmer&lt;/a&gt;
 — David Thomas and Andrew Hunt&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1647823196/" target="_blank" rel="noopener"&gt;The Messenger&lt;/a&gt;
 — Peter Loftus&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B09CZF2Z1G/" target="_blank" rel="noopener"&gt;The Antisocial Network&lt;/a&gt;
 — Ben Mezrich&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com.mx/gp/product/6073818181/" target="_blank" rel="noopener"&gt;México, manual de usuario&lt;/a&gt;
 — Chumel Torres&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B003PDMKIY/" target="_blank" rel="noopener"&gt;Hackers&lt;/a&gt;
 — Steven Levy&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1690029994/" target="_blank" rel="noopener"&gt;Tao Te Ching&lt;/a&gt;
 — Lao Tzu&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com.mx/dp/6073820658/" target="_blank" rel="noopener"&gt;El Rey del Cash&lt;/a&gt;
 — Elena Chávez&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/0008305706/" target="_blank" rel="noopener"&gt;Ultralearning&lt;/a&gt;
 — Scott Young&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="2021"&gt;2021&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1982115858/" target="_blank" rel="noopener"&gt;The Code Breaker&lt;/a&gt;
 — Walter Isaacson&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1524763160/" target="_blank" rel="noopener"&gt;A Promised Land&lt;/a&gt;
 — Barack Obama&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/0385546130/" target="_blank" rel="noopener"&gt;How to Avoid a Climate Disaster&lt;/a&gt;
 — Bill Gates&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B083MYJXZT/" target="_blank" rel="noopener"&gt;Caffeine&lt;/a&gt;
 — Michael Pollan&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B096HD4Y8M/" target="_blank" rel="noopener"&gt;Epidemiology&lt;/a&gt;
 — Rodolfo Saracci&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B08KWR85F8/" target="_blank" rel="noopener"&gt;Working in Public&lt;/a&gt;
 — Nadia Eghbal&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B071S8BNDP/" target="_blank" rel="noopener"&gt;Leonardo da Vinci&lt;/a&gt;
 — Walter Isaacson&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B07Y3TJ163/" target="_blank" rel="noopener"&gt;No Filter&lt;/a&gt;
 — Sarah Frier&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B08VWV2WDK/" target="_blank" rel="noopener"&gt;A Thousand Brains&lt;/a&gt;
 — Jeff Hawkins&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B01IW9TM5O/" target="_blank" rel="noopener"&gt;Born a Crime&lt;/a&gt;
 — Trevor Noah&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com.mx/dp/6074383987/" target="_blank" rel="noopener"&gt;El Mundo de Sofía&lt;/a&gt;
 — Jostein Gaarder&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1599869772/" target="_blank" rel="noopener"&gt;The Art Of War&lt;/a&gt;
 — Sun Tzu&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B01558MH02/" target="_blank" rel="noopener"&gt;The Science of Everyday Life&lt;/a&gt;
 — Marty Jopson&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="2019"&gt;2019&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1501119923/" target="_blank" rel="noopener"&gt;Thanks a Thousand&lt;/a&gt;
 — A. J. Jacobs&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/0525536515/" target="_blank" rel="noopener"&gt;Digital Minimalism&lt;/a&gt;
 — Cal Newport&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1784759481/" target="_blank" rel="noopener"&gt;Ask an Astronaut&lt;/a&gt;
 — Tim Peake&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/154176238X/" target="_blank" rel="noopener"&gt;Cult of Dead Cow&lt;/a&gt;
 — Joseph Menn&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1416505210/" target="_blank" rel="noopener"&gt;Hunt for the Skinwalker&lt;/a&gt;
 — Colm A. Kelleher &amp;amp; George Knapp&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/0062464396/" target="_blank" rel="noopener"&gt;The Flight&lt;/a&gt;
 — Dan Hampton&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/0399592091/" target="_blank" rel="noopener"&gt;The Ride of a Lifetime&lt;/a&gt;
 — Robert Iger&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1250237238/" target="_blank" rel="noopener"&gt;Permanent Record&lt;/a&gt;
 — Edward Snowden&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1517709075/" target="_blank" rel="noopener"&gt;El Principe&lt;/a&gt;
 — Nicolas Maquiavelo&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/0307745171/" target="_blank" rel="noopener"&gt;Slim&lt;/a&gt;
 — Osorno Diego Enrique&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/1781688133/" target="_blank" rel="noopener"&gt;Four Futures&lt;/a&gt;
 — Peter Frase&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amazon.com/dp/B00TP07B0I" target="_blank" rel="noopener"&gt;The Plane That Wasn&amp;rsquo;t There&lt;/a&gt;
 — Jeff Wise&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>Windows Terminal &amp; Nushell</title><link>https://abeestrada.com/post/windows-terminal-nushell/</link><pubDate>Sun, 08 Feb 2026 22:00:00 -0700</pubDate><guid isPermaLink="true">https://abeestrada.com/post/windows-terminal-nushell/</guid><description>&lt;figure class="w-full" &gt;
 
 &lt;picture&gt;
 
 
 &lt;img src="https://cdn.abeestrada.com/images/2026/windows-terminal.jpg" loading="lazy"&gt;
 &lt;/picture&gt;
 
 
 &lt;/figure&gt;

&lt;p&gt;Les voy a contar cómo terminé usando &lt;a href="https://www.nushell.sh/" target="_blank" rel="noopener"&gt;Nushell&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;Por causas ajenas a mí, tengo que trabajar en este entorno:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;256 GB de espacio en disco&lt;/li&gt;
&lt;li&gt;16 GB de RAM&lt;/li&gt;
&lt;li&gt;Windows 11&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Solo necesito mis aplicaciones en la terminal y un navegador. Eso es todo para trabajar.&lt;/p&gt;
&lt;p&gt;Empecé usando WSL 2 con Debian. Funcionaba muy bien: ZSH era rápido y cómodo. Pero el espacio en disco se volvió un problema, así que decidí desinstalarlo.&lt;/p&gt;
&lt;p&gt;Después descargué &lt;a href="https://alacritty.org/" target="_blank" rel="noopener"&gt;Alacritty&lt;/a&gt;
, pensando que la terminal de Windows era la lenta… pero no. El verdadero cuello de botella era PowerShell.&lt;/p&gt;
&lt;figure class="w-full" &gt;
 
 &lt;picture&gt;
 
 
 &lt;img src="https://cdn.abeestrada.com/images/2026/powershell.jpg" loading="lazy"&gt;
 &lt;/picture&gt;
 
 
 &lt;/figure&gt;

&lt;p&gt;Así fue como probé Nushell. Para mi sorpresa (hasta ahora), es lo único que me ha funcionado bien dentro de mis limitaciones. Luego descubrí que no es POSIX-compliant y que fue creada por una &lt;a href="https://www.sophiajt.com/introducing-nushell/" target="_blank" rel="noopener"&gt;ex empleada de Microsoft&lt;/a&gt;
. Ahora tiene sentido que sea tan rápida en Windows.&lt;/p&gt;
&lt;figure class="w-full" &gt;
 
 &lt;picture&gt;
 
 
 &lt;img src="https://cdn.abeestrada.com/images/2026/nushell.jpg" loading="lazy"&gt;
 &lt;/picture&gt;
 
 
 &lt;/figure&gt;

&lt;p&gt;La diferencia de incluso un segundo es muy notable. Además, incluye todas las herramientas básicas que uso, así que no creo que me cueste acostumbrarme.&lt;/p&gt;
&lt;p&gt;En macOS y Linux seguiré usando ZSH, pero si no fuera por esta situación particular, nunca le habría dado una oportunidad a Nushell.&lt;/p&gt;</description></item><item><title>Minimal Arch Linux</title><link>https://abeestrada.com/post/minimal-arch-linux/</link><pubDate>Sun, 28 Dec 2025 00:00:00 -0700</pubDate><guid isPermaLink="true">https://abeestrada.com/post/minimal-arch-linux/</guid><description>&lt;p&gt;Desde que reparé mi vieja &lt;a href="https://abeestrada.com/post/macbook-pro-mid-2010-330uf-capacitor-c9560/"&gt;MacBook Pro&lt;/a&gt;
, se ha convertido en mi máquina principal con Linux. Todo comenzó cuando descubrí los &lt;em&gt;tiling window managers&lt;/em&gt; con &lt;a href="https://i3wm.org/" target="_blank" rel="noopener"&gt;i3&lt;/a&gt;
, del que me hice rápidamente fan. Luego, al migrar a &lt;a href="https://wayland.freedesktop.org/" target="_blank" rel="noopener"&gt;Wayland&lt;/a&gt;
, empecé a usar &lt;a href="https://swaywm.org/" target="_blank" rel="noopener"&gt;Sway&lt;/a&gt;
, y ahora, gracias a una reciente actualización de &lt;a href="https://yalter.github.io/niri/" target="_blank" rel="noopener"&gt;Niri&lt;/a&gt;
, este gestor de ventanas ya funciona en mi viejo equipo.&lt;/p&gt;
&lt;p&gt;Actualmente, considero que esta es la configuración que más me ha gustado hasta la fecha.&lt;/p&gt;
&lt;figure class="w-full" &gt;
 
 &lt;picture&gt;
 
 
 &lt;img src="https://cdn.abeestrada.com/images/2025/minimal-arch-linux.png" loading="lazy"&gt;
 &lt;/picture&gt;
 
 
 &lt;/figure&gt;

&lt;p&gt;Es una instalación base de Arch Linux con los siguientes paquetes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;niri&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;brightnessctl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;firefox&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fuzzel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kitty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mako&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;playerctl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;swaylock&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;udiskie&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xdg-utils&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En mi búsqueda leí que varias personas recomiendan &lt;a href="https://noctalia.dev/" target="_blank" rel="noopener"&gt;Noctalia&lt;/a&gt;
 como un &lt;em&gt;shell&lt;/em&gt; para Wayland, pero la verdad es que no lo he visto necesario hasta ahora. Todo lo que necesito lo consigo directamente desde la terminal: uso &lt;a href="https://yazi-rs.github.io/" target="_blank" rel="noopener"&gt;Yazi&lt;/a&gt;
 como explorador de archivos, &lt;a href="https://github.com/itsjunetime/tdf" target="_blank" rel="noopener"&gt;tdf&lt;/a&gt;
 o el navegador para ver archivos PDF, Kitty incluye un visualizador de imágenes mediante el comando &lt;code&gt;kitten icat&lt;/code&gt;, y &lt;a href="https://mpv.io/" target="_blank" rel="noopener"&gt;mpv&lt;/a&gt;
 para reproducir video y audio.&lt;/p&gt;
&lt;p&gt;Escuchando música desde YouTube con mpv, navegando por algunas páginas de noticias y editando texto en la terminal, no he superado los 2 GB de uso de memoria RAM.&lt;/p&gt;
&lt;p&gt;Después de muchos intentos, ajustes y experimentos, esta es, sin duda, la instalación mínima de Arch Linux que más me ha gustado. Es ligera, funcional y se adapta perfectamente a lo que realmente uso: la terminal, un buen gestor de ventanas y unas pocas herramientas bien elegidas. A veces, menos es más.&lt;/p&gt;</description></item><item><title>Nuevo Método HTTP Query →</title><link>https://www.ietf.org/archive/id/draft-ietf-httpbis-safe-method-w-body-14.html</link><pubDate>Thu, 20 Nov 2025 19:00:00 -0700</pubDate><guid isPermaLink="true">https://abeestrada.com/post/nuevo-m%C3%A9todo-http-query/</guid><description>&lt;p&gt;TL;DR Es GET con &amp;ldquo;body&amp;rdquo;&lt;/p&gt;
&lt;p&gt;El método HTTP QUERY es un método de solicitud seguro e idempotente que permite enviar consultas complejas como contenido de la solicitud en lugar de codificarlas en la URI. Este método proporciona una solución entre GET y POST, ofreciendo las ventajas de ambos y garantizando al mismo tiempo que la solicitud sea segura e idempotente. El método QUERY también permite a los servidores asignar URI a las consultas o a los resultados de las consultas para su posterior uso.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://abeestrada.com/post/nuevo-m%C3%A9todo-http-query/" target="_blank" title="permalink"&gt;#&lt;/a&gt;&lt;/p&gt;</description></item><item><title>How Complex Systems Fail →</title><link>https://how.complexsystems.fail/</link><pubDate>Thu, 23 Oct 2025 15:40:00 -0600</pubDate><guid isPermaLink="true">https://abeestrada.com/post/how-complex-systems-fail/</guid><description>&lt;p&gt;Excelente ensayo del &lt;a href="https://en.wikipedia.org/wiki/Richard_Cook_%28safety_researcher%29" target="_blank" rel="noopener"&gt;Dr. Richard I. Cook&lt;/a&gt;
 sobre como las fallas en sistemas complejos son inherentes a la naturaleza de estos y sobre como nunca hay una única falla, sino una reacción en cadena de múltiples fallas, que desencadenan en la catástrofe de estos sistemas.&lt;/p&gt;
&lt;p&gt;Todo esto con relación sobre la pasada falla que tuvieron los servicios de AWS en la región &lt;code&gt;us-east-1&lt;/code&gt; y la explicación en su &lt;a href="https://aws.amazon.com/message/101925/" target="_blank" rel="noopener"&gt;postmortem&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://abeestrada.com/post/how-complex-systems-fail/" target="_blank" title="permalink"&gt;#&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Principios SOLID y React</title><link>https://abeestrada.com/post/principios-solid-y-react/</link><pubDate>Wed, 15 Oct 2025 11:00:00 -0600</pubDate><guid isPermaLink="true">https://abeestrada.com/post/principios-solid-y-react/</guid><description>&lt;p&gt;La aplicación de los principios &lt;a href="https://en.wikipedia.org/wiki/SOLID" target="_blank" rel="noopener"&gt;SOLID&lt;/a&gt;
 en React ayuda a escribir código fácil de mantener, escalable y comprobable. Aunque SOLID se diseñó originalmente para la programación orientada a objetos, muchas de sus ideas se adaptan bien a la arquitectura basada en componentes de React.&lt;/p&gt;
&lt;h4 id="1-single-responsibility-principle-srp"&gt;1. Single Responsibility Principle (SRP)&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Un componente (o función/clase) solo debe tener una razón para cambiar.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Modo incorrecto:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserProfile&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;setUser&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useState&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;User&lt;/span&gt; | &lt;span style="color:#e06c75"&gt;null&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;setName&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useState&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;email&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;setEmail&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useState&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;useEffect&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetchUser&lt;/span&gt;().&lt;span style="color:#e06c75"&gt;then&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;setUser&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, []);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;validateEmail&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;email&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#98c379"&gt;/\S+@\S+\.\S+/&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;test&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;email&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;handleSubmit&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;&lt;span style="color:#e06c75"&gt;validateEmail&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;email&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;alert&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Invalid email&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;updateUser&lt;/span&gt;({ &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;email&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;h1&lt;/span&gt;&amp;gt;{&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;?&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;}&amp;lt;/&lt;span style="color:#e06c75"&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;} &lt;span style="color:#e06c75"&gt;onChange&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;e&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setName&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;e&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;)} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;email&lt;/span&gt;} &lt;span style="color:#e06c75"&gt;onChange&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;e&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setEmail&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;e&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;)} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;button&lt;/span&gt; &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;handleSubmit&lt;/span&gt;}&amp;gt;&lt;span style="color:#e06c75"&gt;Save&lt;/span&gt;&amp;lt;/&lt;span style="color:#e06c75"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Solución: Dividir responsabilidades&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// 1. Data fetching
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useUser&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;setUser&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useState&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;User&lt;/span&gt; | &lt;span style="color:#e06c75"&gt;null&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;useEffect&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetchUser&lt;/span&gt;().&lt;span style="color:#e06c75"&gt;then&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;setUser&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, []);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;user&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// 2. Validation logic
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useEmailValidation&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;validate&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;email&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#98c379"&gt;/\S+@\S+\.\S+/&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;test&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;email&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;validate&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// 3. UI Component
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserProfileFormProps&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;onSave&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;data&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;; &lt;span style="color:#e06c75"&gt;email&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserProfileForm&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;React.FC&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;UserProfileFormProps&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;onSave&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;setName&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useState&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;email&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;setEmail&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useState&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;validate&lt;/span&gt; } &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useEmailValidation&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;handleSubmit&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;&lt;span style="color:#e06c75"&gt;validate&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;email&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;alert&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Invalid email&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;onSave&lt;/span&gt;({ &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;email&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;} &lt;span style="color:#e06c75"&gt;onChange&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;e&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setName&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;e&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;)} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;email&lt;/span&gt;} &lt;span style="color:#e06c75"&gt;onChange&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;e&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setEmail&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;e&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;)} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;button&lt;/span&gt; &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;handleSubmit&lt;/span&gt;}&amp;gt;&lt;span style="color:#e06c75"&gt;Save&lt;/span&gt;&amp;lt;/&lt;span style="color:#e06c75"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// 4. Main container
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserProfile&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;user&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useUser&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;handleSave&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;data&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;; &lt;span style="color:#e06c75"&gt;email&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;updateUser&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;data&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;) &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;&lt;span style="color:#e06c75"&gt;Loading&lt;/span&gt;...&amp;lt;/&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;h1&lt;/span&gt;&amp;gt;{&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;}&amp;lt;/&lt;span style="color:#e06c75"&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;UserProfileForm&lt;/span&gt; &lt;span style="color:#e06c75"&gt;onSave&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;handleSave&lt;/span&gt;} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cada parte tiene una responsabilidad: obtención de datos, validación, interfaz de usuario u orquestación.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="2-openclosed-principle-ocp"&gt;2. Open/Closed Principle (OCP)&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Los componentes deben estar abiertos a la ampliación, pero cerrados a la modificación.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Modo incorrecto:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Notification&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; ({ &lt;span style="color:#c678dd"&gt;type&lt;/span&gt; }&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;type&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;success&amp;#34;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;error&amp;#34;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;warning&amp;#34;&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;color&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;gray&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;success&amp;#34;&lt;/span&gt;) &lt;span style="color:#e06c75"&gt;color&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;green&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;else&lt;/span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;error&amp;#34;&lt;/span&gt;) &lt;span style="color:#e06c75"&gt;color&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;red&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;else&lt;/span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;warning&amp;#34;&lt;/span&gt;) &lt;span style="color:#e06c75"&gt;color&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;orange&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;div&lt;/span&gt; &lt;span style="color:#e06c75"&gt;style&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{{ &lt;span style="color:#e06c75"&gt;color&lt;/span&gt; }}&amp;gt;{&lt;span style="color:#c678dd"&gt;type&lt;/span&gt;} &lt;span style="color:#e06c75"&gt;message&lt;/span&gt;&amp;lt;/&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Para añadir un nuevo tipo es necesario modificar este componente.&lt;/p&gt;
&lt;p&gt;Solución: Utilizar estrategia o configuración&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;notificationStyles&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Record&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;string&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;React.CSSProperties&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;success&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;color&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;green&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;color&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;red&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;warning&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;color&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;orange&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;info&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;color&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;blue&amp;#34;&lt;/span&gt; }, &lt;span style="color:#7f848e"&gt;// easily extensible
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;NotificationProps&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;type&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;keyof&lt;/span&gt; &lt;span style="color:#c678dd"&gt;typeof&lt;/span&gt; &lt;span style="color:#e06c75"&gt;notificationStyles&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Notification&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;React.FC&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;NotificationProps&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; ({ &lt;span style="color:#c678dd"&gt;type&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;div&lt;/span&gt; &lt;span style="color:#e06c75"&gt;style&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;notificationStyles&lt;/span&gt;[&lt;span style="color:#c678dd"&gt;type&lt;/span&gt;]}&amp;gt;{&lt;span style="color:#c678dd"&gt;type&lt;/span&gt;} &lt;span style="color:#e06c75"&gt;message&lt;/span&gt;&amp;lt;/&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Se puede ampliar el comportamiento sin cambiar el componente.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="3-liskov-substitution-principle-lsp"&gt;3. Liskov Substitution Principle (LSP)&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Los subtipos (por ejemplo, componentes o hooks) deben ser sustituibles por sus tipos base.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;En React, esto suele aplicarse a los props de los componentes o a los hooks personalizados.&lt;/p&gt;
&lt;p&gt;Modo incorrecto:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ButtonProps&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;variant&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;primary&amp;#34;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;secondary&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;PrimaryButton&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;React.FC&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;ButtonProps&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;button&lt;/span&gt; &lt;span style="color:#e06c75"&gt;className&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;primary&amp;#34;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;DestructiveButton&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;React.FC&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;ButtonProps&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;button&lt;/span&gt; &lt;span style="color:#e06c75"&gt;className&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;danger&amp;#34;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;} /&amp;gt; &lt;span style="color:#7f848e"&gt;// ignores variant!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Si se sustituye &lt;code&gt;PrimaryButton&lt;/code&gt; por &lt;code&gt;DestructiveButton&lt;/code&gt;, el comportamiento cambia de forma inesperada.&lt;/p&gt;
&lt;p&gt;Solución: Respetar el contrato.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ThemedButton&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;React.FC&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;ButtonProps&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;variant&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;className&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;variant&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;primary&amp;#34;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;?&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;primary&amp;#34;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;secondary&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;button&lt;/span&gt; &lt;span style="color:#e06c75"&gt;className&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;className&lt;/span&gt;} &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;} /&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Or a more flexible interface
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;FlexibleButtonProps&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;theme&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;primary&amp;#34;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;secondary&amp;#34;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;danger&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cualquier componente que implemente la misma interfaz se comporta de manera coherente.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="4-interface-segregation-principle-isp"&gt;4. Interface Segregation Principle (ISP)&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;No obligues a los clientes a depender de interfaces que no utilizan.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;En React, esto significa evitar los props excesivos.&lt;/p&gt;
&lt;p&gt;Modo incorrecto:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserCardProps&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;user&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;User&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;onEdit&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;?:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;onDelete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;?:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;showActions?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;isEditable?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;isAdminView?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// ... 10 more optional props
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserCard&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;React.FC&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;UserCardProps&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;props&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {&lt;span style="color:#7f848e"&gt;/* complex logic */&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La mayoría de los usos solo necesitan &lt;code&gt;user&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Solución: Dividir en componentes específicos.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Minimal version
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;SimpleUserCard&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;React.FC&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;&amp;lt;&lt;/span&gt;{ &lt;span style="color:#e06c75"&gt;user&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;User&lt;/span&gt; }&lt;span style="color:#56b6c2"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;user&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;{&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;}&amp;lt;/&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// With actions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;EditableUserCard&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;React.FC&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;&amp;lt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;user&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;User&lt;/span&gt;; &lt;span style="color:#e06c75"&gt;onEdit&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt;; &lt;span style="color:#e06c75"&gt;onDelete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#56b6c2"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;user&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;onEdit&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;onDelete&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;SimpleUserCard&lt;/span&gt; &lt;span style="color:#e06c75"&gt;user&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;button&lt;/span&gt; &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;onEdit&lt;/span&gt;}&amp;gt;&lt;span style="color:#e06c75"&gt;Edit&lt;/span&gt;&amp;lt;/&lt;span style="color:#e06c75"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;button&lt;/span&gt; &lt;span style="color:#e06c75"&gt;onClick&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;onDelete&lt;/span&gt;}&amp;gt;&lt;span style="color:#e06c75"&gt;Delete&lt;/span&gt;&amp;lt;/&lt;span style="color:#e06c75"&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Los consumidores solo dependen de lo que necesitan.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="5-dependency-inversion-principle-dip"&gt;5. Dependency Inversion Principle (DIP)&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Los módulos de alto nivel no deben depender de detalles de bajo nivel. Dependen de abstracciones.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;En React, esto significa desacoplar los componentes de los servicios concretos (por ejemplo, los clientes API).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserProfile&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;setUser&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useState&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;User&lt;/span&gt; | &lt;span style="color:#e06c75"&gt;null&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;useEffect&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// Direct dependency on concrete implementation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;axios&lt;/span&gt;.&lt;span style="color:#c678dd"&gt;get&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;/api/user&amp;#34;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;then&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;res&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setUser&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;res&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;data&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, []);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;{&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;?&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;}&amp;lt;/&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Es difícil probar o cambiar la capa API.&lt;/p&gt;
&lt;p&gt;Solución: Inyectar dependencias&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Abstraction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getUser&lt;/span&gt;()&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Promise&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;User&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Concrete implementation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ApiUserService&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;UserService&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getUser&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;axios&lt;/span&gt;.&lt;span style="color:#c678dd"&gt;get&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;/api/user&amp;#34;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;then&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;res&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;res&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;data&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// For testing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;MockUserService&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;UserService&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getUser&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Promise&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;resolve&lt;/span&gt;({ &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;1&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Test&amp;#34;&lt;/span&gt; }),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Component depends on abstraction
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserProfileProps&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;userService&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;UserService&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserProfile&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;React.FC&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;UserProfileProps&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;userService&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;setUser&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;useState&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;User&lt;/span&gt; | &lt;span style="color:#e06c75"&gt;null&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;useEffect&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;userService&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;getUser&lt;/span&gt;().&lt;span style="color:#e06c75"&gt;then&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;setUser&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, [&lt;span style="color:#e06c75"&gt;userService&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;{&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;?&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;}&amp;lt;/&lt;span style="color:#e06c75"&gt;div&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Usage
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;UserProfile&lt;/span&gt; &lt;span style="color:#e06c75"&gt;userService&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;{&lt;span style="color:#e06c75"&gt;ApiUserService&lt;/span&gt;} /&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Intercambiable, comprobable y desacoplado.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;En resúmen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SRP: Dividir componentes/hooks por interés (interfaz de usuario, lógica, datos)&lt;/li&gt;
&lt;li&gt;OCP: Diseñar componentes que admitan extensiones (por ejemplo, mediante props u objetos de configuración).&lt;/li&gt;
&lt;li&gt;LSP: Asegurarse de que los sustitutos de los componentes se comporten de manera coherente.&lt;/li&gt;
&lt;li&gt;ISP: Evita la sobrecarga de propiedades; crea API de componentes específicas.&lt;/li&gt;
&lt;li&gt;DIP: Inyectar servicios (clientes API, etc.) en lugar de codificarlos directamente.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;Al aplicar SOLID en React, se crean aplicaciones más fáciles de probar, refactorizar y escalar, incluso en un marco de interfaz de usuario declarativo y funcional.&lt;/p&gt;</description></item><item><title>Astro Build Time</title><link>https://abeestrada.com/post/astro-build-time/</link><pubDate>Thu, 02 Oct 2025 16:00:00 -0600</pubDate><guid isPermaLink="true">https://abeestrada.com/post/astro-build-time/</guid><description>&lt;p&gt;Tengo una página web construida con &lt;a href="https://astro.build/" target="_blank" rel="noopener"&gt;Astro&lt;/a&gt;
 y noté que el tiempo de compilación había aumentado a más de un minuto para generar aproximadamente 500 páginas estáticas.&lt;/p&gt;
&lt;p&gt;Buscando optimizaciones, la recomendación general era clara: evitar ejecutar cualquier operación &lt;code&gt;fetch&lt;/code&gt; dentro de las páginas que se generan dinámicamente o que utilizan la función &lt;code&gt;getStaticPaths&lt;/code&gt;. Por ello, tomé la decisión de migrar estas páginas a la nueva API de &amp;ldquo;Content Collections&amp;rdquo; de Astro, una funcionalidad que no estaba disponible cuando el sitio fue creado.&lt;/p&gt;
&lt;p&gt;El cambio realizado fue el siguiente:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-diff" data-lang="diff"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;-export const getStaticPaths = async () =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;- const res = await fetch(`${API_URL}/podcasts`, {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;- headers: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;- &amp;#34;Content-Type&amp;#34;: &amp;#34;application/json&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;- },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;- method: &amp;#34;GET&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;- });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;- const { podcasts } = await res?.json();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;- return podcasts.map((podcast) =&amp;gt; ({
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;- params: { podcast: podcast.id },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;- }));
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;-};
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#98c379;font-weight:bold"&gt;+import { getCollection } from &amp;#34;astro:content&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#98c379;font-weight:bold"&gt;+export async function getStaticPaths() {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#98c379;font-weight:bold"&gt;+ const podcasts = await getCollection(&amp;#34;podcasts&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#98c379;font-weight:bold"&gt;+ return podcasts.map((podcast) =&amp;gt; ({
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#98c379;font-weight:bold"&gt;+ params: { podcast: podcast.id },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#98c379;font-weight:bold"&gt;+ }));
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#98c379;font-weight:bold"&gt;+}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Con esta migración, logré que las 500 páginas dejen de hacer llamadas individuales a la API.&lt;/p&gt;
&lt;p&gt;Ahora, toda la información necesaria se captura una sola vez al inicio del proceso de &lt;code&gt;build&lt;/code&gt; y se almacena en memoria. Esto garantiza que el tiempo de acceso sea casi inmediato y elimina los costos de latencia. El resultado fue una mejora drástica: el tiempo de carga pasó de 100 ms a solo 1 ms por página.&lt;/p&gt;
&lt;p&gt;Esta optimización se refleja directamente en una reducción significativa del tiempo total de generación del sitio.&lt;/p&gt;
&lt;figure class="w-1/2" &gt;
 
 &lt;picture&gt;
 
 
 &lt;img src="https://cdn.abeestrada.com/images/2025/astro-build-time.jpg" loading="lazy"&gt;
 &lt;/picture&gt;
 
 
 &lt;/figure&gt;

&lt;p&gt;Fuente:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.astro.build/en/guides/content-collections/" target="_blank" rel="noopener"&gt;Content Collections&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Protocolos para APIs</title><link>https://abeestrada.com/post/protocolos-para-apis/</link><pubDate>Sun, 24 Aug 2025 22:55:00 -0600</pubDate><guid isPermaLink="true">https://abeestrada.com/post/protocolos-para-apis/</guid><description>&lt;p&gt;En el mundo del desarrollo de software, las APIs (Interfaces de Programación de Aplicaciones) son el puente que permite la comunicación entre diferentes sistemas. Sin embargo, elegir el protocolo adecuado para una API no es solo una decisión técnica: puede marcar la diferencia entre un sistema rápido, seguro y escalable, y uno que sufre de cuellos de botella y limitaciones funcionales.&lt;/p&gt;
&lt;p&gt;Estos son los protocolos más comunes utilizados en APIs, cons sus ventajas, limitaciones y cuándo usar cada uno, basándonos en los fundamentos clave de una arquitectura eficiente.&lt;/p&gt;
&lt;h4 id="http-y-https-la-base-de-las-apis-web"&gt;HTTP y HTTPS: La base de las APIs web&lt;/h4&gt;
&lt;p&gt;HTTP (Hypertext Transfer Protocol) es el protocolo más utilizado en la web. Funciona bajo un modelo de solicitud respuesta: el cliente envía una solicitud y el servidor responde.&lt;/p&gt;
&lt;p&gt;Características clave de HTTP:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Métodos comunes: GET (leer), POST (crear), PUT/PATCH (actualizar), DELETE (eliminar).&lt;/li&gt;
&lt;li&gt;Códigos de estado: 200 (éxito), 400 (error del cliente), 500 (error del servidor).&lt;/li&gt;
&lt;li&gt;Encabezados como &lt;code&gt;Content-Type&lt;/code&gt;, &lt;code&gt;Authorization&lt;/code&gt;, &lt;code&gt;Cache-Control&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Sin embargo, HTTP por sí solo no es seguro. Aquí es donde entra HTTPS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HTTPS = HTTP + TLS/SSL&lt;/p&gt;
&lt;p&gt;HTTPS añade una capa de cifrado que protege los datos en tránsito. Sus beneficios incluyen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Confidencialidad: los datos no pueden ser leídos por terceros.&lt;/li&gt;
&lt;li&gt;Integridad: los datos no pueden ser alterados.&lt;/li&gt;
&lt;li&gt;Autenticación: el cliente puede verificar la identidad del servidor.&lt;/li&gt;
&lt;li&gt;Ventajas SEO: los motores de búsqueda favorecen sitios con HTTPS.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="websockets-comunicación-en-tiempo-real"&gt;WebSockets: Comunicación en tiempo real&lt;/h4&gt;
&lt;p&gt;HTTP es excelente para solicitudes puntuales, pero no es ideal para aplicaciones en tiempo real, como chats, notificaciones o paneles de monitoreo.&lt;/p&gt;
&lt;p&gt;Imagina un chat: si usas HTTP, el cliente debe hacer solicitudes constantes (&amp;quot;¿hay nuevos mensajes?&amp;quot;) incluso cuando no hay novedades. Esto genera:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Alta latencia.&lt;/li&gt;
&lt;li&gt;Uso innecesario de ancho de banda.&lt;/li&gt;
&lt;li&gt;Mayor carga en el servidor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;WebSockets resuelve este problema estableciendo una conexión persistente y bidireccional entre cliente y servidor.&lt;/p&gt;
&lt;p&gt;Cómo funciona:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;El cliente inicia una &amp;ldquo;mano de mano&amp;rdquo; (handshake) con el servidor usando HTTP.&lt;/li&gt;
&lt;li&gt;Una vez establecida, la conexión se convierte en un canal bidireccional.&lt;/li&gt;
&lt;li&gt;El servidor puede enviar datos al cliente en cualquier momento, sin necesidad de que este lo solicite.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ventajas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Latencia mínima.&lt;/li&gt;
&lt;li&gt;Ahorro de ancho de banda.&lt;/li&gt;
&lt;li&gt;Ideal para aplicaciones en tiempo real.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="amqp-mensajería-confiable-entre-servicios"&gt;AMQP: Mensajería confiable entre servicios&lt;/h4&gt;
&lt;p&gt;AMQP (Advanced Message Queuing Protocol) es un protocolo orientado a mensajería, común en entornos empresariales.&lt;/p&gt;
&lt;p&gt;Funciona con un modelo de productor-consumidor y un broker de mensajes (como RabbitMQ):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;El productor (por ejemplo, un sistema de pedidos) envía un mensaje a una cola.&lt;/li&gt;
&lt;li&gt;El consumidor (por ejemplo, un sistema de notificaciones) lo procesa cuando esté disponible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Beneficios de AMQP:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Desacoplamiento: los servicios no necesitan estar activos al mismo tiempo.&lt;/li&gt;
&lt;li&gt;Garantía de entrega: los mensajes no se pierden si el consumidor está caído.&lt;/li&gt;
&lt;li&gt;Escalabilidad: puedes tener múltiples consumidores procesando mensajes en paralelo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="grpc-alto-performance-para-microservicios"&gt;gRPC: Alto performance para microservicios&lt;/h4&gt;
&lt;p&gt;Desarrollado por Google, gRPC es un framework de comunicación de alto performance que utiliza:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP/2 como protocolo de transporte.&lt;/li&gt;
&lt;li&gt;Protocol Buffers (protobuf) para serialización eficiente de datos.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ventajas de gRPC:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Muy rápido y eficiente en el uso de recursos.&lt;/li&gt;
&lt;li&gt;Soporta streaming bidireccional (cliente y servidor pueden enviar flujos de datos).&lt;/li&gt;
&lt;li&gt;Ideal para comunicación entre microservicios en un entorno backend.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="conclusión"&gt;Conclusión&lt;/h4&gt;
&lt;p&gt;Los protocolos más comunes HTTP/HTTPS, WebSockets, AMQP y gRPC cubren alrededor del 90% de los casos de uso en APIs modernas. La clave está en entender sus fortalezas y elegir el que mejor se adapte a tu escenario.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Usa HTTP/HTTPS como predeterminado para APIs web.&lt;/li&gt;
&lt;li&gt;Opta por WebSockets en aplicaciones en tiempo real.&lt;/li&gt;
&lt;li&gt;Implementa AMQP para mensajería confiable y desacoplada.&lt;/li&gt;
&lt;li&gt;Considera gRPC para comunicaciones de alto rendimiento entre servicios.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>macOS Daemons/LaunchAgents</title><link>https://abeestrada.com/post/macos-daemons/launchagents/</link><pubDate>Thu, 14 Aug 2025 21:00:00 -0600</pubDate><guid isPermaLink="true">https://abeestrada.com/post/macos-daemons/launchagents/</guid><description>&lt;p&gt;A diferencia de Linux, donde se utiliza comúnmente cron para tareas programadas, en macOS el enfoque recomendado son los &lt;code&gt;daemons&lt;/code&gt; y los &lt;code&gt;launch agents&lt;/code&gt;. Aunque &lt;code&gt;crontab&lt;/code&gt; existe en macOS, no es la forma preferida para ejecutar servicios o comandos de forma periódica.&lt;/p&gt;
&lt;p&gt;Un &lt;code&gt;daemon&lt;/code&gt; se utiliza principalmente para procesos del sistema o aplicaciones de línea de comandos que corren independientemente del usuario. Por otro lado, un &lt;code&gt;launch agent&lt;/code&gt; está asociado a una sesión de usuario y puede interactuar con aplicaciones gráficas, por lo que es más adecuado para tareas específicas del usuario.&lt;/p&gt;
&lt;p&gt;Hace tiempo que utilizo &lt;code&gt;aerc&lt;/code&gt; como cliente de correo, ya que permite una conexión IMAP directa. Sin embargo, en esta ocasión necesitaba realizar copias de seguridad automáticas de una cuenta de correo. Para ello, configuré un launch agent que ejecuta &lt;code&gt;mbsync -a&lt;/code&gt; cada cierto intervalo de tiempo.&lt;/p&gt;
&lt;p&gt;Creación del archivo de configuración&lt;/p&gt;
&lt;p&gt;Primero, se debe crear un archivo de configuración en formato &lt;code&gt;.plist&lt;/code&gt;, que es básicamente un XML con un esquema específico. Este archivo debe ubicarse en el directorio &lt;code&gt;~/Library/LaunchAgents/&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="librarylaunchagentscomusermbsyncplist"&gt;&lt;code&gt;~/Library/LaunchAgents/com.user.mbsync.plist&lt;/code&gt;&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;&amp;lt;!DOCTYPE plist PUBLIC &amp;#34;-//Apple//DTD PLIST 1.0//EN&amp;#34; &amp;#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;#34;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;&amp;lt;plist&lt;/span&gt; &lt;span style="color:#e06c75"&gt;version=&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span style="color:#e06c75"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;Label&lt;span style="color:#e06c75"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;com.user.mbsync&lt;span style="color:#e06c75"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;ProgramArguments&lt;span style="color:#e06c75"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/usr/bin/mbsync&lt;span style="color:#e06c75"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;-a&lt;span style="color:#e06c75"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;&amp;lt;!-- 300 seconds = 5 minutes --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StartInterval&lt;span style="color:#e06c75"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;integer&amp;gt;&lt;/span&gt;300&lt;span style="color:#e06c75"&gt;&amp;lt;/integer&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;&amp;lt;!-- Run immediately when loaded --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;RunAtLoad&lt;span style="color:#e06c75"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;true/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;&amp;lt;!-- Log output --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StandardOutPath&lt;span style="color:#e06c75"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/tmp/mbsync.log&lt;span style="color:#e06c75"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;&amp;lt;!-- Log errors --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;StandardErrorPath&lt;span style="color:#e06c75"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;/tmp/mbsync.error.log&lt;span style="color:#e06c75"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;&amp;lt;/plist&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Una vez creado el archivo, se carga con el siguiente comando:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;launchctl load ~/Library/LaunchAgents/com.user.mbsync.plist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Puedes verificar el estado del agente con:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;launchctl list | grep com.user.mbsync
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Para detener y eliminar la tarea programada, usa:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;launchctl unload ~/Library/LaunchAgents/com.user.mbsync.plist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Notas adicionales:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Asegúrate de que &lt;code&gt;mbsync&lt;/code&gt; esté correctamente configurado en tu sistema.&lt;/li&gt;
&lt;li&gt;Los archivos &lt;code&gt;.plist&lt;/code&gt; deben tener permisos válidos y sintaxis correcta; de lo contrario, &lt;code&gt;launchctl&lt;/code&gt; no los cargará.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Apple silicon: Container →</title><link>https://github.com/apple/container</link><pubDate>Wed, 13 Aug 2025 16:00:00 -0600</pubDate><guid isPermaLink="true">https://abeestrada.com/post/apple-silicon-container/</guid><description>&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brew install container
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;container system start
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;container run hello-world
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://abeestrada.com/post/apple-silicon-container/" target="_blank" title="permalink"&gt;#&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>