How do you know when you should worry about optimising code? Are there any rules of thumb for this?
Don't try and predict when to optimise.
Always implement a good design for flexibility and maintenance. Only afterwards should you start optimizing if you have performance issues. You will never predict correctly the code that will have issues. I have seem many programmers waste good hours creating very clever algorithms only to find that the real performance issues were somewhere else entirely.
You should always be looking for ways to improve your code. Sometimes when I finish writing a line I realize that it could be written more efficiently and start over.
Always keep your mind open when looking at your code for ways to improve it.
After you the brute force solution passes butter (ie passes the unit tests / or simply implements the specced functionality).
Optimization is easiest when the code is new and fresh in your mind, so do it then.
Optimization matters only when it matters. When it matters, it matters a lot, but until you know that it matters, don't waste a lot of time doing it. Even if you know it matters, you need to know where it matters. Without performance data, you won't know what to optimize, and you'll probably optimize the wrong thing.
Code Complete has a chapter on optimization. Optimization often throws "good design" out the door. For example, in extreme cases it is faster to have everything in the same function (depending on your compiler) because it doesn't have to load the stack and move to that function. In most applications today, the database interaction is the pain point.
As you are writing code it is important to be aware of the cost implications of each action that you write, i.e. the cost in terms of CPU cycles, database access, File IO etc. I am frequently amazed at the amount of code that is in production that is written by someone who has no concept of these concepts. Also watch third party libraries as they can hide all manner of inefficiencies.
As you test during development fix anything that is noticable slow.
During system testing anything that is too slow needs to be fixed. The best optimisation is usually to choose a better way of doing the same thing rather than saving cpu cycles.
I think someone clever said something to this effect....
Make it WORK
Make it RIGHT
Make it FAST <-- Optimise here
To quote Donald Knuth:
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."
In most cases, I would say get the code working exactly how you want it to function, then use that as a sanity check against your optimisations.
It depends very much on your performance requirements, both present and going forward into the future. If you design your application well, by selecting efficient algorithms and data structures before you start coding, you are much less likely to require optimization later on.
My experience has been that the cost of doing almost anything at requirements and design stages is much less than at coding and testing stages. If it does not perform at testing stage, fixing through optimization may be necessary and may provide a solution. Personally, I think of this as a design shortcoming should should have been predicted prior to testing.
So my answer; If you need the performance, start optimizing before you start coding.
You should start optimizing your code when your application is too slow. If you lose days on small optimisation that does not mathers, it's not really productive. Often, you will need to change only a function or a classes in your code to gain several seconds of load. But optimisation of some miliseconds is not that helpful.
But it always depends on the project. If you do an application that needs to be as fast as possible, you will want to start optimizing in the beggining. If you work on a project like an ERP, the optimisation will be less present because there's not a big difference between a .5 second load and a 1 second load.
A very quick, off-the-cuff answer:
- Optimise the architecture from the start
- Optimise the design if you think it's likely to be a bottleneck
- Optimise the implementation when you've proved it's a bottleneck
Other points:
- Make sure you have a good idea of what you're trying to optimise for (and what's acceptable)
- Don't optimise before measuring - you won't know whether it's worked or not
- Measure as soon and as often as possible, to get early warning of possible difficulties
As soon as you've measured it and found a bottleneck. If your code is performing fine, then don't bother optimizing. That's time that could be spent writing new code or debugging something that doesn't work.
I find it amusing that so many people jump straight to speed of execution when the term 'optimisation' is in a question. The original question did not specify what required optimising only when to start optimising. The answer is simple:
Optimise when, and only when, a parameter is outside of its specified range.
The parameters and their acceptable values should be defined in the specification, e.g.:
- There must be visual feedback to user within 10ms of user input
- The application must fit into 4K of ROM
- The display refresh rate must be fixed at 30Hz
- There must not be any pause/loading screen when loading game data
- Application data must fit onto a CD ROM
and so on. It may not be possible to meet all the requirements.
Skizz
I would say that optimizations are only required if you have performance issues that cannot be corrected by hardware/platform upgrades within a reasonable cost.
If better performance is still required, a performance analysis in an enviroment resembling the deployed enviroment can give answers to where the bottleneck might be.
When optimizing I always try to avoid making the code more difficult to maintain. Adding complexity can easily become a maintanance nightmare.
Simple framework optimizations like using string.IsNullOrEmpty(string) in stead of (myString != null && myString.Length > 0) are simply best-practice coding conventions that is part of everyday work.
As soon as you open up the editor/IDE and select to open a new file/project/solution.
In fact, before then. Although possibly just after thinking about how to make things extendible and re-using old tools.
Optimize your algorithms and leave the rest for later profiling if you still need it. For example, I worked with a guy who'd use "select * from table" and then filter the results in code. No amount of micro-optimization elsewhere would have fixed this fundamentally damaged design.
Honestly, there have been maybe 3 or 4 times in my entire career where low-level optimization was necessary. In every other case, my time was much better spent making sure my approach was sane and efficient.
I would say it takes two steps.
Keep the design as simple as possible. In particular, have as few classes as possible, and don't let "performance" be the reason for any complexity in the data structure.
Only when a performance problem appears, do performance analysis. My favorite method is "deep sampling" http://en.wikipedia.org/wiki/Performance_analysis#Simple_manual_technique . It's simple, quick, doesn't require any tools, and is very effective.
That way, you fix performance problems you actually have, without getting in the bind of creating performance problems by having complicated data structure whose purpose was to solve performance problems you thought you might have.
consider this: the time you spend with optimizations is wasted on two levels:
- while you optimize, you don't add features (IOW make progress) and at the same time you make the code less maintainable, because most of the time optimization means trading program simplicity/clarity for runtime speed. meanwhile your competition is busy making progress.
- with every second you spend on optimizing your program the hardware is getting cheaper and cheaper.
we never optimize before a performance issue actually pops up. never. but when it does, then we look at the profiler and take the lowest hanging fruits by optimizing some of the easiest hot-spots.
but you need a language that helps this way of development. we work in lisp, where you have a chance to factor out most of your abstractions, which later makes it very easy to shape the code and/or to optimize the framework behind the scene.
Only when you need to. (Or if your bored and have nothing else to do...)
Always remember the 80/20 rule, and always weigh developer time/cost against hardware upgrade costs. Don't optimize until you have a problem. This presupposes good design and best practices, of course.
The rules for optimizations at source level are:
- Don't do it
- (For experts only) Don't do it yet
If you really think that you need to optimize, you first need to identify the real bottleneck of the system (not to be confused with what you think is the bottleneck). Use a good profiler, it will tell you where most of the time is spent.