Wednesday, February 16, 2011

On Premature Optimization

There has been a lot of discussion in my Twitter peer group lately about what's the right level of optimizing website performance and how to go about it.
Premature optimization is the root of all evil.
This sentence is true but it might also seem like an excuse to never optimize, so lets elaborate a little on the condition when and how to optimize your code.
Lets start by defining optimization for the purpose of this blog entry:
When optimizing for performance one chooses between two or more implementation strategies and picks the fastest one based on the reason that it is faster then the other strategies.
Now that we have defined performance optimization as a choice between multiple implementation strategies is becomes clear that it is just a subset of the more general concept of software design. When picking between implementation strategies in software design one has to regularly pick the worst of all evils to achieve the best possible outcome. The trade offs are:
  • Maintainability
  • Scope
  • Quality
  • Performance
You never get more than 3 of those right with limited ressources. This also means that if we want great performance we will have to be cool with worse maintainability, reduced scope and/or worse quality. As a software designer we need to be aware of this and should make a very conscious decision when we opt for great performance.
Now Steve Souders and friends have proven to great length that in the special case of website and web application load time performance can have a great positive impact on the overall success of a project, thus is will often be the right thing to opt for performance and e.g. decide to reduce scope.
Now if performance optimization can be a good thing, then why is premature optimization always evil: Because the premature refers to the fact that the performance optimization was not done because of a conscious design decision but for other reasons: E.g. because we can or because when writing that ray tracer the other day something proved to be faster.
To differentiate mature from premature optimization I already late down that conscious decisions are the key factor. What is needed for a conscious decision:
When thinking about data and performance profiling comes to mind. Yes, profiling is very, very important, but I was also referring to data in terms of how the optimization will impact the scope, quality and maintainability of your application.
Unfortunately profiling is not the solution to all performance problems. Often you have to make decision early in the software design process when little code is written and you cannot really profile anything (you could micro profile but you don't know if that code is relevant to your overall performance yet). Thus besides profiling you also want to use experience to get some things right in the first place. If you don't have that experience, buy some books. Experience often also is the only way to assess how an optimization will impact things like quality or maintainability. I guess, you need a lot of experience to write good software :)
The good thing is: Computers are fast. This leads to an important rule:
When things aren't too slow, optimizing them will always be a bad idea because the the trade offs in quality, maintainability and scope will result in a net loss.
When designing your software, you should never pick an implementation strategy because it is faster unless you have data (through profiling or experience) to support your decision.
In concrete terms for JavaScript when picking between
  1. C-style loop and forEach -> use forEach.
  2. String builder and concatenation -> use concatenation
  3. Script tag VS. script loader -> use a script tag
  4. etc.
If you ever pick the faster alternative that is cool as well, just make sure that when you work on my team that you are able to back up your decision with data or I'll make you change it to the slower code with a really embarrassing commit statement :)
PS: Point 1+2 in the list above are examples where you will only ever opt to the faster version after profiling. Point 3 is a good example where your experience might tell you that the tradeoff of using a script loader is well worth the effort.
Post a Comment