This is not the first time I’ve read something on that Knuth quote, and I’m sure it won’t be the last. One of my favorite anachronisms from Knuth’s article is:
Most programs are probably only run once; and I suppose in such cases we needn’t be too fussy about even the structure, much less the efficiency, as long as we are happy with the answers.
In the infosec field, we have some lists of principles to apply to make programs secure; CWE (Common Weakness Enumeration), OWASP top 10, etc. There’s also the SonarSource rules for writing and linting softwared. I wonder if there’s anything out there at a higher level of abstraction. Perhaps it’s time for a restatements of computer science to be developed (in the fashion of the Restatements of the Law). There are a few things that the Restatement of the Laws does well (particularly the volumes regarding contracts and torts):
Accurately states the precedent and trend of laws and how to interpret them.
Adds identity to each statement of the law allowing for easy and accurate citation.
Consolidates multiple primary sources into a single document
There are a few really good conceptual statements that can be gleaned from Knuth’s article. My restatements of those are:
Strive to write well-structured programs that are easy to understand and almost sure to work. Writing code for performance tends to have a negative impact on debugging and maintenance.
Only optimize critical parts of a program rather than the entire program. A minuscule number of lines has a disproportionate effect on the performance of a program.
Measure (profile) rather than applying intuition when searching for critical parts. Experience shows that most of the time guesses about where to optimize are wrong.
Focus on efficiency only after correctness and maintainability have been attained. Premature emphasis on efficiency introduces complexity and grief.
Introducing transformations of critical parts of a well-structured program allows us to more easily understand the performance-optimized code against the backdrop of the rest of the program.
Build and use tooling that tends to highlight inefficiencies as part of compilation.
Knuth suggests that we should build performance checks into our compilers, but we have the technology these days to do this earlier in the editing phase of our software development (using linters, and pattern matching refactoring tools).
The for loop is far more evil; it’s much harder to follow and thus impacts maintenance.
And it’s also slower. And it doesn’t scale as well.
Optimization in this case turns out to be not only only faster but also good. It’s the opposite of wasting programming time!
You may assert that this example is ridiculous!
I admit it helps that I don’t need to maintain Python’s dictionary implementation. But that’s the point. Today’s powerful computers can run dependencies like Python with ease. The context was definitely different in 1974.
So since this optimization is not evil, this optimization is not premature. It’s in fact never premature – even if this dictionary never grows beyond 10 items and the cost of the for loop version was negligible, it’s still better code.
I agree that the code is better, but I think that misses the point a little. It’s not better because it runs faster, it’s better because it clearly does what it needs to do.
In particular, the claim is sometimes made that code which has better performance will also be easier to understand. I find this to be nonsense. It might happen, on some occasion, that the two are coaligned, but that does not indicate any kind of general correlation.
In particular, both machines and humans are weakly inclined to brevity. But neither tendency is absolute, and the two are not necessarily inclined towards the same sort of brevity.
If there is one area where I think the “premature optimization” mantra is overhyped, it’s design decisions. That’s when “optimize later” means “making it work in an entirely different way”.
This is not the first time I’ve read something on that Knuth quote, and I’m sure it won’t be the last. One of my favorite anachronisms from Knuth’s article is:
In the infosec field, we have some lists of principles to apply to make programs secure; CWE (Common Weakness Enumeration), OWASP top 10, etc. There’s also the SonarSource rules for writing and linting softwared. I wonder if there’s anything out there at a higher level of abstraction. Perhaps it’s time for a restatements of computer science to be developed (in the fashion of the Restatements of the Law). There are a few things that the Restatement of the Laws does well (particularly the volumes regarding contracts and torts):
There are a few really good conceptual statements that can be gleaned from Knuth’s article. My restatements of those are:
Knuth suggests that we should build performance checks into our compilers, but we have the technology these days to do this earlier in the editing phase of our software development (using linters, and pattern matching refactoring tools).
Features, usability, security, and performance are all important, but they cannot all be equally urgent in the software development process. I tend to agree with Jonathan Blow that it’s generally better to stick to simple solutions and fix real performance bottlenecks than to preemptively assume that everything will be a bottleneck and end up building a Rube-Goldberg machine.
Regarding TFA,
I agree that the code is better, but I think that misses the point a little. It’s not better because it runs faster, it’s better because it clearly does what it needs to do.
In particular, the claim is sometimes made that code which has better performance will also be easier to understand. I find this to be nonsense. It might happen, on some occasion, that the two are coaligned, but that does not indicate any kind of general correlation.
In particular, both machines and humans are weakly inclined to brevity. But neither tendency is absolute, and the two are not necessarily inclined towards the same sort of brevity.
If there is one area where I think the “premature optimization” mantra is overhyped, it’s design decisions. That’s when “optimize later” means “making it work in an entirely different way”.