views:

597

answers:

14

One of the most common mantras in computer science and programming is to never optimize prematurely, meaning that you should not optimize anything until a problem has been identified, since code readability/maintainability is likely to suffer.

However, sometimes you might know that a particular way of doing things will perform poorly. When is it OK to optimize before identifying a problem? What sorts of optimizations are allowable right from the beginning?

For example, using as few DB connections as possible, and paying close attention to that while developing, rather than using a new connection as needed and worrying about the performance cost later

+3  A: 

If you don't have a performance problem, then you should not sacrifice readability for performance. However, when choosing a way to implement some functionality, you should avoid using code you know is problematic from a performance point of view. So if there are 2 ways to implement a function, choose the one likely to perform better, but if it's not the most intuitive solution, make sure you put in some comments as to why you coded it that way.

Elie
+14  A: 

I think you're looking at this the wrong way. The point of avoiding premature optimization isn't to avoid optimizing, it's to avoid the mindset you can fall into.

Write your algorithm in the clearest way that you can first. Then make sure it's correct. Then (and only then) worry about performance. But also think about maintenance etc.

If you follow this approach, then your question answers itself. The only "optimizations" that are allowable right from the beginning are those that are at least as clear as the straightforward approach.

simon
I second that.. If I could give you 10+ votes I would...
Nils Pipenbrinck
+4  A: 

IMHO, none. Write your code without ever thinking about "optimisation". Instead, think "clarity", "correctness", "maintainability" and "testability".

anon
Of course... I consider each of those optimizations. :)
Randolpho
Well, that's fine if you are developing a website or GUI, but I would bet that embedded systems programmers would disagree with you.
Ed Swangren
@ed - your psychic abilities have failed you - I don't do websites or GUIs.
anon
I don't know, it often takes quite a bit of effort to make code clear and maintainable. How much effort should you put in to it up front, vs just fixing it as you need to? (I'll never argue against correctness and testability, mind you.)
Jerph
@jerph - not a discussion to have in the confines of an SO comment box, I'm afraid.
anon
@Neil: Well you obviously don't work on anything that is performance critical either. Sometimes you only have 128K and a 200 Mhz processor. You can't ignore efficiency in that case. Anyhow, blanket statements like "never" are *almost* always wrong.
Ed Swangren
There is a balance between "never" and "always".
Ed Swangren
@ed I've written software for process controllers, I've written software for IBM mainframes. I did both, very succesfully, using the guidelines summarised in my answer above.
anon
@Neil: Then you must have found that balance :)
Ed Swangren
+25  A: 

I think you are missing the point of that dictum. There's nothing wrong with doing something the most efficient way possible right from the start, provided it's also clear, straight forward, etc.

The point is that you should not tie yourself (and worse, your code) in knots trying to solve problems that may not even exist. Save that level of extreme optimizations, which are often costly in terms of development, maintenance, technical debt, bug breeding grounds, portability, etc. for cases where you really need it.

MarkusQ
A: 

Don't call Collection.ElementCount directly in the loop check expression if you know for sure this value will be calculated on each pass.

Instead of:

for (int i = 0; i < myArray.Count; ++i)
{
    // Do something
}

Do:

int elementCount = myArray.Count;
for (int i = 0; i < elementCount ; ++i)
{
    // Do something
}

A classical case.

Of course, you have to know what kind of collection it is (actually, how the Count property/method is implemented). May not necessarily be costy.

User
Hmm. Isn't the real optimization not to put things that are calculated on each pass in a property? Make it a function and it will be clear.
Jerph
Never heard of that approach really... The thing is however that some people won't come up with the idea that even calling a method in a loop could be bad.
User
I'm willing to bet, that most of the time length/count of an array/collection is a O(1) operation. So I'd have to disagree.
Greg Dean
Or use a language which can do the iteration for you?
Andrew Grimm
Such a language will just intrinsically call standard interface methods of a collection. This can also be not optimal. If you have all details hidden does not mean yet it's 100% efficient.
User
+6  A: 

The best optimization you can make at any time is to pick the correct algorithm for the problem. It's amazing how often a little thought yields a better approach that will save orders of magnitude, rather than a few percent. It's a complete win.

Things to look for:

  • Mathematical formulas rather than iteration.
  • Patterns that are well known and documented.
  • Existing code / components
dwc
+2  A: 

As you develop in your career as a developer, you'll simply grow in awareness of better, more reasonable approaches to various problems. In most cases I can think of, performance enhancement work resulted in code that was actually smaller and simpler than some complex tangle that evolved from working through a problem. As you get better, such simpler, faster solutions just become easier and more natural to generate.

Update: I'm voting +1 for everyone on the thread so far because the answers are so good. In particular, DWC has captured the essence of my position with some wonderful examples.

Mark Brittingham
+2  A: 

Documentation

Documenting your code is the #1 optimization (of the development process) that you can do right from the get go. As projects grow, the more people you interact with and the more people need to understand what you wrote, the more time you will spend

Toolkits

Make sure your toolkit is appropriate for the application you're developing. If you're making a small app, there's no reason to invoke the mighty power of an Eclipse based GUI system.

Complilers

Let the compiler do the tough work. Most of the time, optimization switches on a compiler will do most of the important things you need.

System Specific Optimizations

Especially in the embedded world, gain an understanding of the underlying architecture of the CPU and system you're interacting with. For example, on a Coldfire CPU, you can gain large performance improvements by ensuring that your data lies on the proper byte boundary.

Algorithms

Strive to make access algorithms O(1) or O(Log N). Strive to make iteration over a list no more than O(N). If you're dealing with large amounts of data, avoid anything more than O(N^2) if it's at all possible.

Code Tricks

Avoid, if possible. This is an optimization in itself - an optimization to make your application more maintainable in the long run.

Robert P
A: 

Agree with Neil's opinion here, doing performance optimizations in code right away is a bad development practice.

IMHO, performance optimization is dependent on your system design. If your system has been designed poorly, from the perspective of performance, no amount of code optimization will get you 'good' performance - you may get relatively better performance, but not good performance.

For instance, if one intends to build an application that accesses a database, a well designed data model, that has been de-normalized just enough, if likely to yield better performance characteristics than its opposite - a poorly designed data model that has been optimized/tuned to obtain relatively better performance.

Of course, one must not forget requirements in this mix. There are implicit performance requirements that one must consider during design - designing a public facing web site often requires that you reduce server-side trips to ensure a 'high-performance' feel to the end user. That doesn't mean that you rebuild the DOM on the browser on every action and repaint the same (I've seen this in reality), but that you rebuild a portion of the DOM and let the browser do the rest (which would have been handled by a sensible designer who understood the implicit requirements).

Vineet Reynolds
+4  A: 

From wikipedia:

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%. - Donald Knuth

I think that sums it up. The question is knowing if you are in the 3% and what route to take. Personally I ignore most optimizations until I at least get my code working. Usually as a separate pass with a profiler so I can make sure I am optimizing things that actually matter. Often times code simply runs fast enough that anything you do will have little or no effect.

fuzzy-waffle
A: 

Picking appropriate data structures. I'm not even sure it counts as optimizing but it can affect the structure of your app (thus good to do early on) and greatly increase performance.

Nick
+1  A: 

You should avoid all optimizations if the only belief that the code you are optimizing will be slow. The only code you should optimize is when you know it is slow (preferably through a profiler).

If you write clear, easy to understand code then odds are it'll be fast enough, and if it isn't then when you go to speed it up it should be easier to do.

That being said, common sense should apply (!). Should you read a file over and over again or should you cache the results? Probably cache the results. So from a high level architecture point of view you should be thinking of optimization.

The "evil" part of optimization is the "sins" that are committed in the name of making something faster - those sins generally result in the code being very hard to understand. I am not 100% sure this is one of them.. but look at this question here, this may or may not be an example of optimization (could be the way the person thought to do it), but there are more obvious ways to solve the problem than what was chosen.

Another thing you can do, which I recently did do, is when you are writing the code and you need to decide how to do something write it both ways and run it through a profiler. Then pick the clearest way to code it unless there is a large difference in speed/memory (depending on what you are after). That way you are not guessing at what is "better" and you can document why you did it that way so that someone doesn't change it later.

The case that I was doing was using memory mapped files -vs- stream I/O... the memory mapped file was significantly faster than the other way, so I wasn't concerned if the code was harder to follow (it wasn't) because the speed up was significant.

Another case I had was deciding to "intern" String in Java or not. Doing so should save space, but at a cost of time. In my case the space savings wasn't huge, and the time was double, so I didn't do the interning. Documenting it lets someone else know not to bother interning it (or if they want to see if a newer version of Java makes it faster then they can try).

TofuBeer
A: 

Item #9 from Sutter and Alexandrescu's C++ Coding Standards: 101 Rules, Guidelines, and Best Practices (amazon) is "Don’t pessimize prematurely".

This means you should do things like

void foo(const std::wstring& str) {...}

from the beginning, rather than write

void foo(std::wstring str) {...}

only to change it later during some "optimization phase".

Dan
+1  A: 

In addition to being clear and straightforward, you also have to take a reasonable amount of time to implement the code correctly. If it takes you a day to get the code to work right, instead of the two hours it would have taken if you'd just written it, then you've quite possibly wasted time you could have spent on fixing the real performance problem (Knuth's 3%).

John Saunders