Caring About Performance Is Nitpicking Now, I Guess

RickRick
5 min read

Last week, I found myself in one of those situations that every senior developer knows all too well. You know the one—you raise a legitimate architectural concern, and someone dismisses it as "nitpicking."

Here's what happened: I was reviewing some Azure Service Bus message processing code that used the standard documented approach with IServiceScopeFactory. When I mentioned that creating scopes for every message could impact performance, especially if message volume grows, I got hit with: "Stop nitpicking. This is the documented best practice, and our volume is low anyway."

This got me thinking about the fine line between nitpicking and legitimate technical concerns. Spoiler alert: they're not the same thing.

So here's what went down

The implementation looked like this:

public class ServiceBusMessageHandler : BackgroundService
{
    private readonly IServiceScopeFactory _scopeFactory;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await foreach (var message in messageStream)
        {
            using var scope = _scopeFactory.CreateScope();
            var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();

            await ProcessMessage(message, dbContext);
        }
    }
}

Is this correct? Absolutely. Is it the safest approach? Yes. Could it become a bottleneck? Also yes.

But apparently, pointing this out made me "nitpicky."

Look, there's a difference between being picky and being concerned

Let me clear something up. Real nitpicking in code reviews looks like this:

  • "This variable should be called userData instead of data"

  • "You're missing a space after the if statement"

  • "Use var instead of the explicit type here"

  • "This comment has a typo"

Legitimate architectural concerns look like this:

  • "This approach might not scale well"

  • "This could create memory pressure under load"

  • "Have we considered the performance implications?"

  • "This pattern has caused issues in similar systems"

See the difference? One is about style preferences. The other is about system design and future-proofing.

But wait, the volume is low so it doesn't matter, right?

Here's where things got really frustrating. The response to my concern was essentially: "Our message volume is low, so it doesn't matter."

This is such a dangerous mindset. Here's why:

Systems Grow

That "low volume" system today could be processing 10x the messages next month. I've seen it happen countless times. You start with 100 messages per day, and suddenly you're dealing with 100,000.

Performance Habits Matter

Building performance awareness into your architecture from day one is way easier than retrofitting it later. It's not about premature optimization—it's about informed design decisions.

The Real Cost of "Later"

Refactoring for performance after the fact typically costs 10x more than considering it upfront. Plus, you're often doing it under pressure when the system is already struggling.

The thing is, most devs today missed the EF Core pain years

Here's something that drives me crazy: many developers today only know EF Core 6+ era, which is genuinely fast and well-optimized. But those of us who lived through EF Core 1.x through 5.x remember the pain:

  • Context creation was expensive

  • Memory tracking issues were common

  • Connection pooling was suboptimal

  • Change tracking could kill performance

When I raise concerns about EF Core patterns, I'm not being paranoid—I'm remembering production systems that fell over because we trusted the "best practice" documentation without understanding the trade-offs.

Microsoft docs are great, but they're not optimizing for what you think

Don't get me wrong—Microsoft's documentation is excellent. When they say using IServiceScopeFactory is the best practice for hosted services, they're absolutely right. But "best practice" optimizes for:

  • ✅ Safety and correctness

  • ✅ Memory leak prevention

  • ✅ Proper service lifetimes

  • ✅ Threading safety

It doesn't necessarily optimize for:

  • ❌ Maximum throughput

  • ❌ Minimum resource usage

  • ❌ Cost efficiency

  • ❌ Performance at scale

Understanding this distinction is crucial.

If you do need to optimize later (and you probably will)

If and when performance becomes important, here are some alternatives:

Batch Processing

// Process messages in batches to amortize scope creation cost
const int batchSize = 50;
using var scope = _scopeFactory.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();

foreach (var batch in messages.Chunk(batchSize))
{
    await ProcessBatch(batch, dbContext);
    dbContext.ChangeTracker.Clear(); // Prevent memory buildup
}

IDbContextFactory

// More control over context lifecycle
public class OptimizedMessageHandler
{
    private readonly IDbContextFactory<MyDbContext> _contextFactory;

    public async Task ProcessMessages(IEnumerable<Message> messages)
    {
        using var context = _contextFactory.CreateDbContext();
        // Process multiple messages with same context
    }
}

This isn't really about the code though

The issue isn't the technical implementation—it's the dismissive attitude toward performance considerations. When someone raises a scalability concern, the response should be: "Interesting point. What are you thinking about specifically?" not "Stop nitpicking."

This kind of dismissal shuts down important architectural discussions. It also creates a culture where people stop raising valid concerns because they don't want to be labeled as difficult.

Here's how I see it

Look, I get it. Sometimes we do overthink things. Sometimes a simple, documented approach is exactly what you need. But there's a huge difference between:

  • Premature optimization: "Let me write custom assembly code for this string concatenation"

  • Architectural awareness: "This pattern might not scale well if our assumptions change"

Raising questions about scalability, especially with historical context, isn't nitpicking—it's good engineering.

So what's the point of all this?

Next time someone dismisses your performance concerns as "nitpicking," ask yourself:

  1. Am I worried about style, or system behavior?

  2. Could this decision impact future scalability?

  3. Am I drawing from real experience with similar patterns?

If you're thinking about system behavior, scalability, and drawing from experience, you're not nitpicking. You're doing your job as a senior developer.


Have you been in similar situations? How do you handle it when architectural concerns get dismissed as nitpicking? I'd love to hear your stories in the comments.

0
Subscribe to my newsletter

Read articles from Rick directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Rick
Rick

15+ years of experience having fun building apps with .NET I began my professional career in 2006, using Microsoft technologies where C# and Windows Forms and WPF were the first technologies I started working with during that time. I had the opportunity to actively participate in the Windows ecosystem as an MVP and Windows 8/Windows Phone application developer from 2013-2018. Throughout my career, I have used Azure as my default cloud platform and have primarily worked with technologies like ASP.NET Core for multiple companies globally across the US, UK, Korea, Japan, and Latin America. I have extensive experience with frameworks such as: ASP.NET Core Microsoft Orleans WPF UWP React with TypeScript Reactive Extensions Blazor I am an entrepreneur, speaker, and love traveling the world. I created this blog to share my experience with new generations and to publish all the technical resources that I had been writing privately, now made public as a contribution to enrich the ecosystem in which I have developed my career.