<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Emilio Acevedo</title>
    <description>The latest articles on Forem by Emilio Acevedo (@emilioacevedodev).</description>
    <link>https://forem.com/emilioacevedodev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3543177%2Fdc621602-a94a-43d9-b772-4d0b50cd1d01.jpg</url>
      <title>Forem: Emilio Acevedo</title>
      <link>https://forem.com/emilioacevedodev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/emilioacevedodev"/>
    <language>en</language>
    <item>
      <title>My journey from a chaotic, manual agility to a bureaucracy disguised as Scrum. And how we can get back on track.</title>
      <dc:creator>Emilio Acevedo</dc:creator>
      <pubDate>Tue, 21 Oct 2025 02:04:25 +0000</pubDate>
      <link>https://forem.com/emilioacevedodev/my-journey-from-a-chaotic-manual-agility-to-a-bureaucracy-disguised-as-scrum-and-how-we-can-get-1h8h</link>
      <guid>https://forem.com/emilioacevedodev/my-journey-from-a-chaotic-manual-agility-to-a-bureaucracy-disguised-as-scrum-and-how-we-can-get-1h8h</guid>
      <description>&lt;p&gt;In 2018, I landed in a world that called itself "agile." I had never worked with user stories or incremental deliveries, and everything was new to me. Today, after years immersed in a supposed "agile transformation," I ask myself a question that many whisper in the hallways: &lt;strong&gt;are we truly more agile than before, or have we just perfected the art of filling out forms?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I remember those early days. Our Scrum was manual, almost artisanal. User stories were written jointly with the Product Owner, we broke them down into tasks, and we got to work. It had its flaws, of course. Our flow was an internal mini-waterfall: &lt;code&gt;Development -&amp;gt; QA Testing -&amp;gt; PO Approval&lt;/code&gt;. It was imperfect, sometimes chaotic, but it was human. There was a direct connection and a clear goal: to deliver.&lt;/p&gt;

&lt;p&gt;Fast forward to today. We have sophisticated tools, formalized processes, and an agile vocabulary that everyone recites from memory. But that genuine agility feels further away than ever. We've adopted the &lt;strong&gt;rituals&lt;/strong&gt; of Scrum, but we've lost its &lt;strong&gt;spirit&lt;/strong&gt;. We are living in the era of the "Scrum Zombie": we go through the motions, but there's no life.&lt;/p&gt;

&lt;p&gt;These are the pain points I believe many will recognize.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pain Point #1: The Pre-Sprint Gauntlet: Agility by Committee
&lt;/h3&gt;

&lt;p&gt;Before we can write a single line of code, every sprint must survive a bureaucratic maze I call the "sprint before the sprint."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Justification Kickoff:&lt;/strong&gt; A meeting where the PO must "sell" the sprint's value, justifying the investment, calculating ROI, and savings in manual hours. It feels less like the start of an iterative cycle and more like a defense for an annual budget.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The Costing and Planning Review:&lt;/strong&gt; A detailed analysis of costs and timelines that reeks of the waterfall project management we were supposed to leave behind.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The PMO's Blessing:&lt;/strong&gt; Finally, a stamp of approval from the Project Management Office that adds another layer of waiting and bureaucracy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Diagnosis:&lt;/strong&gt; This isn't agility. It's the traditional project management mindset using Scrum terminology. It prioritizes control and prediction over adaptation and rapid value delivery, which are the heart of agility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pain Point #2: The Daily That Became a Status Meeting (While Seated, of Course)
&lt;/h3&gt;

&lt;p&gt;I remember when dailies were 15-minute meetings, standing up, with a single purpose: what blockers do we have, and how can we help each other overcome them?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Today's Reality:&lt;/strong&gt; Those meetings have morphed into 30-to-45-minute sessions. The team no longer collaborates to solve problems; each member reports their status to management. The focus is no longer "how do we move forward together?" but rather "did you justify the hours you were assigned yesterday?".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Diagnosis:&lt;/strong&gt; This is a symptom of a lack of trust. When the daily becomes a status report, the team's self-organization dies. The Scrum Master (or whoever leads the meeting) has shifted from a facilitator who removes impediments to a foreman who oversees progress.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pain Point #3: The Sprint as a Two-Week Mini-Waterfall
&lt;/h3&gt;

&lt;p&gt;This is a problem that has persisted over the years. Although the tools have changed, the underlying workflow remains the same.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Reality:&lt;/strong&gt; Work flows in one direction: all development is completed, then everything moves to QA, and finally, everything is delivered to the PO for approval. A story doesn't move forward until all its tasks are done, and the sprint doesn't end until all stories are approved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Diagnosis:&lt;/strong&gt; This creates massive bottlenecks and delays crucial feedback. True agility aims for a cross-functional team (developers, QA, etc.) to work on &lt;strong&gt;a single story&lt;/strong&gt; until it is &lt;strong&gt;completely done&lt;/strong&gt; (meeting a robust "Definition of Done") before starting the next one. Our model is simply a waterfall with a two-week time limit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion: Small Acts of Rebellion to Revive the 'Scrum Zombie'
&lt;/h3&gt;

&lt;p&gt;We can't change the entire organization overnight, but we can start reclaiming the agile spirit with small, pragmatic actions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Reclaim the Daily Stand-up.&lt;/strong&gt; The first step is the simplest: go back to 15 minutes. Standing up. With a single goal: identify impediments. Anything else is discussed after the meeting, and only with the necessary people.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Advocate for a Real "Definition of Done."&lt;/strong&gt; Let's propose in the retrospective that a story is "done" when it is developed AND tested by QA, not just when the developer finishes their part. This forces collaboration, breaks down silos, and focuses us on delivering functional value increments.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Question Bureaucracy with Data.&lt;/strong&gt; Instead of complaining, let's use the retrospective to measure the time lost. "How many days did we wait for PMO approval this sprint?". Presenting that data isn't a complaint; it's an opportunity for improvement for the entire organization.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A successful sprint isn't one that checks all the ritual boxes, but one that delivers real value to the user and, in the process, teaches us how to be a slightly better team next time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you experience a similar reality in your team? What other "Scrum Zombie" symptoms have you seen? I'd love to read your experiences in the comments.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>scrum</category>
      <category>agile</category>
      <category>devops</category>
      <category>discuss</category>
    </item>
    <item>
      <title>From 3.5 Hours to 30 Minutes: Optimizing C# with LINQ's ToLookup</title>
      <dc:creator>Emilio Acevedo</dc:creator>
      <pubDate>Wed, 15 Oct 2025 01:50:42 +0000</pubDate>
      <link>https://forem.com/emilioacevedodev/from-35-hours-to-30-minutes-optimizing-c-with-linqs-tolookup-31ik</link>
      <guid>https://forem.com/emilioacevedodev/from-35-hours-to-30-minutes-optimizing-c-with-linqs-tolookup-31ik</guid>
      <description>&lt;h2&gt;
  
  
  The Silent Bottleneck: From Fast Process to 3.5-Hour Nightmare
&lt;/h2&gt;

&lt;p&gt;In software development, some processes are born fast and efficient, but as data grows over time, they turn into real bottlenecks. This was the case with our &lt;code&gt;AplicarReglasWithAllReferences&lt;/code&gt; method, a crucial component in pension calculations that, over the months, went from running in minutes to taking a staggering &lt;strong&gt;three and a half hours&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The system became sluggish, users grew impatient, and maintenance became increasingly complex. The culprit wasn't the database or a convoluted business logic, but a very common and dangerously inefficient coding pattern: using &lt;code&gt;.Where()&lt;/code&gt; on lists inside a &lt;code&gt;foreach&lt;/code&gt; loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Anti-Pattern: Death by a Thousand &lt;code&gt;.Where()&lt;/code&gt; Cuts in a Loop
&lt;/h2&gt;

&lt;p&gt;The original logic was simple and straightforward. At the beginning of the method, we loaded several large lists of related data into memory: policies, people, exceptions, coverages, etc. Then, we iterated through the main list of policies and, for each one, looked up its related data in the other lists.&lt;/p&gt;

&lt;p&gt;The code looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Large lists of data are loaded at the start&lt;/span&gt;
&lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Poliza&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;allPolicies&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetPolicies&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RuleException&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;allExceptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetExceptions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Coverage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;allCoverages&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetCoverages&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;poliza&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;allPolicies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// For EACH policy, the ENTIRE list of exceptions is scanned again&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;exceptionsForPolicy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;allExceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IDPoliza&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;poliza&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IDPoliza&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// And the ENTIRE list of coverages is scanned again&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;coveragesForPolicy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;allCoverages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IDPoliza&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;poliza&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IDPoliza&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// ...do something with the found data...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why is this so slow?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer lies in computational complexity. A &lt;code&gt;.Where()&lt;/code&gt; on a list performs a &lt;strong&gt;linear scan (O(N))&lt;/strong&gt;. This means that to find an item, it has to check, in the worst case, all N items in the list. If you do this inside a loop that repeats M times, the total complexity skyrockets to &lt;strong&gt;O(N * M)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you have 100,000 policies (M) and 500,000 exceptions (N), the number of operations is astronomical. You're asking the system to read the entire phone book, over and over, for every person you're looking up.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Elegant Solution: &lt;code&gt;ToLookup&lt;/code&gt; as a High-Speed Index
&lt;/h2&gt;

&lt;p&gt;The solution to this problem is one of LINQ's most powerful and underrated methods: &lt;code&gt;ToLookup()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ToLookup&lt;/code&gt; transforms a list into a dictionary-like structure, but optimized for one-to-many relationships. It works like a book's index: instead of reading the entire book to find a term, you go directly to the correct page.&lt;/p&gt;

&lt;p&gt;Implementing this change is surprisingly simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;One-Time Indexing Cost:&lt;/strong&gt; Before entering the loop, you convert your secondary data lists into an &lt;code&gt;ILookup&lt;/code&gt;. This has an initial cost of O(N) to create the index.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Instantaneous Lookups:&lt;/strong&gt; Inside the loop, you replace the expensive &lt;code&gt;.Where()&lt;/code&gt; with a direct access to the lookup, which is an almost instantaneous operation (O(1)).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The refactored code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Large lists of data are loaded at the start&lt;/span&gt;
&lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Poliza&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;allPolicies&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetPolicies&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RuleException&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;allExceptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetExceptions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;IList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Coverage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;allCoverages&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetCoverages&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// 1. The "indexes" are created once before the loop.&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;exceptionsLookup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;allExceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToLookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IDPoliza&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;coveragesLookup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;allCoverages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToLookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IDPoliza&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;poliza&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;allPolicies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 2. The lookup is now instantaneous (O(1)). No more scans.&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;exceptionsForPolicy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;exceptionsLookup&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;poliza&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IDPoliza&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;coveragesForPolicy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;coveragesLookup&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;poliza&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IDPoliza&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// ...do something with the found data...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The total complexity is now &lt;strong&gt;O(N + M)&lt;/strong&gt;, a drastic improvement over O(N * M).&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Results: An 85% Reduction in Execution Time
&lt;/h2&gt;

&lt;p&gt;By applying this technique to our &lt;code&gt;AplicarReglasWithAllReferences&lt;/code&gt; method, the results were transformative. The process, which used to paralyze the system for &lt;strong&gt;3.5 hours&lt;/strong&gt;, now consistently finishes in &lt;strong&gt;approximately 30 minutes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This represents an &lt;strong&gt;85% reduction in execution time&lt;/strong&gt;, achieved with a minimally invasive yet conceptually powerful code change. We moved from an inefficient algorithm to an optimized one, freeing up system resources and restoring agility to the business process.&lt;/p&gt;

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

&lt;p&gt;If you have a slow process that works with large collections of data in memory, look for this anti-pattern. You'll likely find &lt;code&gt;foreach&lt;/code&gt; loops with &lt;code&gt;.Where()&lt;/code&gt; calls inside. Replacing them with a pre-calculated &lt;code&gt;ILookup&lt;/code&gt; is one of the most effective optimizations you can implement. Not only will you dramatically reduce execution times, but you'll also make your code cleaner and more readable.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>performance</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why I'm Learning 3D Graphics After 20 Years in Tech</title>
      <dc:creator>Emilio Acevedo</dc:creator>
      <pubDate>Sun, 05 Oct 2025 21:02:23 +0000</pubDate>
      <link>https://forem.com/emilioacevedodev/why-im-learning-3d-graphics-after-20-years-in-tech-35c8</link>
      <guid>https://forem.com/emilioacevedodev/why-im-learning-3d-graphics-after-20-years-in-tech-35c8</guid>
      <description>&lt;p&gt;Hello, world. My name is Emilio, and I'm a Senior Software Engineer.&lt;/p&gt;

&lt;p&gt;For the better part of two decades, my world has been one of databases, APIs, massive processes, CI/CD pipelines, and complex enterprise architectures. I've built robust, scalable, and mission-critical applications. It's been a rewarding career, one that has taught me the value of solid foundations and meticulous design.&lt;/p&gt;

&lt;p&gt;But I'm missing something. All this time, I've only created things for others, so I inevitably felt that call, the next step that had to come at some point: the desire to build something completely different. Something visual, interactive, from scratch, and my own.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Itch to Create
&lt;/h3&gt;

&lt;p&gt;I've always been fascinated by virtual worlds and complex simulations, but my professional path led me down the road of enterprise software. Although it has been rewarding, the desire to build something tangible, something you can &lt;em&gt;see&lt;/em&gt; and &lt;em&gt;feel&lt;/em&gt;, has always been a quiet hum in the background.&lt;/p&gt;

&lt;p&gt;This blog is the public chronicle of that new journey. It's my commitment to stepping out of my comfort zone.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Mission: Embracing the Junior Mindset
&lt;/h3&gt;

&lt;p&gt;I'm embarking on my most ambitious personal project to date: a large-scale, interactive 3D experience for the web. For now, I'll call it &lt;strong&gt;"Project S"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My goal is not just to build it, but to document the entire process in public: the good, the bad, and the buggy. This means embracing the humility of being a beginner again. After 20 years of being the "expert" for backend problems, I'm now the student, facing the intimidating interface of Blender and the endless possibilities of Three.js.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Toolkit
&lt;/h3&gt;

&lt;p&gt;My arsenal for this adventure will be a mix of the familiar and the completely new:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;3D Modeling:&lt;/strong&gt; Starting from zero with &lt;strong&gt;Blender&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Rendering:&lt;/strong&gt; Bringing it to life in the browser with &lt;strong&gt;Three.js&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend &amp;amp; Blog:&lt;/strong&gt; This very site (&lt;a href="https://www.emilioacevedo.dev/" rel="noopener noreferrer"&gt;emilioacevedo.dev&lt;/a&gt;), built from scratch with &lt;strong&gt;Astro&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Leveraging my experience with &lt;strong&gt;Node.js, TypeScript,&lt;/strong&gt; and modern cloud architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Promise
&lt;/h3&gt;

&lt;p&gt;So, what can you expect from this space?&lt;/p&gt;

&lt;p&gt;This won't be a polished tutorial series. It will be an unfiltered log of a senior developer tackling a new domain. I'll share architectural decisions, frustrating bugs, performance optimizations, 'aha!' moments in Blender, and the raw code behind it all.&lt;/p&gt;

&lt;p&gt;If you're a developer curious about 3D, a creative professional interested in the tech, or just someone who enjoys watching a complex project come to life, I'd love for you to join me.&lt;/p&gt;

&lt;p&gt;Let's build something cool.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>career</category>
      <category>showdev</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
