When low-level .NET performance optimization is worth the complexity
Daniel Marbach draws on his pull requests to the Azure .NET SDK to explain when low-level performance work pays off. He argues that in library code, small allocation decisions multiply across every caller, yet added complexity carries a maintenance cost. The post offers a practical decision framework for library authors and application developers alike.
Key points
- Decide whether a code path deserves optimization from its call frequency and user impact, measured with real data
- In library code, small allocations multiply because every message or request triggers them
- Look at input/output costs first, then allocations, and only then algorithmic details
- A gain for one input type can slow another; a benchmark alone does not show which inputs matter
- Readability is a cost too, so keep simple code in setup and rarely executed paths
- Give optimization investigations a time budget and ship one measured change
Daniel Marbach argues that low-level .NET optimization should be judged by where the code runs. He learned the craft through pull requests to the Azure .NET SDK, where maintainers often rejected changes by asking whether the complexity was justified. In library code, a small allocation repeated for every message in a messaging client adds up quickly, so the same change matters far more than in application code.
His practical order is to check input and output costs first, then allocations, and only then algorithmic detail. A Service Bus change that favored materialized IEnumerable<string> inputs helped common callers but slowed lazy sequences, which shows that benchmarks only cover the cases you chose. He also keeps readable code on rarely run paths and suggests a short time budget with one measured change.
Real-world use
- Reviewing a Service Bus or Event Hubs consumer path that handles thousands of messages per second
- Reducing allocations in a shared helper that runs on every request, after a profiler has flagged it
- Checking whether an old helper written for low call volume now sits on a high-traffic path
Why it matters
Spending complexity only on measured, frequently executed paths keeps the codebase maintainable while still delivering real gains. If you maintain a library, remember that one change reaches every consumer.
Related stories
- Building AI Agents in C# with Microsoft Agent FrameworkBruno Capuano (El Bruno)2 d ago
- Collection Return Types in C#: Interfaces, Views, and SnapshotsNick Cosentino (Dev Leader)2 d ago
- Dynamic Gauss-Legendre numerical integration in C#: computing nodes and weights on the fly without overflowHabr C# (ru)2 d ago