BenchmarkDotNet helps you to transform methods into benchmarks, track their performance, and share reproducible measurement experiments. It's no harder than writing unit tests! Under the hood, it performs a lot of magic that guarantees reliable and precise results thanks to the perfolizer and pragmastat statistical engine.
One of the most common mistakes in multithreaded programming is assuming that operations on in-memory variables are automatically atomic.
They are not.
Even a simple statement like counter++; is actually composed of multiple steps:
If multiple threads execute this simultaneously, race conditions can occur and updates may be lost.
Optimizing SQL performance isn’t just about writing queries, it’s about designing smarter systems. Here are some practical insights:
Indexing is critical
Proper indexes dramatically reduce query time by avoiding full table scans and improving joins.
Write efficient queries
Avoid SELECT *, unnecessary functions in WHERE clauses, and leading wildcards , these prevent index usage and slow everything down.
Optimize joins & filtering
Filter data early, use appropriate JOIN types, and ensure join columns are indexed to minimize processing overhead.
Reduce unnecessary operations
Prefer UNION ALL over UNION (when duplicates are acceptable) and replace multiple OR conditions with IN for better performance.
Monitor & tune continuously
Track CPU, memory, disk I/O, and query performance to identify bottlenecks and optimize proactively.
Configuration matters as much as code
Default database settings are rarely optimal—fine-tuning them can unlock major performance gains.
💡 Bottom line:
Great performance comes from a combination of well-structured queries, proper indexing, and continuous monitoring , not just more hardware.
Over the past few years, I’ve noticed a growing trend in .NET projects:
Developers are replacing Task with ValueTask everywhere , assuming it’s a free performance improvement.
It’s not.
While ValueTask was introduced to reduce allocations in high-performance scenarios, it comes with trade-offs, constraints, and subtle complexity that many teams underestimate.
In most real-world applications CRUD systems, Web APIs, microservices, background jobs Task is still the correct default choice.
In this article, I break down:
Task remains the recommended return type for most async methodsValueTask adds zero benefit (and sometimes makes things worse)Task inside ValueTask defeats the purposeValueTask shines (high-frequency infrastructure code like ASP.NET Core internals, pipelines, sockets, etc.)One of the biggest mistakes in performance engineering is optimizing without evidence.ValueTask is a precision tool , not a default replacement.
If you're working with async/await in .NET, this deep dive will help you:
Wolverine is a next-generation .NET mediator and messaging framework that combines:
At its core, Wolverine is centered around messages and handlers with minimal ceremony, favoring conventions and code-generation over heavy framework base classes.
Technical leadership isn’t about pleasing stakeholders at the expense of the product’s future.
Ignoring architecture, choosing outdated technologies, or dismissing technical risks may speed up delivery today,but it creates long-term costs, frustrated teams, and fragile systems.
Technical debt can be a conscious strategy. Choosing the wrong technology is a managerial failure.
A strong technical lead balances customer needs with technical quality, makes hard decisions early, and treats technical quality as what it really is: risk management for the future.
In modern cloud-native systems, managing state across multiple API calls can be tricky. Imagine an airline ticket purchase:
1. List flights & prices
2. Reserve a flight
3. Complete payment
If the price changes between steps, how do you ensure the user can still complete the process reliably?
Traditional 𝗦𝘁𝗶𝗰𝗸𝘆 𝗦𝗲𝘀𝘀𝗶𝗼𝗻𝘀 can help by routing a user to the same instance, but they come with drawbacks: tight coupling, failover risks, and uneven load distribution.
A more robust solution? 𝗦𝗵𝗮𝗿𝗲𝗱 𝗦𝘁𝗮𝘁𝗲 using Redis or NoSQL:
• Store temporary state on each API call
• Persist final state to the main database
• Handle concurrency with 𝗢𝗽𝘁𝗶𝗺𝗶𝘀𝘁𝗶𝗰 𝗟𝗼𝗰𝗸𝗶𝗻𝗴
• Ensure 𝗮𝘁𝗼𝗺𝗶𝗰 𝘂𝗽𝗱𝗮𝘁𝗲𝘀 using transactions or Lua scripts
• Use 𝗶𝗱𝗲𝗺𝗽𝗼𝘁𝗲𝗻𝗰𝘆 𝗸𝗲𝘆𝘀 to prevent duplicate operations
In large distributed systems, adding a 𝗖𝗼𝗿𝗿𝗲𝗹𝗮𝘁𝗶𝗼𝗻 𝗜𝗗 alongside state makes debugging and tracing end-to-end workflows much easier.
Proper TTL, failure handling, and atomicity ensure your solution is 𝘀𝗰𝗮𝗹𝗮𝗯𝗹𝗲, 𝗿𝗲𝘀𝗶𝗹𝗶𝗲𝗻𝘁, 𝗮𝗻𝗱 𝗽𝗿𝗼𝗱𝘂𝗰𝘁𝗶𝗼𝗻-𝗿𝗲𝗮𝗱𝘆.
RowVersion is a blunt instrument for optimistic concurrency.
In EF Core, RowVersion treats every data mutation as concurrency-critical.
That assumption doesn’t always hold in real systems.
In read-heavy applications, entities often mix:
Title)ViewCount, LastSeen, HitCount)With RowVersion:
DbUpdateConcurrencyExceptionNot because of a semantic conflict ,
but because all mutations are treated equally.
A more intentional design is to scope concurrency to business intent, not storage changes.
Using [ConcurrencyCheck] on selected properties:
Concurrency is a modeling decision, not a framework default.
Design it around what should conflict, not what happened to change.
Email notifications are still one of the simplest and most reliable ways to keep users informed in many applications.
For lightweight scenarios—such as alerts, confirmations, or internal notifications—using an SMTP server can be a practical and cost-effective solution.
In this article, we focus primarily on configuring and using Google App Passwords, and then briefly demonstrate how to send an email from a .NET application using Gmail’s SMTP server.
While Gmail is used as the example, the same concept applies to most SMTP providers.
Have you ever wondered how EF maps inheritance hierarchies to database tables?
When working with inheritance in your domain model, Entity Framework Core must decide how to represent that hierarchy in the database. Although the class structure may look simple, EF Core has multiple strategies for mapping derived types, and each one has significant performance and storage implications.
By default, EF Core uses Table-Per-Hierarchy (TPH), but newer versions also support Table-Per-Type (TPT) and Table-Per-Concrete-Type (TPC). Choosing between them is not just a design decision—it affects query performance, insert/update costs, schema complexity, and scalability.
© vahid arya. All Rights Reserved.