Eu sempre vi essa citação usada para justificar código ou código obviamente inválido que, embora seu desempenho não tenha sido medido, provavelmente poderia ser feito com mais rapidez, sem aumentar o tamanho do código ou comprometer sua legibilidade.
Em geral, acho que as micro-otimizações iniciais podem ser uma má ideia. No entanto, as otimizações de macro (coisas como escolher um algoritmo O (log N) em vez de O (N ^ 2)) geralmente valem a pena e devem ser feitas cedo, pois pode ser um desperdício escrever um algoritmo O (N ^ 2) e em seguida, jogue-o fora completamente em favor de uma abordagem O (log N).
Note que as palavras podem ser : se o algoritmo O (N ^ 2) é simples e fácil de escrever, você pode jogá-lo fora mais tarde sem muita culpa se ele for muito lento. Mas se os dois algoritmos são similarmente complexos, ou se a carga de trabalho esperada é tão grande que você já sabe que precisará da mais rápida, a otimização antecipada é uma decisão de engenharia que reduzirá sua carga de trabalho a longo prazo.
Assim, em geral, acho que a abordagem correta é descobrir quais são suas opções antes de começar a escrever código e escolher conscientemente o melhor algoritmo para sua situação. Mais importante ainda, a frase "otimização prematura é a raiz de todo o mal" não é desculpa para a ignorância. Desenvolvedores de carreira devem ter uma ideia geral de quanto custo de operações comuns; eles devem saber, por exemplo,
- que as sequências custam mais do que os números
- que os idiomas dinâmicos são muito mais lentos que os idiomas com tipagem estática
- as vantagens das listas vetoriais / vetoriais sobre listas vinculadas e vice-versa
- quando usar um hashtable, quando usar um mapa ordenado e quando usar um heap
- que (se funcionarem com dispositivos móveis) "double" e "int" têm desempenho semelhante em desktops (FP pode até ser mais rápido), mas "double" pode ser cem vezes mais lento em dispositivos móveis low-end sem FPUs;
- que a transferência de dados pela Internet é mais lenta do que o HDD, os HDDs são muito mais lentos que a RAM, a RAM é muito mais lenta que a L1 e registra, e as operações da Internet podem bloquear indefinidamente (e falhar a qualquer momento).
E os desenvolvedores devem estar familiarizados com uma caixa de ferramentas de estruturas de dados e algoritmos para que possam usar facilmente as ferramentas certas para o trabalho.
Ter muito conhecimento e uma caixa de ferramentas pessoal permite que você otimize quase sem esforço. Colocar um grande esforço em uma otimização que pode ser desnecessária é mal (e eu admito cair nessa armadilha mais de uma vez). Mas quando a otimização é tão fácil quanto escolher um set / hashtable ao invés de um array, ou armazenar uma lista de números em double [] ao invés de string [], então por que não? Eu posso estar discordando de Knuth aqui, não tenho certeza, mas acho que ele estava falando sobre otimização de baixo nível enquanto eu estou falando sobre otimização de alto nível.
Lembre-se de que essa citação é originalmente de 1974. Em 1974, os computadores eram lentos e o poder de computação era caro, o que dava a alguns desenvolvedores uma tendência de super otimização, linha por linha. Eu acho que é isso que Knuth estava empurrando contra. Ele não estava dizendo "não se preocupe com a performance", porque em 1974 isso seria apenas uma conversa maluca. Knuth estava explicando como otimizar; Em suma, deve-se focar apenas nos gargalos e, antes de fazer isso, você deve realizar medições para descobrir os gargalos.
Observe que você não pode encontrar os gargalos até ter escrito um programa para medir, o que significa que algumas decisões de desempenho devem ser feitas antes que haja algo para medir. Às vezes, essas decisões são difíceis de mudar se você as errar. Por esse motivo, é bom ter uma ideia geral do que as coisas custam para que você possa tomar decisões razoáveis quando não houver dados concretos disponíveis.
Quão cedo para otimizar e quanto se preocupar com o desempenho dependem do trabalho. Ao escrever scripts que você só executará algumas vezes, preocupar-se com o desempenho é geralmente um completo desperdício de tempo. Mas se você trabalha para a Microsoft ou Oracle e está trabalhando em uma biblioteca que milhares de outros desenvolvedores usarão em milhares de maneiras diferentes, talvez seja melhor otimizar o trabalho, então que você pode cobrir todos os casos de uso diversificados de forma eficiente. Mesmo assim, a necessidade de desempenho deve sempre ser equilibrada com a necessidade de legibilidade, facilidade de manutenção, elegância, extensibilidade e assim por diante.