I get bombarded with questions like these all the time from my fellow developers:

  • "Which is faster, .Count() or .Any()?"
  • "Should I use a Redis database for my reads rather then SQL Server? I heard Redis is amazingly fast."
  • "Won't [Snippet X] be faster than [Snippet Y] because it's more optimized?"

The interesting thing about all of these questions is that they each have a defined, measurable answer. Almost certainly, .Any() will be faster than .Count() (for an IEnumerable, as we'll see below). Almost certainly, in simple cases, Redis will be faster for reads than SQL Server. Optimized code will be faster than non-optimized code (because, really, that's kinda what optimized means). All of these questions can be answered in a definable way.

In each of these cases, though, the developer asking is probably posing the wrong question. The dev is concerned about performance, forgetting that 97% of the time performance doesn't matter. Spending time on making your app perform better is, often, time and effort wasted, as the energy you put in to solving that problem might have been better spent elsewhere.

In The Line Of Fire Business

Most developers (including me) work on line-of-business apps. A line-of-business app is one that directly contributes to a customer transaction or business need. A great many of these apps are internal, meaning that no one outside that company will ever see them.

The vast majority of the time, programmers (including myself) are working on software that will probably never be seen by the outside world at large, never be used by anyone other than our coworkers, direct customers, and peers. In these situations, what's most important is zeroing in on getting the user requirements implemented correctly. In fact, trying to do micro-optimization of this type on these kinds of apps actually hurts your team, as the time spent trying to implementing these micro-optimizations could be better spent implementing the core requirements.

A naval cadet looks down the sight of her training weapon.

Let's take one of the questions from earlier. Here's some sample code that uses Count() and Any() to determine if a User has any Email Addresses:

var user = userRepository.Get(id);
if(user.EmailAddresses.Count() > 0)
    //Send an email to all addresses

var user = userRepository.Get(id);
    //Send an email to all addresses

What's interesting about these two snippets is that the answer of "which is faster" depends on the type of the collection EmailAddresses; if it is a simple IEnumerable then Any() is faster, but for List or ICollection Count() is faster.

Let's say we (in our capacity as a lead developer) ran across either this code in a code review for an internal app. Should we flag either scenario, tell the developer to change their code for performance reasons? No, because there isn't sufficient justification for changing the code.

The mental algorithm I use to determine if I should refactor a given code snippet goes like this:

  1. If the code doesn't work, change it.
  2. If the code doesn't fulfill the customer requirements, change it.
  3. If the code doesn't match team coding standards, change it.
  4. If you think the code isn't fast enough, prove it.
  5. If you can't prove it or don't have time to, leave it alone.

If I can't prove that the code is a performance problem, then I probably don't care about fixing it. And yet, lots of devs will still try to optimize everything, even snippets that don't really need it (I know because I'm very much guilty of this). The question becomes: why do we like trying to optimize everything, even when we suspect that it probably isn't that important to do so? The answer comes down to one thing: it feels good to solve problems.

Solve All The Things

Software development is 100% about solving problems. Without problems there wouldn’t be a need for software.

John Sonmez

Programmers are, at their core, problem solvers. We take pride in our ability to break down problems into composable parts, solve for the issue each of those parts represent, then put the parts back together in a way that resembles a functional, working application. We do this because a) we get paid for it, but more importantly b) because it's fun! Solving problems makes us happy.

Sometimes, though, our problem-solving drive misfires and manufactures solutions when, really, there wasn't a problem to solve in the first place.

My coworker (we'll call her Claire) came to me with a problem the other day. She had a snippet of code that looked something like this:

public string EmailBody(string salutation, string name, string bodyText, string closing, string signatureName)
    string body = "";
    body += salutation + " " + name + ":\n\n" + bodyText + "\n" + closing + "\n" + signatureName;
    return body;

Claire had read this answer on StackOverflow and wanted to refactor this method to use StringBuilder so that, in her words, "it would be faster". The refactored method looked like this:

public string EmailBody(string salutation, string name, string bodyText, string closing, string signatureName)
    StringBuilder body = new StringBuilder();
    return body.ToString();

She hadn't run any benchmarks on these two snippets, and was basing her supposition that the refactored code would be "faster" on a hunch and that StackOverflow question. This method was called fairly often in the app we were building, but that app had very little users and hadn't shown any need for performance testing. In short, she'd solved a problem she couldn't prove existed.

I told her to go back and benchmark the two methods. The difference between them turned out to be miniscule (something like 10ms) and so I told her not to worry about it, as we had bigger fish to fry. She objected, saying that this could back to bite us if the app gets heavy load. I agreed with her, essentially saying if it did bite us, we'd fix it, but until then we have 40% of the requirements not implemented and we needed to get those done first before doing any optimizations at this level. She wasn't happy about it, but understood.

All of which is to say: don't fix things performance-related because you think they are a problem. Rather, fix things you can prove are a problem.

Correct, Readable, Fast, In That Order

None of this is to say that performance never matters (after all, those who speak in absolutes are invariably wrong). Just that performance doesn't matter as much as we might like to think it does. When it does matter, it can matter A LOT.

A closeup shot of a steer ruler
Steel ruler closeup from Wikimedia, used under license

Let's take StackOverflow for instance, whose co-founder Jeff Atwood explicitly writes that performance is a feature for the site. I can tell, just by using it over the last seven years, that the team has spent a LOT of time tweaking, improving, generally making the site's performance so good that it's a non-issue as to whether or not StackOverflow will respond quickly. The site is remarkably performant on relatively little hardware (and yes, I know that post is two years old and they've probably gotten some updates since). StackOverflow takes immense pride in providing one of the most responsive web experiences around, and I'd be willing to bet that the site's performance is a major reason why it's become the go-to site for developers needing answers.

But the question is, do you work on huge customer-facing sites like StackOverflow?

If you don't, and you probably don't, then performance is not an important issue for you. Yes, this means you (and me). You probably don't need those performance tweaks, you don't need less-than-10ms response time, you don't need to waste energy and effort plunging into the depths of your libraries to save some milliseconds in processing. It's just extra work with no tangible benefit.

The most important thing for you, the line-of-business app developer, to focus on is acquiring and implementing the correct requirements for your site. After that, it's critical that you make your code readable so that other devs can correct or expand on it. Only after those are done should you focus on improving your app's performance.

In other words, the performance of your application is at best a tertiary concern, behind making it correct and making it readable.

Get it right, get it beautiful, get it fast. In that order.

Joris Timmermans

Performance doesn't matter, unless you can prove that it does. Until then, work on your other pressing problems, and don't worry about shaving that extra 10 ms off your response time.

What do you think about performance in general? Should it be more important, and where does its importance fall relative to getting correct requirements and making beautiful code? Have you worked on applications where performance unquestionably was important, and how did you ensure that the application measured up? Let me know in the comments!

Happy Coding!