<?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>DEV Community: Korir Moses</title>
    <description>The latest articles on DEV Community by Korir Moses (@korirmoze).</description>
    <link>https://dev.to/korirmoze</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%2F991376%2F237dd296-2a00-4817-8eb1-891e2be950f2.jpg</url>
      <title>DEV Community: Korir Moses</title>
      <link>https://dev.to/korirmoze</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/korirmoze"/>
    <language>en</language>
    <item>
      <title>Chauffeur Knowledge in Software Development: When Developers Sound Smart Without Deep Understanding</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Sun, 08 Feb 2026 07:16:55 +0000</pubDate>
      <link>https://dev.to/korirmoze/chauffeur-knowledge-in-software-development-when-developers-sound-smart-without-deep-understanding-2hkb</link>
      <guid>https://dev.to/korirmoze/chauffeur-knowledge-in-software-development-when-developers-sound-smart-without-deep-understanding-2hkb</guid>
      <description>&lt;h2&gt;
  
  
  Let's Be Honest
&lt;/h2&gt;

&lt;p&gt;We've all been that developer in a meeting who confidently throws around terms like "event-driven architecture" or "CQRS pattern" while secretly hoping nobody asks us to explain what those actually mean. &lt;/p&gt;

&lt;p&gt;I know I have.&lt;/p&gt;

&lt;p&gt;There's a great old story that explains this perfectly: A famous scientist had a chauffeur who drove him to lectures across the country. After months of hearing the same speech, the chauffeur memorized it word-for-word. One day, he joked, "I could give that lecture myself!" The scientist, amused, let him try.&lt;/p&gt;

&lt;p&gt;The chauffeur nailed it. Perfect delivery. Standing ovation.&lt;/p&gt;

&lt;p&gt;Then someone asked a follow-up question.&lt;/p&gt;

&lt;p&gt;The chauffeur froze.&lt;/p&gt;

&lt;p&gt;This is what we call "chauffeur knowledge" in software development - and it's everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does This Actually Look Like?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Buzzword Enthusiast
&lt;/h3&gt;

&lt;p&gt;You know this person. Maybe you've been this person.&lt;/p&gt;

&lt;p&gt;They walk into planning meetings with energy: "We need microservices! Event sourcing! Kubernetes!"&lt;/p&gt;

&lt;p&gt;Someone asks, "Why?"&lt;/p&gt;

&lt;p&gt;"Because... that's what successful companies use?"&lt;/p&gt;

&lt;p&gt;Here's the thing: Netflix uses microservices because they have hundreds of developers and millions of users. Your internal tool has three developers and 200 users. You probably need a well-organized monolith, not a distributed nightmare.&lt;/p&gt;

&lt;p&gt;But "microservices" sounds way cooler in your LinkedIn profile.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Framework Wizard (Who Can't Explain JavaScript)
&lt;/h3&gt;

&lt;p&gt;I once worked with a developer who could build beautiful React apps. Seriously impressive stuff. Then our Node.js backend started hanging randomly.&lt;/p&gt;

&lt;p&gt;"It's probably the async calls," I suggested.&lt;/p&gt;

&lt;p&gt;Blank stare.&lt;/p&gt;

&lt;p&gt;"How do promises work?" I asked.&lt;/p&gt;

&lt;p&gt;More blank stares.&lt;/p&gt;

&lt;p&gt;They'd been building async apps for two years without understanding what async actually meant. The framework had hidden all the complexity - until it didn't.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Stack Overflow Speedrunner
&lt;/h3&gt;

&lt;p&gt;We've all done this. Production breaks, you Google the error, find a Stack Overflow answer, copy-paste the solution, push to prod.&lt;/p&gt;

&lt;p&gt;It works! Ship it!&lt;/p&gt;

&lt;p&gt;Three months later, the same bug appears under different conditions. Nobody on the team understands why the fix worked in the first place. You're back to Stack Overflow, finding another patch for your patch.&lt;/p&gt;

&lt;p&gt;This is how legacy codebases are born.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Architecture Tourist
&lt;/h3&gt;

&lt;p&gt;"Let's build our system like Uber's!"&lt;/p&gt;

&lt;p&gt;"Do we have Uber's problems?"&lt;/p&gt;

&lt;p&gt;"Well... no. We have 10 concurrent users max."&lt;/p&gt;

&lt;p&gt;"Do we have Uber's engineering team?"&lt;/p&gt;

&lt;p&gt;"No, there's three of us."&lt;/p&gt;

&lt;p&gt;"So why—"&lt;/p&gt;

&lt;p&gt;"BECAUSE IT'S BEST PRACTICE."&lt;/p&gt;

&lt;p&gt;We love copying what big tech does without asking if we actually need it. It's like buying a semi-truck when you need to move one couch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does This Happen? (And Why It's Not Entirely Our Fault)
&lt;/h2&gt;

&lt;p&gt;Let's be real about why this happens:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tech world moves insanely fast.&lt;/strong&gt; Last week's hot framework is this week's legacy code. We feel like we're constantly playing catch-up, so we memorize instead of understand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Imposter syndrome is real.&lt;/strong&gt; Everyone else seems to know everything, so we fake it. We use complex words to hide that we're still figuring things out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interviews reward memorization.&lt;/strong&gt; "Reverse a binary tree on a whiteboard" doesn't test understanding - it tests whether you memorized the solution the night before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deadlines are brutal.&lt;/strong&gt; "Why does this work?" takes time we don't have. "Does this work?" is all that matters when you're shipping tomorrow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools over fundamentals.&lt;/strong&gt; Bootcamps teach React in week three. Nobody teaches how the browser actually works.&lt;/p&gt;

&lt;p&gt;I get it. I've been there. We've all been there.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Chauffeur Knowledge Bites Back
&lt;/h2&gt;

&lt;p&gt;Here's where it gets painful:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That 3 AM production incident.&lt;/strong&gt; Your beautifully copied solution breaks. You have no idea why. The Stack Overflow answer that saved you can't help you now. You're Googling frantically while users are locked out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The performance disaster.&lt;/strong&gt; You used that ORM everyone recommends. Suddenly your database is dying. Someone looks at the queries and finds you're doing 1,000 database calls per page load. You didn't know ORMs could do that because you never learned SQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The overengineered mess.&lt;/strong&gt; You built microservices because Netflix does it. Now you have eight services talking to each other, deployment takes three hours, and debugging requires checking logs across multiple systems. Your team of three spends more time on DevOps than features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The security hole.&lt;/strong&gt; You copied an authentication pattern without understanding how tokens work. Turns out your app has been leaking user sessions for six months.&lt;/p&gt;

&lt;p&gt;These aren't hypothetical. These happen every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Actually Get Better (Without Burning Out)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Start With "Why"
&lt;/h3&gt;

&lt;p&gt;Before you implement anything, pause and ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Why does this solution exist?"&lt;/li&gt;
&lt;li&gt;"What problem is it solving?"&lt;/li&gt;
&lt;li&gt;"What are the alternatives?"&lt;/li&gt;
&lt;li&gt;"What breaks if I get this wrong?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you can't answer these, you're probably in chauffeur mode.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learn the Boring Stuff
&lt;/h3&gt;

&lt;p&gt;I know, I know. Learning HTTP fundamentals isn't as sexy as learning the new JavaScript framework. But here's the secret: frameworks change, fundamentals don't.&lt;/p&gt;

&lt;p&gt;Learn how databases actually work. Learn how networks actually work. Learn how memory actually works.&lt;/p&gt;

&lt;p&gt;That knowledge compounds. Every new tool you learn becomes easier because you understand what it's built on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build Something Stupid Simple
&lt;/h3&gt;

&lt;p&gt;Want to really understand Express? Build a web server without it. Just raw Node.js HTTP handlers.&lt;/p&gt;

&lt;p&gt;Want to understand Redux? Build simple state management from scratch.&lt;/p&gt;

&lt;p&gt;Want to understand authentication? Implement basic JWT handling yourself.&lt;/p&gt;

&lt;p&gt;You'll appreciate what frameworks do for you, and you'll know how to fix them when they break.&lt;/p&gt;

&lt;h3&gt;
  
  
  Say "I Don't Know" More Often
&lt;/h3&gt;

&lt;p&gt;This is the hardest one.&lt;/p&gt;

&lt;p&gt;In your next meeting, when someone asks about something you don't understand, try saying: "I don't know. Can you explain?"&lt;/p&gt;

&lt;p&gt;I promise: half the room doesn't know either. They're just better at hiding it.&lt;/p&gt;

&lt;p&gt;Good teams reward curiosity over fake confidence. If your team punishes "I don't know," you're on the wrong team.&lt;/p&gt;

&lt;h3&gt;
  
  
  Teach Someone Else
&lt;/h3&gt;

&lt;p&gt;You think you understand dependency injection? Try explaining it to a junior developer.&lt;/p&gt;

&lt;p&gt;Can't do it without hand-waving? You don't understand it yet.&lt;/p&gt;

&lt;p&gt;Teaching forces you to organize your thoughts, find simple examples, and answer unexpected questions. It's the fastest way to find gaps in your knowledge.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Confession
&lt;/h2&gt;

&lt;p&gt;I wrote this article because I needed to read it.&lt;/p&gt;

&lt;p&gt;Last month I confidently recommended a caching strategy in a code review. Someone asked me to explain the eviction policy.&lt;/p&gt;

&lt;p&gt;I... couldn't.&lt;/p&gt;

&lt;p&gt;I'd read about it. I'd used it. I could spell "LRU cache." But I didn't actually understand how it worked.&lt;/p&gt;

&lt;p&gt;I'd been the chauffeur.&lt;/p&gt;

&lt;p&gt;So I shut up, went back, actually learned it, then came back to the conversation. It was humbling. It was also necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Point Isn't Perfection
&lt;/h2&gt;

&lt;p&gt;You don't need to understand everything from first principles. That's impossible.&lt;/p&gt;

&lt;p&gt;The point is recognizing when you're operating on chauffeur knowledge versus real understanding - and being honest about which one you have.&lt;/p&gt;

&lt;p&gt;Sometimes chauffeur knowledge is fine. If you're prototyping fast, copy that Stack Overflow solution. Ship it. Learn later.&lt;/p&gt;

&lt;p&gt;But when you're building something that matters - something people depend on, something that needs to scale, something you'll maintain for years - that's when you need to slow down and actually understand what you're doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Last Thing
&lt;/h2&gt;

&lt;p&gt;If you made it this far and thought, "Oh god, this is me" - good.&lt;/p&gt;

&lt;p&gt;That means you're self-aware enough to do something about it.&lt;/p&gt;

&lt;p&gt;The worst developers I've worked with weren't the ones with chauffeur knowledge. They were the ones who refused to admit it.&lt;/p&gt;

&lt;p&gt;The best developers I've worked with? They said "I don't know" constantly. Then they'd go learn, come back, and teach the rest of us.&lt;/p&gt;

&lt;p&gt;Be the second kind.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;P.S. - If you're reading this thinking "I should share this in Slack," but worried your team will think you're calling them out... you're overthinking it. Share it anyway. The developers who need it most won't realize it's about them. The ones who do realize are already working on it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>discuss</category>
      <category>learning</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Entity framework core</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Fri, 04 Jul 2025 11:04:04 +0000</pubDate>
      <link>https://dev.to/korirmoze/entity-framework-core-jcc</link>
      <guid>https://dev.to/korirmoze/entity-framework-core-jcc</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/korirmoze/entity-framework-race-conditions-the-silent-data-corruption-bug-a6l" class="crayons-story__hidden-navigation-link"&gt;Entity Framework Race Conditions: The Silent Data Corruption Bug - And How to Fix It&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/korirmoze" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F991376%2F237dd296-2a00-4817-8eb1-891e2be950f2.jpg" alt="korirmoze profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/korirmoze" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Korir Moses
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Korir Moses
                
              
              &lt;div id="story-author-preview-content-2655082" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/korirmoze" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F991376%2F237dd296-2a00-4817-8eb1-891e2be950f2.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Korir Moses&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/korirmoze/entity-framework-race-conditions-the-silent-data-corruption-bug-a6l" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 4 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/korirmoze/entity-framework-race-conditions-the-silent-data-corruption-bug-a6l" id="article-link-2655082"&gt;
          Entity Framework Race Conditions: The Silent Data Corruption Bug - And How to Fix It
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/csharp"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;csharp&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/sql"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;sql&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/korirmoze/entity-framework-race-conditions-the-silent-data-corruption-bug-a6l" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/korirmoze/entity-framework-race-conditions-the-silent-data-corruption-bug-a6l#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              1&lt;span class="hidden s:inline"&gt; comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>programming</category>
      <category>csharp</category>
      <category>sql</category>
    </item>
    <item>
      <title>Entity Framework Race Conditions: The Silent Data Corruption Bug - And How to Fix It</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Fri, 04 Jul 2025 11:03:30 +0000</pubDate>
      <link>https://dev.to/korirmoze/entity-framework-race-conditions-the-silent-data-corruption-bug-a6l</link>
      <guid>https://dev.to/korirmoze/entity-framework-race-conditions-the-silent-data-corruption-bug-a6l</guid>
      <description>&lt;p&gt;&lt;strong&gt;When Performance Optimizations Become Data Disasters&lt;/strong&gt;&lt;br&gt;
Race conditions in Entity Framework applications are among the most dangerous bugs you'll encounter in production systems. They're invisible during development, pass all unit tests, and only surface under real-world load conditions. When they do appear, they can cause data corruption, duplicate processing, and system-wide inconsistencies that are expensive to fix.&lt;br&gt;
This article explores the anatomy of EF race conditions, demonstrates how they manifest in production, and provides proven solutions to prevent them.&lt;br&gt;
&lt;strong&gt;The Anatomy of a Race Condition&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;The Perfect Storm: Three Ingredients for Disaster&lt;/strong&gt;&lt;br&gt;
Entity Framework race conditions typically require three conditions to manifest:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change Tracking Disabled: Using .AsNoTracking() on entities you plan to modify&lt;/li&gt;
&lt;li&gt;Concurrent Access: Multiple threads or processes accessing the same data&lt;/li&gt;
&lt;li&gt;State Modification: Attempting to update entity state without proper tracking
Let's examine a typical scenario with a background job processing system:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ❌ DANGEROUS: This code contains a race condition
public class OrderProcessingService
{
    private readonly IServiceScopeFactory _scopeFactory;

    public async Task ProcessPendingOrdersAsync()
    {
        var pendingOrders = await GetPendingOrdersAsync();

        while (pendingOrders.Any())
        {
            await ProcessOrderBatchAsync(pendingOrders);
            // Race condition: Next batch retrieved before previous updates are committed
            pendingOrders = await GetPendingOrdersAsync();
        }
    }

    private async Task&amp;lt;List&amp;lt;Order&amp;gt;&amp;gt; GetPendingOrdersAsync()
    {
        using var scope = _scopeFactory.CreateScope();
        var context = scope.ServiceProvider.GetRequiredService&amp;lt;AppDbContext&amp;gt;();

        var orders = await context.Orders
            .Where(o =&amp;gt; o.Status == OrderStatus.Pending)
            .Take(10)
            .AsNoTracking() // ❌ PROBLEM: Disables change tracking
            .ToListAsync();

        // ❌ PROBLEM: These changes are invisible to EF
        foreach (var order in orders)
        {
            order.Status = OrderStatus.Processing;
            order.LastModified = DateTime.UtcNow;
        }

        if (orders.Any())
        {
            // ❌ PROBLEM: SaveChanges does nothing - no tracked changes
            await context.SaveChangesAsync();
        }

        return orders;
    }

    private async Task ProcessOrderBatchAsync(List&amp;lt;Order&amp;gt; orders)
    {
        var tasks = orders.Select(ProcessSingleOrderAsync);
        await Task.WhenAll(tasks);
    }

    private async Task ProcessSingleOrderAsync(Order order)
    {
        using var scope = _scopeFactory.CreateScope();
        var context = scope.ServiceProvider.GetRequiredService&amp;lt;AppDbContext&amp;gt;();

        try
        {
            // Process the order (call external APIs, etc.)
            await ProcessOrderExternally(order);

            order.Status = OrderStatus.Completed;
            order.CompletedAt = DateTime.UtcNow;

            // Update in database
            context.Orders.Attach(order);
            context.Entry(order).State = EntityState.Modified;
            await context.SaveChangesAsync();
        }
        catch (Exception ex)
        {
            order.Status = OrderStatus.Failed;
            order.ErrorMessage = ex.Message;

            context.Orders.Attach(order);
            context.Entry(order).State = EntityState.Modified;
            await context.SaveChangesAsync();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;The Production Nightmare: What Actually Happens&lt;/strong&gt;&lt;br&gt;
In production, this code creates a devastating race condition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Timeline of Disaster:
T1: Worker A: GetPendingOrders() → Returns [Order 1001, 1002, 1003]
T2: Worker A: Sets status to Processing → NOT SAVED (AsNoTracking)
T3: Worker B: GetPendingOrders() → Returns [Order 1001, 1002, 1003] AGAIN!
T4: Worker A: ProcessOrderBatch() → Processes orders
T5: Worker B: ProcessOrderBatch() → Processes SAME orders again
T6: Duplicate processing, double charges, data corruption
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Debugging Challenge&lt;/strong&gt;&lt;br&gt;
The race condition is nearly impossible to reproduce in development because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Low Latency: Local databases respond instantly&lt;/li&gt;
&lt;li&gt;Single Process: Development typically runs one instance&lt;/li&gt;
&lt;li&gt;Low Concurrency: Limited concurrent operations&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Different Connection Pooling: Production pools behave differently&lt;br&gt;
&lt;strong&gt;Real-World Impact Assessment&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;E-commerce Systems&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Duplicate Orders: Customers charged multiple times&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inventory Issues: Stock levels become incorrect&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shipping Problems: Multiple shipments for single orders&lt;br&gt;
&lt;strong&gt;Financial Applications&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Double Transactions: Money transferred multiple times&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Account Imbalances: Incorrect balance calculations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reconciliation Failures: Mismatched records across systems&lt;br&gt;
&lt;strong&gt;Content Management Systems&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Duplicate Content: Articles published multiple times&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Workflow Corruption: Approval processes broken&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Audit Trail Issues: Incomplete change tracking&lt;br&gt;
&lt;strong&gt;The Fix: Proven Solutions&lt;br&gt;
Solution 1: Remove AsNoTracking (Immediate Fix)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ✅ FIXED: Enable change tracking for entities we plan to modify
private async Task&amp;lt;List&amp;lt;Order&amp;gt;&amp;gt; GetPendingOrdersAsync()
{
    using var scope = _scopeFactory.CreateScope();
    var context = scope.ServiceProvider.GetRequiredService&amp;lt;AppDbContext&amp;gt;();

    var orders = await context.Orders
        .Where(o =&amp;gt; o.Status == OrderStatus.Pending)
        .Take(10)
        // ✅ REMOVED: .AsNoTracking()
        .ToListAsync();

    // ✅ FIXED: Changes are now tracked
    foreach (var order in orders)
    {
        order.Status = OrderStatus.Processing;
        order.LastModified = DateTime.UtcNow;
    }

    if (orders.Any())
    {
        // ✅ FIXED: SaveChanges now works
        await context.SaveChangesAsync();
    }

    return orders;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Solution 2: Atomic Update Pattern (Robust)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ✅ BEST PRACTICE: Atomic select-and-update operation
private async Task&amp;lt;List&amp;lt;Order&amp;gt;&amp;gt; GetPendingOrdersAsync()
{
    using var scope = _scopeFactory.CreateScope();
    var context = scope.ServiceProvider.GetRequiredService&amp;lt;AppDbContext&amp;gt;();

    using var transaction = await context.Database.BeginTransactionAsync();

    try
    {
        // Step 1: Select IDs of orders to process
        var orderIds = await context.Orders
            .Where(o =&amp;gt; o.Status == OrderStatus.Pending)
            .OrderBy(o =&amp;gt; o.CreatedAt)
            .Take(10)
            .Select(o =&amp;gt; o.Id)
            .ToListAsync();

        if (!orderIds.Any())
            return new List&amp;lt;Order&amp;gt;();

        // Step 2: Atomically update status
        await context.Orders
            .Where(o =&amp;gt; orderIds.Contains(o.Id))
            .ExecuteUpdateAsync(o =&amp;gt; o
                .SetProperty(x =&amp;gt; x.Status, OrderStatus.Processing)
                .SetProperty(x =&amp;gt; x.LastModified, DateTime.UtcNow));

        // Step 3: Retrieve updated orders
        var orders = await context.Orders
            .Where(o =&amp;gt; orderIds.Contains(o.Id))
            .ToListAsync();

        await transaction.CommitAsync();
        return orders;
    }
    catch
    {
        await transaction.RollbackAsync();
        throw;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Solution 3: Database-Level Locking (Advanced)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ✅ ADVANCED: Use database row locking for absolute safety
private async Task&amp;lt;List&amp;lt;Order&amp;gt;&amp;gt; GetPendingOrdersAsync()
{
    using var scope = _scopeFactory.CreateScope();
    var context = scope.ServiceProvider.GetRequiredService&amp;lt;AppDbContext&amp;gt;();

    // Use raw SQL with row locking
    var sql = @"
        UPDATE TOP(@batchSize) Orders 
        SET Status = @processingStatus, LastModified = @now
        OUTPUT INSERTED.*
        WHERE Status = @pendingStatus
        ORDER BY CreatedAt";

    var parameters = new[]
    {
        new SqlParameter("@batchSize", 10),
        new SqlParameter("@processingStatus", (int)OrderStatus.Processing),
        new SqlParameter("@pendingStatus", (int)OrderStatus.Pending),
        new SqlParameter("@now", DateTime.UtcNow)
    };

    var orders = await context.Orders
        .FromSqlRaw(sql, parameters)
        .ToListAsync();

    return orders;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Solution 4: Distributed Locking (Microservices)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ✅ MICROSERVICES: Use distributed locking
public class OrderProcessingService
{
    private readonly IDistributedLock _distributedLock;

    public async Task ProcessPendingOrdersAsync()
    {
        var lockKey = "order-processing-lock";
        var lockExpiry = TimeSpan.FromMinutes(5);

        await using var @lock = await _distributedLock.AcquireAsync(lockKey, lockExpiry);

        if (@lock == null)
        {
            _logger.LogInformation("Another instance is processing orders");
            return;
        }

        var pendingOrders = await GetPendingOrdersAsync();

        while (pendingOrders.Any())
        {
            await ProcessOrderBatchAsync(pendingOrders);
            pendingOrders = await GetPendingOrdersAsync();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Performance Considerations&lt;br&gt;
When to Use AsNoTracking&lt;br&gt;
AsNoTracking is safe and beneficial for:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ✅ SAFE: Read-only operations
public async Task&amp;lt;List&amp;lt;OrderSummary&amp;gt;&amp;gt; GetOrderSummariesAsync()
{
    return await _context.Orders
        .Where(o =&amp;gt; o.Status == OrderStatus.Completed)
        .Select(o =&amp;gt; new OrderSummary
        {
            Id = o.Id,
            CustomerName = o.Customer.Name,
            Total = o.Total
        })
        .AsNoTracking() // ✅ Safe - we're not modifying entities
        .ToListAsync();
}

// ✅ SAFE: Reporting and analytics
public async Task&amp;lt;decimal&amp;gt; GetMonthlyRevenueAsync()
{
    return await _context.Orders
        .Where(o =&amp;gt; o.CreatedAt.Month == DateTime.Now.Month)
        .AsNoTracking() // ✅ Safe - aggregate operation
        .SumAsync(o =&amp;gt; o.Total);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Performance Optimization Strategies&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ✅ OPTIMIZED: Use projection for read-only data
public async Task&amp;lt;List&amp;lt;OrderListItem&amp;gt;&amp;gt; GetOrdersForDisplayAsync()
{
    return await _context.Orders
        .Select(o =&amp;gt; new OrderListItem
        {
            Id = o.Id,
            CustomerName = o.Customer.Name,
            Status = o.Status,
            Total = o.Total
        })
        .AsNoTracking() // ✅ Safe - projected data
        .ToListAsync();
}

// ✅ OPTIMIZED: Split reads and writes
public async Task ProcessOrdersAsync()
{
    // Read-only query for IDs
    var orderIds = await _context.Orders
        .Where(o =&amp;gt; o.Status == OrderStatus.Pending)
        .Select(o =&amp;gt; o.Id)
        .AsNoTracking() // ✅ Safe - just IDs
        .ToListAsync();

    // Separate tracked query for updates
    var orders = await _context.Orders
        .Where(o =&amp;gt; orderIds.Contains(o.Id))
        .ToListAsync(); // ✅ Tracked for updates

    foreach (var order in orders)
    {
        order.Status = OrderStatus.Processing;
    }

    await _context.SaveChangesAsync();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Testing Strategies&lt;br&gt;
Unit Tests for Race Conditions&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Test]
public async Task ProcessOrders_WithConcurrentWorkers_ShouldNotProcessSameOrderTwice()
{
    // Arrange
    var orders = CreateTestOrders(20);
    await SeedDatabase(orders);

    // Act: Start multiple workers concurrently
    var tasks = Enumerable.Range(0, 5)
        .Select(_ =&amp;gt; _orderService.ProcessPendingOrdersAsync())
        .ToArray();

    await Task.WhenAll(tasks);

    // Assert: No order should be processed twice
    var processedOrders = await GetProcessedOrders();
    var duplicates = processedOrders
        .GroupBy(o =&amp;gt; o.Id)
        .Where(g =&amp;gt; g.Count() &amp;gt; 1)
        .ToList();

    Assert.That(duplicates, Is.Empty, 
        $"Found duplicate processing for orders: {string.Join(",", duplicates.Select(g =&amp;gt; g.Key))}");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Integration Tests with Database&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Test]
public async Task ProcessOrders_UnderLoad_ShouldMaintainDataIntegrity()
{
    // Arrange
    var orderCount = 100;
    var workerCount = 10;
    var orders = CreateTestOrders(orderCount);
    await SeedDatabase(orders);

    // Act: Simulate production load
    var workers = Enumerable.Range(0, workerCount)
        .Select(async _ =&amp;gt;
        {
            for (int i = 0; i &amp;lt; 5; i++)
            {
                await _orderService.ProcessPendingOrdersAsync();
                await Task.Delay(100); // Simulate processing time
            }
        })
        .ToArray();

    await Task.WhenAll(workers);

    // Assert: Verify data integrity
    var allOrders = await _context.Orders.ToListAsync();

    // No order should be stuck in Processing status
    var stuckOrders = allOrders
        .Where(o =&amp;gt; o.Status == OrderStatus.Processing)
        .ToList();
    Assert.That(stuckOrders, Is.Empty);

    // All orders should be either Completed or Failed
    var finalStates = allOrders
        .Where(o =&amp;gt; o.Status == OrderStatus.Completed || o.Status == OrderStatus.Failed)
        .ToList();
    Assert.That(finalStates.Count, Is.EqualTo(orderCount));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Monitoring and Alerting&lt;br&gt;
Key Metrics to Track&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class OrderProcessingMetrics
{
    private readonly IMetricsLogger _metrics;

    public async Task TrackProcessingMetrics()
    {
        // Track stuck orders
        var stuckOrders = await _context.Orders
            .Where(o =&amp;gt; o.Status == OrderStatus.Processing &amp;amp;&amp;amp; 
                       o.LastModified &amp;lt; DateTime.UtcNow.AddMinutes(-10))
            .CountAsync();

        _metrics.Gauge("orders.stuck_in_processing", stuckOrders);

        // Track duplicate processing attempts
        var duplicateProcessingAttempts = await _context.OrderProcessingLogs
            .Where(l =&amp;gt; l.CreatedAt &amp;gt; DateTime.UtcNow.AddMinutes(-5))
            .GroupBy(l =&amp;gt; l.OrderId)
            .Where(g =&amp;gt; g.Count() &amp;gt; 1)
            .CountAsync();

        _metrics.Gauge("orders.duplicate_processing_attempts", duplicateProcessingAttempts);

        // Track processing rate
        var processingRate = await _context.Orders
            .Where(o =&amp;gt; o.Status == OrderStatus.Processing)
            .CountAsync();

        _metrics.Gauge("orders.current_processing_rate", processingRate);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Alert Conditions&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class OrderProcessingAlerts
{
    public async Task CheckForAnomalies()
    {
        // Alert: Too many orders stuck in processing
        var stuckCount = await GetStuckOrdersCount();
        if (stuckCount &amp;gt; 50)
        {
            await SendAlert("High number of stuck orders detected", 
                $"Found {stuckCount} orders stuck in processing status");
        }

        // Alert: Duplicate processing detected
        var duplicateCount = await GetDuplicateProcessingCount();
        if (duplicateCount &amp;gt; 0)
        {
            await SendAlert("Duplicate order processing detected", 
                $"Found {duplicateCount} orders processed multiple times");
        }

        // Alert: Processing rate anomaly
        var processingRate = await GetCurrentProcessingRate();
        var historicalAverage = await GetHistoricalProcessingRate();

        if (processingRate &amp;gt; historicalAverage * 2)
        {
            await SendAlert("Unusual processing rate detected", 
                $"Current rate: {processingRate}, Average: {historicalAverage}");
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Prevention Checklist&lt;br&gt;
Code Review Guidelines&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Change Tracking: Are we using AsNoTracking() on entities we plan to modify?&lt;/li&gt;
&lt;li&gt; Concurrency: Could multiple workers process the same data?&lt;/li&gt;
&lt;li&gt;Atomicity: Are related operations wrapped in transactions?&lt;/li&gt;
&lt;li&gt; State Management: Are entity states properly managed across scopes?&lt;/li&gt;
&lt;li&gt; Error Handling: Do we handle partial failures correctly?
&lt;strong&gt;Architecture Patterns&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; Single Responsibility: Each service has clear ownership of data&lt;/li&gt;
&lt;li&gt;Idempotency: Operations can be safely repeated&lt;/li&gt;
&lt;li&gt;Optimistic Concurrency: Use row versions for conflict detection&lt;/li&gt;
&lt;li&gt; Event Sourcing: Consider event-driven architectures for complex workflows&lt;/li&gt;
&lt;li&gt; CQRS: Separate read and write models where appropriate
&lt;strong&gt;Conclusion&lt;/strong&gt;
Entity Framework race conditions are silent killers in production applications. They manifest only under realistic load conditions and can cause significant data corruption before being detected. The key to prevention is understanding when and why to use performance optimizations like AsNoTracking().
&lt;strong&gt;Key Takeaways&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Never use AsNoTracking() on entities you plan to modify&lt;/li&gt;
&lt;li&gt;Use atomic operations for critical state changes&lt;/li&gt;
&lt;li&gt;Test with realistic concurrent scenarios&lt;/li&gt;
&lt;li&gt;Monitor for stuck entities and duplicate processing&lt;/li&gt;
&lt;li&gt;Implement proper error handling and rollback strategies
&lt;strong&gt;When in Doubt, Choose Safety&lt;/strong&gt;
In production systems, data integrity is more important than marginal performance gains. It's better to have slightly slower but correct operations than fast operations that corrupt your data.
Remember: The most expensive bugs are the ones that silently corrupt data over time. Invest in proper testing, monitoring, and defensive programming practices to prevent race conditions from reaching production.
The cost of fixing data corruption far exceeds the cost of preventing it in the first place.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>csharp</category>
      <category>sql</category>
    </item>
    <item>
      <title>Advanced Performance Optimization: Using Dotnet Channels</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Mon, 02 Jun 2025 07:06:40 +0000</pubDate>
      <link>https://dev.to/korirmoze/advanced-ussd-performance-optimization-implementing-fire-and-forget-background-processing-for-496o</link>
      <guid>https://dev.to/korirmoze/advanced-ussd-performance-optimization-implementing-fire-and-forget-background-processing-for-496o</guid>
      <description>&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
In the rapidly evolving landscape of mobile financial services and telecommunications applications, USSD (Unstructured Supplementary Service Data) remains a critical channel for delivering services to users across diverse network conditions. However, the inherent constraints of USSD—including session timeouts, synchronous communication patterns, and limited bandwidth—present unique challenges for developers seeking to deliver responsive, data-rich applications.&lt;br&gt;
This article explores the implementation of fire-and-forget background processing patterns in USSD applications, demonstrating how asynchronous data fetching can dramatically improve user experience while maintaining system reliability and performance. We'll examine real-world implementation strategies, performance considerations, and best practices for enterprise-grade USSD applications.&lt;br&gt;
&lt;strong&gt;The USSD Performance Challenge&lt;br&gt;
Understanding USSD Constraints&lt;/strong&gt;&lt;br&gt;
USSD applications operate within a constrained environment that demands careful architectural consideration:&lt;br&gt;
&lt;strong&gt;Session Timeout Limitations&lt;/strong&gt;, USSD sessions typically expire within 30-180 seconds, depending on the mobile network operator&lt;br&gt;
&lt;strong&gt;Synchronous Communication Model&lt;/strong&gt;, Each user interaction requires an immediate response&lt;br&gt;
&lt;strong&gt;Network Latency Variability&lt;/strong&gt;, Response times can vary significantly based on network conditions&lt;br&gt;
&lt;strong&gt;Memory Constraints&lt;/strong&gt;, Limited session state management capabilities&lt;br&gt;
&lt;strong&gt;Sequential Processing&lt;/strong&gt;, Users must wait for each operation to complete before proceeding&lt;br&gt;
&lt;strong&gt;Traditional Synchronous Approach Limitations&lt;/strong&gt;&lt;br&gt;
In conventional USSD implementations, data fetching operations block the user interface flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Traditional blocking approach
public async Task&amp;lt;UssdResponse&amp;gt; HandleLoginAsync(string msisdn, string pin)
{
    // Authenticate user
    var user = await _authService.ValidateUserAsync(msisdn, pin);

    // Blocking operations that delay response
    var banks = await _bankService.GetSupportedBanksAsync();
    var accounts = await _accountService.GetUserAccountsAsync(msisdn);
    var transactions = await _transactionService.GetRecentTransactionsAsync(msisdn);

    // User waits for all operations to complete
    return UssdResponse.Continue("Welcome! Select an option...");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach introduces several critical issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Increased Response Times: Users experience delays while waiting for multiple API calls&lt;/li&gt;
&lt;li&gt;Higher Timeout Risk: Extended processing time increases session timeout probability
3.Poor User Experience: Perceived application sluggishness reduces user satisfaction
4.Resource Inefficiency: Blocking threads waste computational resources
&lt;strong&gt;Fire-and-Forget: A Modern Solution
Architectural Overview&lt;/strong&gt;
Fire-and-forget background processing addresses these limitations by decoupling data fetching from user interface flow. The pattern involves:
1.Immediate Response: Return control to the user immediately after essential operations
2.Background Processing: Execute data fetching operations asynchronously
3.Intelligent Caching: Store fetched data for future use
4.Graceful Fallback: Handle scenarios where background data isn't yet available
&lt;strong&gt;Implementation Architecture&lt;/strong&gt;
The core fire-and-forget helper provides controlled background execution
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void Run(Func&amp;lt;IServiceProvider, Task&amp;gt; operation)
{
    Task.Run(async () =&amp;gt; 
    {
        await _concurrencyLimiter.WaitAsync(); // Prevent resource exhaustion
        try
        {
            using var scope = _scopeFactory.CreateScope();
            await operation(scope.ServiceProvider);
        }
        catch (Exception ex) { /* Log errors, never crash */ }
        finally { _concurrencyLimiter.Release(); }
    });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enhanced Login Implementation
&lt;/h3&gt;

&lt;p&gt;The login handler separates critical authentication from data fetching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public async Task&amp;lt;UssdResponse&amp;gt; HandleLoginAsync(string msisdn, string pin)
{
    // Only essential synchronous operations
    var user = await _authService.ValidateUserAsync(msisdn, pin);
    if (user == null) return UssdResponse.End("Invalid credentials");

    // Start background loading immediately
    InitiateBackgroundDataLoading(msisdn);

    // Return control to user without waiting
    return UssdResponse.Continue($"Welcome {user.Name}!\n1. Account Services\n2. Transfer Money");
}
The background loading handles multiple services with timeout protection
_fireAndForgetHelper.Run(async sp =&amp;gt;
{
    using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(45));

    await Task.WhenAll(
        LoadAndCacheBanks(bankService, cache, cts.Token),
        LoadAndCacheUserAccounts(accountService, msisdn, cache, cts.Token)
    );

    // Signal completion for later states
    await cache.SetStringAsync($"data_ready_{msisdn}", "true", expiration);
});
## Advanced Caching Strategies

### Hierarchical Caching Implementation

A multi-layer cache approach optimizes data access patterns:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
csharp&lt;br&gt;
// Check memory cache first (fastest)&lt;br&gt;
if (_memoryCache.TryGetValue(key, out T cachedValue))&lt;br&gt;
    return cachedValue;&lt;/p&gt;

&lt;p&gt;// Check distributed cache (Redis/SQL)&lt;br&gt;
var distributedValue = await _distributedCache.GetStringAsync(key);&lt;br&gt;
if (distributedValue != null)&lt;br&gt;
{&lt;br&gt;
    var data = JsonSerializer.Deserialize(distributedValue);&lt;br&gt;
    _memoryCache.Set(key, data, TimeSpan.FromMinutes(5)); // Populate memory cache&lt;br&gt;
    return data;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Fetch from source and populate both caches&lt;br&gt;
var freshValue = await factory();&lt;br&gt;
await StoreInBothCaches(key, freshValue);&lt;br&gt;
&lt;strong&gt;Best Practices and Recommendations&lt;/strong&gt;&lt;br&gt;
** 1.Resource Management**&lt;br&gt;
Connection Pooling: Implement proper database and HTTP connection pooling to prevent resource exhaustion&lt;br&gt;
Thread Pool Management: Monitor thread pool usage and implement semaphores to limit concurrent background operations&lt;br&gt;
Memory Management: Implement cache size limits and automatic cleanup for user-specific data&lt;br&gt;
&lt;strong&gt;2. Monitoring and Observability&lt;/strong&gt;&lt;br&gt;
Performance Metrics: Track response times, cache hit rates, and background task completion rates&lt;br&gt;
Error Tracking: Implement comprehensive error logging with correlation IDs for debugging&lt;br&gt;
Health Checks: Monitor the health of background services and dependent systems&lt;br&gt;
&lt;strong&gt;3.Configuration Management&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class UssdConfiguration
{
    public TimeSpan BackgroundTaskTimeout { get; set; } = TimeSpan.FromSeconds(45);
    public int MaxConcurrentBackgroundTasks { get; set; } = 10;
    public TimeSpan CacheExpirationTime { get; set; } = TimeSpan.FromMinutes(15);
    public int CircuitBreakerFailureThreshold { get; set; } = 5;
    public TimeSpan CircuitBreakerTimeout { get; set; } = TimeSpan.FromMinutes(2);
    public bool EnableAggressiveCaching { get; set; } = true;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4.Testing Strategies&lt;/strong&gt;&lt;br&gt;
Load Testing: Simulate high concurrent user loads to validate background processing performance&lt;br&gt;
Chaos Engineering: Test system resilience by introducing controlled failures&lt;br&gt;
Cache Testing: Verify cache invalidation and refresh mechanisms work correctly&lt;br&gt;
&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Fire-and-forget background processing represents a paradigm shift in USSD application architecture, enabling developers to deliver responsive user experiences while maintaining robust data access capabilities. The pattern's success lies in its ability to decouple user interface flow from data fetching operations, leveraging asynchronous processing and intelligent caching to create seamless user experiences.&lt;br&gt;
As mobile financial services continue to evolve and user expectations increase, implementing sophisticated background processing patterns becomes not just an optimization but a necessity for competitive advantage. Organizations that embrace these architectural patterns will be better positioned to deliver the fast, reliable services that modern users demand&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>csharp</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Clean Architecture in .NET: Moving Beyond Generic Repositories and Leveraging IServiceScopeFactory</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Wed, 28 May 2025 06:09:25 +0000</pubDate>
      <link>https://dev.to/korirmoze/clean-architecture-in-net-moving-beyond-generic-repositories-and-leveraging-iservicescopefactory-11gb</link>
      <guid>https://dev.to/korirmoze/clean-architecture-in-net-moving-beyond-generic-repositories-and-leveraging-iservicescopefactory-11gb</guid>
      <description>&lt;p&gt;&lt;strong&gt;Abstrac&lt;/strong&gt;t&lt;br&gt;
In modern software development, architectural patterns such as Domain-Driven Design (DDD), Clean Architecture, and Command Query Responsibility Segregation (CQRS) have gained widespread adoption. However, their implementation often leads to over-engineering through unnecessary abstractions like generic IRepository interfaces. This article examines when these patterns add value versus when they introduce complexity, proposes intent-driven alternatives to generic repositories, and demonstrates the proper application of IServiceScopeFactory for managing service lifetimes in .NET applications.&lt;br&gt;
&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
The pursuit of "good architecture" has led many development teams to adopt heavyweight patterns and abstractions without sufficient consideration of their actual requirements. While patterns like Clean Architecture provide valuable guidance, their mechanical application often results in code that is more complex than necessary. This analysis focuses on identifying when architectural patterns serve genuine needs versus when they constitute over-engineering.&lt;br&gt;
&lt;strong&gt;Clean Architecture:&lt;/strong&gt; Principles and Pragmatism&lt;br&gt;
Clean Architecture, as articulated by Robert C. Martin, establishes a layered approach to software design with clear separation of concerns:&lt;br&gt;
&lt;strong&gt;Core Layers:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Entities:&lt;/strong&gt; Domain models containing business rules, isolated from infrastructure concerns&lt;br&gt;
Use Cases: Application services orchestrating business workflows&lt;br&gt;
Interface Adapters: Translation layer between domain and external systems&lt;br&gt;
Infrastructure: Databases, web frameworks, and external services&lt;/p&gt;

&lt;p&gt;The fundamental principle—the Dependency Rule—ensures that business logic remains independent of infrastructure decisions, enhancing testability and maintainability.&lt;br&gt;
The Context-Dependent Nature of Architectural Patterns&lt;br&gt;
When DDD and CQRS Add Value:&lt;/p&gt;

&lt;p&gt;Complex business domains requiring sophisticated modeling&lt;br&gt;
Systems with distinct read/write optimization needs&lt;br&gt;
Applications where domain expertise is critical to success&lt;br&gt;
Large teams requiring shared understanding through ubiquitous language&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When They Become Overhead:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CRUD-centric applications with straightforward business rules&lt;br&gt;
Small teams lacking domain modeling expertise&lt;br&gt;
Tight delivery timelines where complexity impedes progress&lt;br&gt;
Domains that don't justify the learning curve and maintenance overhead&lt;/p&gt;

&lt;p&gt;The key insight is that architectural patterns should solve actual problems, not theoretical ones.&lt;br&gt;
&lt;strong&gt;The Generic Repository Anti-Pattern&lt;/strong&gt;&lt;br&gt;
The IRepository interface represents a common abstraction that appears beneficial but often creates more problems than it solves:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface IRepository&amp;lt;T&amp;gt;
{
    T GetById(Guid id);
    void Add(T entity);
    void Delete(T entity);
    IEnumerable&amp;lt;T&amp;gt; GetAll();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Critical Limitations&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1. Semantic Mismatch with Domain Operations&lt;/strong&gt;&lt;br&gt;
Business operations rarely align with generic CRUD operations. Consider an e-commerce scenario:&lt;/p&gt;

&lt;p&gt;Retrieving orders may require specific filtering by status, customer, or date range&lt;br&gt;
Order updates might be restricted based on fulfillment status&lt;br&gt;
Deletion might be prohibited for auditing reasons&lt;/p&gt;

&lt;p&gt;Generic repositories cannot express these domain-specific constraints effectively.&lt;br&gt;
&lt;strong&gt;2. Abstraction Leakage&lt;/strong&gt;&lt;br&gt;
Many implementations expose IQueryable, creating tight coupling between domain logic and ORM-specific constructs. This coupling:&lt;/p&gt;

&lt;p&gt;Makes unit testing more complex&lt;br&gt;
Prevents clean separation between layers&lt;br&gt;
Reduces flexibility in data access strategy changes&lt;br&gt;
**&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Promotion of Anemic Domain Models**
By externalizing all data access logic, generic repositories encourage treating domain entities as mere data containers, violating object-oriented principles and reducing code expressiveness.
&lt;strong&gt;Intent-Driven Repository Design&lt;/strong&gt;
A superior approach involves creating repositories that reflect actual business operations:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface IOrderRepository
{
    Task&amp;lt;Order?&amp;gt; GetPendingOrderForCustomerAsync(Guid customerId);
    Task&amp;lt;IEnumerable&amp;lt;Order&amp;gt;&amp;gt; GetOrdersByStatusAsync(OrderStatus status);
    Task AddAsync(Order order);
    Task&amp;lt;bool&amp;gt; CanCancelOrderAsync(Guid orderId);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Benefits of Intent-Driven Design&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Enhanced Clarity:&lt;/strong&gt; Method names communicate business intent clearly&lt;br&gt;
&lt;strong&gt;Better Encapsulation:&lt;/strong&gt; Implementation details remain hidden&lt;br&gt;
&lt;strong&gt;Improved Testability:&lt;/strong&gt; Mock objects can simulate specific business scenarios&lt;br&gt;
&lt;strong&gt;Domain Alignment:&lt;/strong&gt; Interfaces reflect real-world operations&lt;br&gt;
&lt;strong&gt;Refactoring Example&lt;br&gt;
Before (Generic Approach):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class OrderService
{
    private readonly IRepository&amp;lt;Order&amp;gt; _orderRepository;

    public async Task&amp;lt;IEnumerable&amp;lt;Order&amp;gt;&amp;gt; GetCustomerOrders(Guid customerId)
    {
        var allOrders = await _orderRepository.GetAll();
        return allOrders.Where(o =&amp;gt; o.CustomerId == customerId);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After (Intent-Driven Approach):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class OrderService
{
    private readonly IOrderRepository _orderRepository;

    public Task&amp;lt;IEnumerable&amp;lt;Order&amp;gt;&amp;gt; GetCustomerOrders(Guid customerId)
    {
        return _orderRepository.GetOrdersByCustomerIdAsync(customerId);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The refactored version moves filtering logic into the repository where it belongs, making the service more focused and the abstraction more meaningful.&lt;br&gt;
&lt;strong&gt;Understanding IServiceScopeFactory in .NET&lt;/strong&gt;&lt;br&gt;
While generic repositories often represent unnecessary abstraction, IServiceScopeFactory serves a legitimate architectural purpose in .NET's dependency injection system.&lt;br&gt;
&lt;strong&gt;The Service Lifetime Challenge&lt;/strong&gt;&lt;br&gt;
.NET Core supports three service lifetimes:&lt;/p&gt;

&lt;p&gt;Singleton: Created once per application&lt;br&gt;
Scoped: Created once per HTTP request&lt;br&gt;
Transient: Created each time requested&lt;/p&gt;

&lt;p&gt;Problems arise when singleton services need to consume scoped services (like DbContext) outside of HTTP request contexts, such as in background services or hosted workers.&lt;br&gt;
&lt;strong&gt;IServiceScopeFactory Solution&lt;/strong&gt;&lt;br&gt;
IServiceScopeFactory enables manual creation of service scopes, allowing safe resolution of scoped services in non-request contexts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class OrderProcessingBackgroundService : BackgroundService
{
    private readonly IServiceScopeFactory _scopeFactory;
    private readonly ILogger&amp;lt;OrderProcessingBackgroundService&amp;gt; _logger;

    public OrderProcessingBackgroundService(
        IServiceScopeFactory scopeFactory,
        ILogger&amp;lt;OrderProcessingBackgroundService&amp;gt; logger)
    {
        _scopeFactory = scopeFactory;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            using var scope = _scopeFactory.CreateScope();
            var orderService = scope.ServiceProvider.GetRequiredService&amp;lt;IOrderService&amp;gt;();
            var dbContext = scope.ServiceProvider.GetRequiredService&amp;lt;OrderDbContext&amp;gt;();

            try
            {
                await ProcessPendingOrders(orderService, dbContext);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error processing orders");
            }

            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
        }
    }

    private async Task ProcessPendingOrders(IOrderService orderService, OrderDbContext dbContext)
    {
        // Business logic implementation
        var pendingOrders = await orderService.GetPendingOrdersAsync();
        foreach (var order in pendingOrders)
        {
            await orderService.ProcessOrderAsync(order.Id);
        }

        await dbContext.SaveChangesAsync();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach maintains proper service lifetimes while enabling background processing capabilities.&lt;br&gt;
&lt;strong&gt;Implementation Recommendations&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;1. Start Simple&lt;/strong&gt;&lt;br&gt;
Begin with straightforward service classes and add abstractions only when genuine needs emerge. Premature abstraction often creates more problems than it solves.&lt;br&gt;
&lt;strong&gt;2. Focus on Intent&lt;/strong&gt;&lt;br&gt;
When creating interfaces, ensure they reflect actual business operations rather than technical CRUD operations.&lt;br&gt;
&lt;strong&gt;3. Respect Service Lifetimes&lt;/strong&gt;&lt;br&gt;
Use IServiceScopeFactory appropriately when consuming scoped services outside HTTP request contexts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Iterative Refinement
Allow architecture to evolve with understanding. What starts as a simple service can be refactored into more sophisticated patterns as complexity justifies the investment.
&lt;strong&gt;5. Team Capability Alignment&lt;/strong&gt;
Ensure architectural choices align with team expertise and project timelines. Complex patterns require corresponding knowledge and maintenance commitment.
&lt;strong&gt;Conclusion&lt;/strong&gt;
Effective software architecture balances structure with pragmatism. While Clean Architecture principles provide valuable guidance, their implementation should be tailored to actual requirements rather than theoretical ideals. Generic repositories often represent over-abstraction, while intent-driven interfaces better serve domain needs. Meanwhile, IServiceScopeFactory addresses legitimate technical requirements in .NET applications.
&lt;strong&gt;The goal remains constant:&lt;/strong&gt; creating maintainable, testable, and comprehensible code. This is achieved through thoughtful application of patterns rather than their mechanical adoption. By understanding when patterns add value versus when they introduce unnecessary complexity, development teams can make informed architectural decisions that serve both immediate needs and long-term maintainability.
&lt;strong&gt;References and Further Reading&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Martin, Robert C. "Clean Architecture: A Craftsman's Guide to Software Structure and Design"&lt;br&gt;
Evans, Eric. "Domain-Driven Design: Tackling Complexity in the Heart of Software"&lt;br&gt;
Microsoft Documentation: "Dependency injection in .NET"&lt;br&gt;
Fowler, Martin. "Patterns of Enterprise Application Architecture"&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Parameter Perfection: Mastering Positional and Named Arguments in Modern .NET</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Sun, 06 Apr 2025 07:18:23 +0000</pubDate>
      <link>https://dev.to/korirmoze/parameter-perfection-mastering-positional-and-named-arguments-in-modern-net-4jbe</link>
      <guid>https://dev.to/korirmoze/parameter-perfection-mastering-positional-and-named-arguments-in-modern-net-4jbe</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
In the .NET ecosystem, method and constructor parameters serve as the cornerstone for passing data between components. The framework supports two primary parameter passing mechanisms: positional parameters and named parameters. Understanding these concepts in depth is essential for developers to write elegant, maintainable, and error-resistant code. This article explores both approaches in detail, including their syntax, benefits, limitations, and best practices, with a special focus on how they integrate with modern .NET development patterns like Dependency Injection.&lt;br&gt;
&lt;strong&gt;Positional Parameters in Depth&lt;/strong&gt;&lt;br&gt;
Positional parameters represent the traditional approach to parameter passing in most programming languages, including C#. Arguments must be provided in the exact sequence defined in the method or constructor signature.&lt;br&gt;
&lt;strong&gt;Basic Syntax and Usage&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class UserProfile
{
    public void UpdateProfile(string username, string email, int age, bool isActive)
    {
        // Implementation
    }
}

// Usage with positional parameters
var profile = new UserProfile();
profile.UpdateProfile("johndoe", "john@example.com", 32, true);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advanced Scenarios with Positional Parameters&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Method Overloading&lt;/strong&gt;&lt;br&gt;
Positional parameters work seamlessly with method overloading, allowing multiple method implementations with different parameter types or counts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class MessageFormatter
{
    public string Format(string message)
    {
        return $"INFO: {message}";
    }

    public string Format(string message, bool isError)
    {
        return isError ? $"ERROR: {message}" : $"INFO: {message}";
    }

    public string Format(string message, string category, int priority)
    {
        return $"{category}({priority}): {message}";
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parameter Arrays (params)&lt;/strong&gt;&lt;br&gt;
The params keyword allows methods to accept a variable number of arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Calculator
{
    public int Sum(params int[] numbers)
    {
        int result = 0;
        foreach (var num in numbers)
        {
            result += num;
        }
        return result;
    }
}

// Usage
var calc = new Calculator();
int result1 = calc.Sum(1, 2, 3);        // Passes 3 arguments
int result2 = calc.Sum(10, 20, 30, 40); // Passes 4 arguments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations of Positional Parameters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cognitive Load: When dealing with methods that have numerous parameters, remembering the correct order becomes challenging.&lt;br&gt;
Error Proneness: Passing arguments in the wrong order can lead to runtime errors, especially when multiple parameters share the same type.&lt;br&gt;
Code Readability: Without looking at the method definition, it might be difficult to understand what each argument represents.&lt;br&gt;
Maintenance Challenges: Adding, removing, or reordering parameters in a method signature can break existing code that relies on positional arguments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Named Parameters in Depth&lt;/strong&gt;&lt;br&gt;
Named parameters allow developers to specify arguments by parameter name rather than position, offering greater flexibility and clarity.&lt;br&gt;
Basic Syntax and Usage&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class NotificationService
{
    public void SendNotification(string recipient, string subject, string body, bool isUrgent = false, string[] attachments = null)
    {
        // Implementation
    }
}

// Usage with named parameters
var notifier = new NotificationService();
notifier.SendNotification(
    recipient: "user@example.com",
    subject: "Meeting Reminder",
    body: "Don't forget our meeting tomorrow",
    isUrgent: true
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advanced Scenarios with Named Parameters&lt;/strong&gt;&lt;br&gt;
Optional Parameters with Default Values&lt;br&gt;
Named parameters work exceptionally well with optional parameters that have default values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ReportGenerator
{
    public string GenerateReport(
        string title,
        DateTime startDate,
        DateTime endDate,
        bool includeCharts = true,
        string format = "PDF",
        int compressionLevel = 0,
        bool encrypt = false
    )
    {
        // Implementation
        return $"Report generated: {title} ({format})";
    }
}

// Usage examples
var generator = new ReportGenerator();

// Only providing required parameters, using defaults for the rest
string report1 = generator.GenerateReport(
    title: "Sales Report",
    startDate: new DateTime(2023, 1, 1),
    endDate: new DateTime(2023, 3, 31)
);

// Providing required parameters and selectively overriding some defaults
string report2 = generator.GenerateReport(
    title: "Financial Analysis",
    startDate: new DateTime(2023, 1, 1),
    endDate: new DateTime(2023, 12, 31),
    format: "Excel",
    encrypt: true
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using Named Arguments with Delegates and Lambda Expressions&lt;br&gt;
Named parameters can enhance clarity when working with delegates and lambda expressions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class UserManager
{
    public List&amp;lt;User&amp;gt; FilterUsers(List&amp;lt;User&amp;gt; users, Func&amp;lt;User, bool&amp;gt; predicate)
    {
        return users.Where(predicate).ToList();
    }
}

var manager = new UserManager();
var filteredUsers = manager.FilterUsers(
    users: allUsers,
    predicate: user =&amp;gt; user.Age &amp;gt; 18 &amp;amp;&amp;amp; user.IsActive
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Leading Named Arguments&lt;/strong&gt;&lt;br&gt;
Named arguments can be followed by positional arguments, as long as all positional arguments are in the correct position:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void ConfigureService(string name, int timeout, bool isEnabled)
{
    // Implementation
}

// Valid in C# 7.2 and later
ConfigureService(name: "AuthService", 30, isEnabled: true);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Combining Positional and Named Parameters&lt;/strong&gt;&lt;br&gt;
In practice, a hybrid approach often offers the best balance between conciseness and clarity.&lt;br&gt;
Best Practices for Combining Both Approaches&lt;/p&gt;

&lt;p&gt;Use positional parameters for mandatory, logically ordered arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void ScheduleAppointment(DateTime dateTime, string patientName, bool isEmergency = false)
{
    // Implementation
}

// Usage
ScheduleAppointment(DateTime.Now.AddDays(1), "John Smith", isEmergency: true);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use named parameters for boolean flags and optional parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void ProcessOrder(string orderId, double amount, string currency = "USD", bool expediteShipping = false)
{
    // Implementation
}

// Usage
ProcessOrder("ORD-12345", 299.99, expediteShipping: true);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parameter Passing in Dependency Injection&lt;br&gt;
Dependency Injection (DI) is a design pattern that has become the standard approach for managing dependencies in .NET applications, especially with ASP.NET Core.&lt;br&gt;
Constructor Injection&lt;br&gt;
Constructor injection is the most common form of DI in .NET. When a class is resolved from the DI container, its constructor parameters are automatically provided:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class OrderService
{
    private readonly IRepository&amp;lt;Order&amp;gt; _orderRepository;
    private readonly IPaymentProcessor _paymentProcessor;
    private readonly ILogger&amp;lt;OrderService&amp;gt; _logger;

    public OrderService(
        IRepository&amp;lt;Order&amp;gt; orderRepository,
        IPaymentProcessor paymentProcessor,
        ILogger&amp;lt;OrderService&amp;gt; logger)
    {
        _orderRepository = orderRepository;
        _paymentProcessor = paymentProcessor;
        _logger = logger;
    }

    // Service methods
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Registration Examples with the Built-in DI Container&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Register dependencies
        services.AddScoped&amp;lt;IRepository&amp;lt;Order&amp;gt;, OrderRepository&amp;gt;();
        services.AddSingleton&amp;lt;IPaymentProcessor, StripePaymentProcessor&amp;gt;();
        services.AddTransient&amp;lt;OrderService&amp;gt;();

        // Register with factory method and named parameters
        services.AddSingleton&amp;lt;IConfigurationService&amp;gt;(sp =&amp;gt; new ConfigurationService(
            environment: "Production",
            useCache: true,
            logger: sp.GetRequiredService&amp;lt;ILogger&amp;lt;ConfigurationService&amp;gt;&amp;gt;()
        ));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Advantages in Testing Scenarios&lt;br&gt;
Named parameters significantly improve the readability of test setup code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Fact]
public void ProcessOrder_ValidOrder_ReturnsOrderConfirmation()
{
    // Arrange
    var mockRepository = new Mock&amp;lt;IRepository&amp;lt;Order&amp;gt;&amp;gt;();
    var mockProcessor = new Mock&amp;lt;IPaymentProcessor&amp;gt;();
    var mockLogger = new Mock&amp;lt;ILogger&amp;lt;OrderService&amp;gt;&amp;gt;();

    var orderService = new OrderService(
        orderRepository: mockRepository.Object,
        paymentProcessor: mockProcessor.Object,
        logger: mockLogger.Object
    );

    var testOrder = new Order { /* Test data */ };

    // Act
    var result = orderService.ProcessOrder(testOrder);

    // Assert
    Assert.NotNull(result);
    Assert.Equal("Confirmed", result.Status);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advanced Parameter Patterns in Modern .NET&lt;/strong&gt;&lt;br&gt;
Record Types and Positional Parameters (C# 9.0+)&lt;br&gt;
C# 9.0 introduced record types with positional parameters for immutable data models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Record with positional parameters
public record Person(string FirstName, string LastName, int Age);

// Usage
var person = new Person("John", "Doe", 30);

// Deconstruction
var (firstName, lastName, age) = person;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Options Pattern for Complex Configurations&lt;br&gt;
The Options Pattern is commonly used in ASP.NET Core for handling complex configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class SmtpOptions
{
    public string Server { get; set; }
    public int Port { get; set; }
    public bool UseSsl { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
}

public class EmailService
{
    private readonly SmtpOptions _options;

    public EmailService(IOptions&amp;lt;SmtpOptions&amp;gt; options)
    {
        _options = options.Value;
    }

    // Service methods
}

// Registration
services.Configure&amp;lt;SmtpOptions&amp;gt;(configuration.GetSection("Smtp"));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Extension Methods and Fluent APIs&lt;/strong&gt;&lt;br&gt;
Extension methods often use named parameters to enhance readability in fluent APIs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddCustomAuthentication(
        this IServiceCollection services,
        string authority = null,
        bool requireHttpsMetadata = true,
        string apiName = null,
        string apiSecret = null)
    {
        // Implementation
        return services;
    }
}

// Usage
services.AddCustomAuthentication(
    authority: "https://auth.example.com",
    apiName: "api1",
    requireHttpsMetadata: false
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Positional and named parameters each offer distinct advantages in .NET development. Positional parameters provide conciseness and efficiency for simple method signatures, while named parameters enhance code readability, maintainability, and self-documentation for complex APIs.&lt;br&gt;
Modern .NET development often employs a hybridized approach, using positional parameters for straightforward, commonly-used methods and named parameters for complex configurations, optional parameters, and in scenarios where code clarity is paramount. This balanced approach results in code that is both efficient and maintainable.&lt;br&gt;
As .NET continues to evolve, understanding the nuances of parameter passing becomes increasingly important, especially in the context of cross-platform development, microservices architectures, and cloud-native applications where clear, maintainable code is essential for long-term project success.&lt;br&gt;
By following the guidelines and best practices outlined in this article, developers can make informed decisions about parameter usage, leading to more robust, readable, and maintainable .NET applications.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Building a Scalable USSD Banking Solution for a Bank</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Sun, 23 Mar 2025 09:05:51 +0000</pubDate>
      <link>https://dev.to/korirmoze/building-a-scalable-ussd-banking-solution-for-a-bank-19e7</link>
      <guid>https://dev.to/korirmoze/building-a-scalable-ussd-banking-solution-for-a-bank-19e7</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
In the bustling financial landscape of  Africa, banks are faced with a significant challenge, how to provide reliable, secure banking services across multiple countries where smartphone penetration remains low and internet connectivity unstable. This case study explores how a USSD-based banking solution can transform  operations across multiple countries, bringing banking services to thousands without requiring internet access or smartphones.&lt;br&gt;
&lt;strong&gt;The African Banking Landscape&lt;/strong&gt;&lt;br&gt;
Across many African regions, traditional mobile banking applications face substantial barriers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Low smartphone adoption rates in rural areas&lt;/li&gt;
&lt;li&gt;Inconsistent and expensive internet connectivity&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost prohibitions of mobile data for many customers&lt;br&gt;
Despite these challenges, the demand for accessible banking services continues to grow. USSD (Unstructured Supplementary Service Data) technology offers a compelling alternative, allowing customers to access banking services through any mobile phone by dialing simple code sequences like *123#.&lt;br&gt;
For Banks to achieve more effective solution,&lt;br&gt;
Most Bank with operations spread across  Africa, need to consolidate disparate systems from its subsidiaries into a unified platform. Their requirements are clear but demanding:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a single, maintainable codebase that could serve multiple countries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ensure robust security for financial transactions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deliver near-instant response times within USSD's tight session constraints&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Support core banking functions: balance checks, transfers, bill payments, and airtime purchases&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Seamlessly integrate with their existing core banking infrastructure&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The stakes are always high  a system serving thousands of customers needs to be reliable, secure, and fast, all while operating under the technical constraints of USSD technology.&lt;br&gt;
&lt;strong&gt;Technical Solution&lt;/strong&gt;: Architecture for Scale&lt;br&gt;
The solution leverages modern architecture patterns while respecting the limitations of USSD technology:&lt;br&gt;
Technology Foundation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend:&lt;/strong&gt; .NET 8.0 (C#) provided a robust, performance-focused foundation&lt;br&gt;
&lt;strong&gt;Database:&lt;/strong&gt; PostgreSQL offered reliability with flexible data structures&lt;br&gt;
&lt;strong&gt;Deployment:&lt;/strong&gt; Docker containers orchestrated by Kubernetes enabled scalability&lt;br&gt;
&lt;strong&gt;Security:&lt;/strong&gt; JWT authentication and end-to-end encryption protected sensitive data&lt;br&gt;
&lt;strong&gt;Caching:&lt;/strong&gt; Redis managed user sessions, critical for preserving state in USSD's restrictive environment&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Microservices Approach&lt;/strong&gt;&lt;br&gt;
Rather than building a monolithic application, the system can be decomposed into specialized services:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;USSD Gateway Service:&lt;/strong&gt; The first point of contact for all user requests, handling the complexities of the USSD protocol and maintaining session state.&lt;br&gt;
&lt;strong&gt;Authentication Service:&lt;/strong&gt; A dedicated security layer implementing JWT tokens, encryption, and PIN validation, ensuring that every transaction is properly authorized.&lt;br&gt;
&lt;strong&gt;Transaction Service:&lt;/strong&gt; The core banking engine, processing balance inquiries, transfers, payments, and purchases while communicating with the banking core system.&lt;br&gt;
&lt;strong&gt;Session Management:&lt;/strong&gt; A Redis-based caching layer that preserved user context across the short-lived USSD sessions, creating a smoother experience.&lt;/p&gt;

&lt;p&gt;The microservices design proves crucial for both development velocity and operational resilience - issues in one component wouldn't cascade to others, and teams could focus on specific aspects of the system.&lt;br&gt;
Key Innovations&lt;br&gt;
Several innovative approaches distinguished this solution:&lt;br&gt;
Dynamic Menu System&lt;br&gt;
Rather than hardcoding USSD menus, the system retrieved menu structures from a database. This seemingly simple choice has profound implications:&lt;/p&gt;

&lt;p&gt;Marketing teams could modify customer offerings without developer intervention&lt;br&gt;
Region-specific promotions could be deployed instantly&lt;br&gt;
Menu updates didn't require system redeployment&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-Tenancy Architecture&lt;/strong&gt;&lt;br&gt;
The system should implement a sophisticated multi-tenant design where:&lt;/p&gt;

&lt;p&gt;A single codebase serves all the subsidiary countries&lt;br&gt;
Each country operated as a configurable "tenant"&lt;br&gt;
Country-specific banking rules, languages, and services be configured rather than coded&lt;br&gt;
New countries could be onboarded without code changes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;USSD Emulator&lt;/strong&gt;&lt;br&gt;
One particularly valuable innovation was a custom USSD emulator that&lt;br&gt;
Simulates real-world USSD interactions in a developer environment&lt;br&gt;
To Allow comprehensive testing without physical phones, this will&lt;br&gt;
greatly reduce development-test cycles.&lt;br&gt;
Enable  automated testing of complex banking flows&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overcoming Technical Challenges&lt;/strong&gt;&lt;br&gt;
The development journey isn't without significant obstacles:&lt;br&gt;
The Session Timeout Problem&lt;br&gt;
USSD sessions typically timeout after just 2-3 minutes, creating a poor user experience if a transaction is interrupted. The solution:&lt;br&gt;
Implement Redis-based session persistence&lt;br&gt;
Created unique session identifiers tied to phone numbers&lt;br&gt;
Reduced redundant data entry, improving customer satisfaction&lt;/p&gt;

&lt;p&gt;Multi-Country Regulatory Compliance&lt;br&gt;
Each country has different banking regulations and compliance requirements. To address this:&lt;/p&gt;

&lt;p&gt;Designed a rule-based configuration system&lt;br&gt;
Create country-specific validation rules without code changes&lt;br&gt;
Implement an audit trail for regulatory reporting&lt;br&gt;
Enable per-country feature toggles for controlled rollouts&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Latency Management&lt;/strong&gt;&lt;br&gt;
External banking APIs often introduces unacceptable latency in the time-sensitive USSD environment. The team:&lt;br&gt;
Should Implement asynchronous processing for non-critical operations&lt;br&gt;
Create a tiered caching strategy for frequently requested data&lt;br&gt;
Establish circuit breakers to gracefully handle API failures&lt;br&gt;
Optimize database queries for minimal response times&lt;/p&gt;

&lt;p&gt;Security in a Constrained Environment&lt;br&gt;
USSD's simplicity presents unique security challenges. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution should&lt;/strong&gt;&lt;br&gt;
Create short-lived JWT tokens for authentication&lt;br&gt;
Encrypted all sensitive data end-to-end&lt;br&gt;
Established strict session expiration policies&lt;br&gt;
Built a fraud detection system monitoring unusual transaction patterns&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-World Impact&lt;/strong&gt;&lt;br&gt;
Accessibility: Banking services becomes available to additional customers without smartphones&lt;br&gt;
Scalability: The platform successfully handles more concurrent USSD sessions&lt;br&gt;
User Experience is Paramount Despite technical constraints, focusing on user experience pays dividends. Simple menus, clear instructions, and minimal key presses improves adoption rates.&lt;br&gt;
Caching Transforms Performance: Strategic caching in Redis dodn't just improve performance it fundamentally changes what was possible within USSD's constraints.&lt;br&gt;
Security requires creativity conventional web security approaches needs adaptation for USSD's unique environment, leading to innovative approaches to authentication and encryption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
The USSD banking solution demonstrates that technology constraints need not limit innovation. By embracing modern architecture patterns while respecting the realities of the African telecommunications landscape, Banks should create a system that expands banking access to thousands of customers.&lt;br&gt;
In markets where smartphone and internet penetration continue to grow but remain far from universal, USSD technology bridges a critical gap—bringing essential financial services to everyone with a basic mobile phone. The project stands as a testament to thoughtful design that meets users where they are, rather than where technology trends might suggest they should be.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Managing Payments and Orders in E-commerce: Avoiding Double Debits</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Thu, 13 Mar 2025 05:12:09 +0000</pubDate>
      <link>https://dev.to/korirmoze/managing-payments-and-orders-in-e-commerce-avoiding-double-debits-1lnb</link>
      <guid>https://dev.to/korirmoze/managing-payments-and-orders-in-e-commerce-avoiding-double-debits-1lnb</guid>
      <description>&lt;p&gt;In the fast-paced world of e-commerce, payment processing is a critical component that directly impacts both customer satisfaction and business profitability. One of the most frustrating issues for customers—and potentially costly problems for businesses—is the double debit: when a customer is charged twice for a single purchase. This article explores the causes of double debits in e-commerce systems and presents practical strategies to prevent them.&lt;br&gt;
Understanding the Double Debit Problem&lt;br&gt;
Double debits typically occur due to system design flaws, network issues, or improper handling of payment callbacks. When a customer completes a purchase, multiple events must be synchronized:&lt;/p&gt;

&lt;p&gt;The payment gateway must process the transaction&lt;br&gt;
The e-commerce platform must record the order&lt;br&gt;
The inventory must be updated&lt;br&gt;
Confirmation must be sent to the customer&lt;/p&gt;

&lt;p&gt;If these processes aren't properly coordinated, issues like double debits can arise, especially when:&lt;/p&gt;

&lt;p&gt;The customer clicks the "Pay" button multiple times&lt;br&gt;
Network timeouts occur during payment processing&lt;br&gt;
Payment gateway callbacks are handled incorrectly&lt;br&gt;
Race conditions exist in the order processing workflow&lt;/p&gt;

&lt;p&gt;Key Strategies to Prevent Double Debits&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implement Idempotent Operations
Idempotency is a property where an operation can be applied multiple times without changing the result beyond the initial application. In payment processing, this means:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Generate a unique idempotency key for each payment attempt&lt;br&gt;
Send this key with each payment request to your payment processor&lt;br&gt;
Configure your system to recognize and reject duplicate payment attempts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Example of generating an idempotency key
public string GenerateIdempotencyKey(int orderId, int customerId)
{
    return $"{orderId}-{customerId}-{DateTime.UtcNow.Ticks}";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Use Transaction IDs Effectively
Every transaction should have a unique identifier that follows it throughout the entire payment flow:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Generate the transaction ID at the beginning of the checkout process&lt;br&gt;
Include this ID in all payment gateway communications&lt;br&gt;
Use the ID to track the transaction status in your database&lt;br&gt;
Verify the ID when processing callbacks from payment gateways&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implement Proper Database Design
Your database schema should support clean transaction tracking:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Create an Orders table with a clear state machine (e.g., "pending," "processing," "completed")&lt;br&gt;
Establish a separate Payments table that links to orders with a one-to-many relationship&lt;br&gt;
Include transaction status fields that track each step of the payment process&lt;br&gt;
Use database constraints to enforce business rules&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Utilize Distributed Locks
For high-volume systems, distributed locks can prevent concurrent processing of the same order:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public async Task ProcessOrderPayment(int orderId)
{
    using (var lockResult = await _distributedLock.AcquireLockAsync($"order-payment-{orderId}", TimeSpan.FromMinutes(5)))
    {
        if (lockResult.IsAcquired)
        {
            // Proceed with payment processing
            // Only one instance of this code can run for a specific order
        }
        else
        {
            // Lock not acquired, payment is already being processed
            _logger.LogWarning($"Order {orderId} is already being processed");
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Implement a Finite State Machine for Orders
Design your order processing system as a finite state machine where:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each order can only be in one state at a time&lt;br&gt;
Transitions between states follow strict rules&lt;br&gt;
Each state transition is atomic and persisted&lt;br&gt;
Payment processing triggers specific state transitions&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;em&gt;Created → PaymentInitiated → PaymentProcessing → PaymentCompleted → Fulfilled&lt;/em&gt;_&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Design Proper Callback Handling
Payment gateways typically send callbacks (webhooks) to notify your system about payment statuses:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Verify the authenticity of each callback&lt;br&gt;
Process callbacks idempotently (handle duplicates gracefully)&lt;br&gt;
Update the order status only if the transition is valid&lt;br&gt;
Implement proper error handling and retry mechanisms&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public async Task HandlePaymentCallback(PaymentCallback callback)
{
    // Verify callback signature
    if (!_paymentService.VerifyCallbackSignature(callback))
    {
        _logger.LogWarning("Invalid callback signature received");
        return;
    }

    // Find the order
    var order = await _orderRepository.GetByTransactionIdAsync(callback.TransactionId);
    if (order == null)
    {
        _logger.LogWarning($"Order not found for transaction {callback.TransactionId}");
        return;
    }

    // Check if this callback has already been processed
    if (_callbackRepository.HasBeenProcessed(callback.CallbackId))
    {
        _logger.LogInformation($"Callback {callback.CallbackId} already processed");
        return;
    }

    // Process based on payment status
    switch (callback.Status)
    {
        case "success":
            await _orderService.CompletePaymentAsync(order.Id);
            break;
        case "failed":
            await _orderService.MarkPaymentFailedAsync(order.Id);
            break;
        // Handle other statuses
    }

    // Mark callback as processed
    await _callbackRepository.MarkAsProcessedAsync(callback.CallbackId);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Implement Client-Side Protection
Prevent multiple submissions from the customer's browser:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Disable the payment button after the first click&lt;br&gt;
Show a "Processing" indicator during payment&lt;br&gt;
Implement clear error messaging if there are issues&lt;br&gt;
Use JavaScript to prevent form resubmission&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.getElementById('paymentForm').addEventListener('submit', function(e) {
    // Disable the submit button
    document.getElementById('submitButton').disabled = true;

    // Show processing indicator
    document.getElementById('processingIndicator').style.display = 'block';

    // Continue with form submission
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Testing Your Payment System&lt;br&gt;
Regular testing is crucial for maintaining a robust payment system:&lt;/p&gt;

&lt;p&gt;Unit Tests: Test individual components of your payment processing system&lt;br&gt;
Integration Tests: Test the interaction between your system and payment gateways&lt;br&gt;
Chaos Testing: Simulate network failures and timeouts to ensure proper recovery&lt;br&gt;
Load Testing: Verify system behavior under high transaction volumes&lt;br&gt;
End-to-End Tests: Simulate complete customer journeys&lt;/p&gt;

&lt;p&gt;Conclusion&lt;br&gt;
Preventing double debits in e-commerce requires a combination of careful system design, proper transaction handling, and robust error management. By implementing idempotent operations, effective database design, and proper state management, you can create a payment system that provides a seamless experience for customers while protecting your business from the financial and reputational damage of payment errors.&lt;br&gt;
Remember that payment processing is not just about technical implementation—it's about building trust with your customers. A reliable payment system is a foundation for long-term e-commerce success.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Understanding Switch Statements vs. Switch Expressions in .NET</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Mon, 10 Mar 2025 06:05:07 +0000</pubDate>
      <link>https://dev.to/korirmoze/understanding-switch-statements-vs-switch-expressions-in-net-1ooe</link>
      <guid>https://dev.to/korirmoze/understanding-switch-statements-vs-switch-expressions-in-net-1ooe</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
When writing conditional logic in C#, developers often face choices about the most appropriate control structures to use. Among these options, switch constructs stand out as powerful tools for handling multiple conditions based on a single value. With the evolution of C# and .NET, we now have two distinct approaches: the traditional switch statement and the more modern switch expression introduced in C# 8. This article explores both approaches, clarifying their syntax, benefits, limitations, and ideal use cases to help you make informed decisions in your code.&lt;br&gt;
Switch Statements: The Traditional Approach&lt;br&gt;
Switch statements have been a fundamental part of C# since its inception, providing a clean alternative to lengthy if-else chains when comparing a single value against multiple possibilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static string GetDayType(int day)
{
    switch (day)
    {
        case 1:
        case 7:
            return "Weekend";
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
            return "Weekday";
        default:
            return "Invalid day";
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use switch statements:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you need to execute multiple lines of code for each case&lt;br&gt;
When you have complex logic within each case&lt;br&gt;
When you need to use control flow statements like continue or break&lt;br&gt;
When working with side effects (like modifying variables outside the switch)&lt;br&gt;
In scenarios where readability of complex branching logic is important&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Potential issues:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Forgetting break statements can cause unexpected "fall-through" behavior where execution continues to the next case&lt;br&gt;
More verbose syntax requires more code&lt;br&gt;
Can be harder to scan and understand at a glance&lt;br&gt;
Prone to errors if proper flow control isn't maintained&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Switch Expressions: The Modern Alternative&lt;/strong&gt;&lt;br&gt;
C# 8 introduced switch expressions as part of the language's movement toward more functional programming paradigms, offering a more concise and expressive syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static string GetDayTypeExpression(int day) =&amp;gt; day switch
{
    1 or 7 =&amp;gt; "Weekend",
    &amp;gt;= 2 and &amp;lt;= 6 =&amp;gt; "Weekday",
    _ =&amp;gt; "Invalid day"
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;When to use switch expressions:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For simple value mappings where each case returns a single result&lt;br&gt;
When using pattern matching features (type patterns, property patterns, etc.)&lt;br&gt;
When you want more readable, compact code&lt;br&gt;
For functional programming approaches where expressions are preferred over statements&lt;br&gt;
When you want compiler enforcement of exhaustiveness (handling all possible cases)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cannot execute multiple statements per case (single expression only)&lt;br&gt;
Not suitable for complex logic requiring multiple operations&lt;br&gt;
Limited ability to handle side effects&lt;br&gt;
Relatively new feature that may not be familiar to all team members&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tuple Patterns in Switch Expressions&lt;/strong&gt;&lt;br&gt;
One of the most powerful features of switch expressions is their ability to match on tuples, allowing you to evaluate multiple values simultaneously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static string ClassifyPoint(int x, int y) =&amp;gt; (x, y) switch
{
    (0, 0) =&amp;gt; "Origin",
    (var x1, 0) =&amp;gt; $"X-axis at {x1}",
    (0, var y1) =&amp;gt; $"Y-axis at {y1}",
    (&amp;gt; 0, &amp;gt; 0) =&amp;gt; "First quadrant",
    (&amp;lt; 0, &amp;gt; 0) =&amp;gt; "Second quadrant",
    (&amp;lt; 0, &amp;lt; 0) =&amp;gt; "Third quadrant",
    (&amp;gt; 0, &amp;lt; 0) =&amp;gt; "Fourth quadrant",
    _ =&amp;gt; "Error"
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tuple patterns allow for extremely concise and readable code when dealing with multiple conditions. You can also use discard patterns (_) for values you don't need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static string GetShippingRate(string country, decimal weight) =&amp;gt; (country, weight) switch
{
    ("USA", &amp;lt; 1) =&amp;gt; "$5.00",
    ("USA", &amp;lt; 5) =&amp;gt; "$10.00",
    ("USA", _) =&amp;gt; "$15.00",
    ("Canada", &amp;lt; 1) =&amp;gt; "$8.00",
    ("Canada", &amp;lt; 5) =&amp;gt; "$15.00",
    ("Canada", _) =&amp;gt; "$20.00",
    (_, &amp;lt; 1) =&amp;gt; "$12.00",
    (_, &amp;lt; 5) =&amp;gt; "$25.00",
    _ =&amp;gt; "$35.00"
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Differences at a Glance&lt;/strong&gt;&lt;br&gt;
Switch statements and switch expressions differ in several important ways. While switch statements use more verbose syntax, switch expressions are concise and expression-based. Switch statements can either return a value or not, but switch expressions always return a value. Pattern matching capabilities are limited in switch statements but extensively supported in switch expressions. Switch statements support multiple operations within a case, whereas switch expressions are limited to a single expression per case. Exhaustiveness is not enforced in switch statements, but the compiler checks all cases in switch expressions. Fall-through behavior is possible (and sometimes problematic) in switch statements but not possible in switch expressions. Tuple support is limited in traditional switch statements but excellent in switch expressions. Finally, switch statements have been part of C# since its initial release, while switch expressions were introduced in C# 8 in 2019.&lt;br&gt;
&lt;strong&gt;Advanced Pattern Matching with Switch Expressions&lt;/strong&gt;&lt;br&gt;
One of the most powerful aspects of switch expressions is their enhanced pattern matching capabilities:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static string DescribeObject(object obj) =&amp;gt; obj switch
{
    null =&amp;gt; "It's null",
    string s when s.Length == 0 =&amp;gt; "Empty string",
    string s =&amp;gt; $"String with length {s.Length}",
    int n when n &amp;lt; 0 =&amp;gt; "Negative number",
    int n =&amp;gt; $"Positive number: {n}",
    Person { Age: &amp;gt; 18 } p =&amp;gt; $"Adult named {p.Name}",
    Person p =&amp;gt; $"Minor named {p.Name}",
    _ =&amp;gt; "Unknown type"
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example shows how switch expressions can match on types, properties, and conditions in a highly readable format that would be much more verbose with traditional switch statements.&lt;br&gt;
&lt;strong&gt;Performance Considerations&lt;/strong&gt;&lt;br&gt;
From a performance perspective, both switch statements and expressions generally compile to similar IL code in simple cases. The compiler optimizes switch constructs (both types) into efficient jump tables when possible, particularly for consecutive integer values. For more complex pattern matching scenarios, switch expressions might generate slightly different code, but the performance difference is typically negligible in most applications.&lt;br&gt;
&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Both switch statements and switch expressions are valuable tools in a C# developer's toolkit, each with their own strengths and appropriate use cases. Switch statements continue to excel in scenarios requiring complex multi-line logic or specific control flow, while switch expressions shine when clarity, conciseness, and functional programming principles are prioritized.&lt;br&gt;
The introduction of switch expressions with tuple support represents a significant advancement in C#'s pattern matching capabilities. This feature allows developers to write more elegant, readable code when evaluating multiple conditions simultaneously, something that would require nested if statements or more complex logic in traditional approaches.&lt;br&gt;
As your codebase evolves, consider gradually adopting switch expressions where they make sense, particularly for pattern matching and tuple-based conditions. By choosing the right construct for each situation, you can write code that is both efficient and expressive, taking full advantage of C#'s rich feature set while maintaining readability and maintainability.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>dotnet</category>
      <category>csharp</category>
      <category>coding</category>
    </item>
    <item>
      <title>Suitable DB Choice in USSD Application</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Thu, 06 Feb 2025 05:27:47 +0000</pubDate>
      <link>https://dev.to/korirmoze/suitable-db-choice-in-ussd-application-221h</link>
      <guid>https://dev.to/korirmoze/suitable-db-choice-in-ussd-application-221h</guid>
      <description>&lt;p&gt;USSD (Unstructured Supplementary Service Data) technology, despite its age, continues to be a critical component in modern digital infrastructure, particularly in emerging markets. Its significance extends beyond basic menu-driven applications, serving as a crucial backup system during mobile app downtime and providing essential services to populations with limited internet access. In the banking sector, USSD applications handle millions of daily transactions, making efficient memory management and robust architecture paramount.&lt;br&gt;
Understanding USSD Architecture&lt;br&gt;
Session Management Challenges&lt;br&gt;
USSD sessions present unique challenges compared to traditional web applications. With a strict timeout limit of 180 seconds and limited payload size, every aspect of the application must be optimized for speed and efficiency. The stateless nature of USSD requires sophisticated session management to maintain context across multiple user interactions.&lt;br&gt;
Memory Constraints&lt;br&gt;
USSD gateways impose strict memory limitations per session, typically ranging from 512 bytes to 1KB. This constraint necessitates careful consideration of data structures and serialization formats. Additionally, high concurrency requirements in production environments mean that memory usage must be strictly controlled to prevent resource exhaustion.&lt;br&gt;
Advanced Implementation Strategies&lt;br&gt;
Dynamic Menu System&lt;br&gt;
Rather than traditional hard-coded menus, a dynamic menu system stored in a database offers several advantages:&lt;/p&gt;

&lt;p&gt;Real-time menu updates without deployment&lt;br&gt;
A/B testing capabilities for different user segments&lt;br&gt;
Personalized menu options based on user history&lt;br&gt;
Multi-language support through dynamic content loading&lt;br&gt;
Menu versioning and rollback capabilities&lt;br&gt;
Better Localization Based on user Location&lt;/p&gt;

&lt;p&gt;State Management Architecture&lt;br&gt;
The implementation utilizes a hybrid approach to state management:&lt;/p&gt;

&lt;p&gt;Short-term session data stored in Redis&lt;br&gt;
Long-term user preferences in SQL database&lt;br&gt;
Cached frequently accessed data in distributed cache&lt;br&gt;
Event sourcing for transaction history&lt;br&gt;
Command pattern for action tracking&lt;/p&gt;

&lt;p&gt;Performance Optimization Techniques&lt;br&gt;
Several strategies are employed to maintain optimal performance:&lt;/p&gt;

&lt;p&gt;Aggressive caching of static menu items&lt;br&gt;
Compression of session data&lt;br&gt;
Batch processing of analytics data&lt;br&gt;
Asynchronous logging and monitoring&lt;br&gt;
Connection pooling for database access&lt;/p&gt;

&lt;p&gt;Security Considerations&lt;br&gt;
Data Protection&lt;br&gt;
The application implements multiple security layers:&lt;/p&gt;

&lt;p&gt;End-to-end encryption of sensitive data&lt;br&gt;
Secure session management&lt;br&gt;
PIN-based authentication, in which case pin first and pin last&lt;br&gt;
Transaction signing&lt;br&gt;
Ensure no sesinsitive data is logged&lt;/p&gt;

&lt;p&gt;Compliance and Auditing&lt;br&gt;
Banking regulations require comprehensive audit trails:&lt;/p&gt;

&lt;p&gt;All user actions are logged&lt;br&gt;
Transaction history is immutable&lt;br&gt;
Session data is archived for compliance&lt;br&gt;
Regular security audits are automated&lt;/p&gt;

&lt;p&gt;Monitoring and Maintenance&lt;br&gt;
Real-time Monitoring&lt;br&gt;
The system includes comprehensive monitoring:&lt;/p&gt;

&lt;p&gt;Session metrics tracking&lt;br&gt;
Performance counters&lt;br&gt;
Error rate monitoring&lt;br&gt;
User journey analytics&lt;br&gt;
Resource utilization alerts&lt;/p&gt;

&lt;p&gt;Disaster Recovery&lt;br&gt;
Robust disaster recovery mechanisms include:&lt;br&gt;
We implemented a hybrid system such that incase of a redis issue the app would default to managing user sessions in the main database.&lt;br&gt;
Automatic fail-over&lt;br&gt;
Session state replication&lt;br&gt;
Database mirroring&lt;br&gt;
Regular backups&lt;br&gt;
Recovery point objectives (RPO)&lt;/p&gt;

&lt;p&gt;[Code examples follow as in previous version...]&lt;br&gt;
Optimization Techniques&lt;br&gt;
Memory Pooling&lt;br&gt;
The application implements custom memory pooling:&lt;/p&gt;

&lt;p&gt;Object pooling for frequent operations&lt;br&gt;
Buffer pooling for network operations&lt;br&gt;
Connection pooling for database access&lt;br&gt;
Thread pooling for concurrent processing&lt;/p&gt;

&lt;p&gt;Cache Strategy&lt;br&gt;
Multi-level caching strategy includes:&lt;/p&gt;

&lt;p&gt;L1 cache: In-memory application cache&lt;br&gt;
L2 cache: Distributed Redis cache&lt;br&gt;
L3 cache: Database query cache&lt;br&gt;
Cache invalidation patterns&lt;br&gt;
Cache warming strategies&lt;/p&gt;

&lt;p&gt;Testing and Quality Assurance&lt;br&gt;
Load Testing&lt;br&gt;
Comprehensive load testing approach:&lt;/p&gt;

&lt;p&gt;Simulation of concurrent users&lt;br&gt;
Peak load testing&lt;br&gt;
Stress testing&lt;br&gt;
Endurance testing&lt;br&gt;
Recovery testing&lt;/p&gt;

&lt;p&gt;Here are the example code snippets to achieve that&lt;br&gt;
USSD Menu Data Models&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public class UssdMenu
{
    public int Id { get; set; }
    public string Code { get; set; }
    public string Text { get; set; }
    public int? ParentId { get; set; }
    public bool IsEndpoint { get; set; }
    public string ServiceCode { get; set; }
    public virtual UssdMenu Parent { get; set; }
    public virtual ICollection&amp;lt;UssdMenu&amp;gt; Children { get; set; }
}

public class UssdSession
{
    public string SessionId { get; set; }
    public string PhoneNumber { get; set; }
    public string CurrentMenuCode { get; set; }
    public Dictionary&amp;lt;string, string&amp;gt; SessionData { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime LastAccessedAt { get; set; }
}

Redis Session Management

public class RedisSessionManager : ISessionManager
{
    private readonly IConnectionMultiplexer _redis;
    private const int SESSION_TIMEOUT_MINUTES = 5;

    public RedisSessionManager(IConnectionMultiplexer redis)
    {
        _redis = redis;
    }

    public async Task&amp;lt;UssdSession&amp;gt; GetOrCreateSessionAsync(string sessionId, string phoneNumber)
    {
        var db = _redis.GetDatabase();
        var sessionKey = $"ussd:session:{sessionId}";

        var sessionData = await db.StringGetAsync(sessionKey);
        if (!sessionData.HasValue)
        {
            var session = new UssdSession
            {
                SessionId = sessionId,
                PhoneNumber = phoneNumber,
                CurrentMenuCode = "MAIN",
                SessionData = new Dictionary&amp;lt;string, string&amp;gt;(),
                CreatedAt = DateTime.UtcNow,
                LastAccessedAt = DateTime.UtcNow
            };

            await SaveSessionAsync(session);
            return session;
        }

        return JsonSerializer.Deserialize&amp;lt;UssdSession&amp;gt;(sessionData);
    }

    public async Task SaveSessionAsync(UssdSession session)
    {
        var db = _redis.GetDatabase();
        var sessionKey = $"ussd:session:{session.SessionId}";

        session.LastAccessedAt = DateTime.UtcNow;
        var serializedSession = JsonSerializer.Serialize(session);

        await db.StringSetAsync(sessionKey, serializedSession, 
            TimeSpan.FromMinutes(SESSION_TIMEOUT_MINUTES));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Conclusion&lt;br&gt;
Building a production-grade USSD application requires careful consideration of memory management, performance optimization, and security. The implementation described here demonstrates how modern architectural patterns and technologies can be applied to create a robust, scalable, and maintainable USSD banking platform. Regular monitoring, testing, and optimization ensure that the system continues to meet the demanding requirements of financial services while providing reliable service to users across all segments of the population.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Building An SAAS in 2025-Week 1</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Tue, 14 Jan 2025 10:02:57 +0000</pubDate>
      <link>https://dev.to/korirmoze/building-an-saas-in-2025-week-1-4pe3</link>
      <guid>https://dev.to/korirmoze/building-an-saas-in-2025-week-1-4pe3</guid>
      <description>&lt;p&gt;As Promised that After each week I would document the progress that I have had with the challenges that I have faced. So Lets Dig IN.&lt;br&gt;
Getting Started&lt;br&gt;
Last week, I focused on building the authentication system for my FarmFluent platform. I started by setting up the project structure using Onion Architecture, which helped me organize my code better and maintain a clean separation of concerns. For my database, I chose PostgreSQL.&lt;br&gt;
Initial Setup&lt;br&gt;
I began by initializing the application and implementing MediatR to handle my commands and queries efficiently. This choice made it easier to manage the different authentication flows I needed to build.&lt;br&gt;
Authentication Implementation&lt;br&gt;
My main focus was on creating a multi-role authentication system that would work for all my users. I implemented three distinct roles:&lt;/p&gt;

&lt;p&gt;Farmers&lt;br&gt;
Agricultural Experts&lt;br&gt;
System Administrators&lt;/p&gt;

&lt;p&gt;One of my key decisions was implementing different authentication requirements for each role. For farmers, I created a simplified authentication system using a four-digit PIN. I made this choice because many of our farmer users have varying levels of digital literacy, I wanted to ensure they could easily access the system without compromising basic security.&lt;br&gt;
For experts and administrators, I implemented more stringent authentication requirements since they have access to sensitive system features and data.&lt;br&gt;
Authentication Features&lt;br&gt;
I successfully implemented several key features:&lt;/p&gt;

&lt;p&gt;User signup and login using Microsoft Identity with a custom user model&lt;br&gt;
Role-based authentication with different security levels&lt;br&gt;
Google signup integration for additional login options&lt;br&gt;
JWT implementation for secure token-based authentication&lt;/p&gt;

&lt;p&gt;Making Authentication More Accessible&lt;br&gt;
For farmers specifically, I focused on making the authentication process as straightforward as possible. The four-digit PIN system works well for basic access, while still maintaining security through:&lt;/p&gt;

&lt;p&gt;Limited login attempts&lt;br&gt;
Account lockout protection&lt;br&gt;
Additional verification for sensitive operations&lt;/p&gt;

&lt;p&gt;Database Implementation&lt;br&gt;
I integrated PostgreSQL into my authentication system, which was a practical choice given my existing SQL license couldn't work for this project. This database is handling all user data, authentication records, and session management effectively.&lt;br&gt;
Current State and Next Steps&lt;br&gt;
The authentication system is now functional with:&lt;/p&gt;

&lt;p&gt;Complete signup and login flows&lt;br&gt;
Working role-based access control&lt;br&gt;
Google authentication integration&lt;br&gt;
JWT token system implementation&lt;/p&gt;

&lt;p&gt;My next steps will focus on:&lt;/p&gt;

&lt;p&gt;Adding additional security features&lt;br&gt;
Implementing more robust farmer-focused accessibility options&lt;br&gt;
Expanding the authentication options for experts and administrators&lt;br&gt;
Adding more comprehensive audit logging.&lt;/p&gt;

&lt;p&gt;Challenges Faced&lt;br&gt;
One of my main challenges was balancing security with accessibility, especially for farmer users. While a four-digit PIN isn't typically recommended for security reasons, I implemented additional safeguards to protect these accounts while maintaining ease of use.&lt;br&gt;
The integration of multiple authentication methods (local PIN-based, Google OAuth, and standard password-based) required careful planning to ensure all systems worked together seamlessly.&lt;br&gt;
Technical Decisions&lt;br&gt;
Throughout this implementation, I made several key technical choices:&lt;/p&gt;

&lt;p&gt;Used Onion Architecture for clean separation of concerns&lt;br&gt;
Implemented MediatR for better command and query handling&lt;br&gt;
Chose PostgreSQL for its robust features and licensing compatibility&lt;br&gt;
Integrated Microsoft Identity for flexible user management&lt;br&gt;
Added Google authentication for additional login options&lt;/p&gt;

&lt;p&gt;Looking Forward&lt;br&gt;
While the basic authentication system is now in place, I plan to continue improving it by:&lt;/p&gt;

&lt;p&gt;Adding more security features for sensitive operations&lt;br&gt;
Implementing additional accessibility options&lt;br&gt;
Expanding audit logging capabilities&lt;br&gt;
Adding more authentication providers&lt;br&gt;
Work On courses and modules with all their dependent functionalities.&lt;/p&gt;

&lt;p&gt;The current implementation provides a solid foundation for these future improvements while meeting our immediate needs for user authentication and access control.&lt;br&gt;
Conclusion&lt;br&gt;
This week's work has resulted in a functional authentication system that serves our diverse user base. While there's still room for improvement, the current implementation successfully balances security requirements with accessibility needs, particularly for our farmer users.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>dotnet</category>
      <category>programming</category>
      <category>saas</category>
    </item>
    <item>
      <title>Building An SAAS in 2025</title>
      <dc:creator>Korir Moses</dc:creator>
      <pubDate>Sun, 05 Jan 2025 15:24:31 +0000</pubDate>
      <link>https://dev.to/korirmoze/building-an-saas-in-2025-2m89</link>
      <guid>https://dev.to/korirmoze/building-an-saas-in-2025-2m89</guid>
      <description>&lt;p&gt;Happy New Year! One of my resolutions this year is to build a SaaS solution in agriculture and document my journey weekly. My goal is to showcase my skills beyond my day-to-day work while addressing a significant need in this sector.&lt;/p&gt;

&lt;p&gt;This idea sprouted from conversations with friends over the holidays about investing in agriculture. Our biggest challenge? None of us are experts in the field. Like many, we’ve heard cautionary tales about "telephone farmers" who face significant losses due to a lack of hands-on expertise. For individuals in tech, the learning curve in unfamiliar fields often involves Googling research papers, watching YouTube videos, or enrolling in courses on platforms like Udemy and Coursera.&lt;/p&gt;

&lt;p&gt;Although agricultural courses exist online, they often lack the accessibility and focus needed to make a real impact. In contrast, we’ve seen a rise in educational content on social media about investing in money market funds (MMFs), government bonds, and other low-risk options. While these are great, I believe in the principle of "go big or go home." Agriculture in Africa, with its untapped potential, seems like the perfect opportunity.&lt;/p&gt;

&lt;p&gt;Through my research, I noticed that resources for farmers remain disorganized. Most rural farmers rely on WhatsApp and Facebook groups to communicate. However, these platforms often result in cluttered messages and disorganized timelines. My solution? A platform that provides:&lt;/p&gt;

&lt;p&gt;Curated Courses: Farmers can enroll in structured lessons.&lt;br&gt;
Organized Communication: A dedicated chat where farmers can ask questions and get expert answers.&lt;br&gt;
Expert Contributions: A space for agricultural experts to share their knowledge through courses.&lt;br&gt;
This week marks the start of building this platform—a farming learning solution. While the features will expand over time, my initial focus is on creating an MVP.&lt;/p&gt;

&lt;p&gt;Tech Stack:&lt;/p&gt;

&lt;p&gt;Backend: .NET&lt;br&gt;
Frontend: Vue.js&lt;br&gt;
Database: SQL&lt;br&gt;
Stay tuned as I share updates and insights on this exciting journey!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>saas</category>
      <category>dotnet</category>
      <category>vue</category>
    </item>
  </channel>
</rss>
