A otimização prematura é realmente a raiz de todo mal?

215

Um colega meu hoje comprometeu uma classe chamada ThreadLocalFormat, que basicamente moveu instâncias das classes Java Format para um local de encadeamento, pois elas não são seguras e são "relativamente caras" para criar. Eu escrevi um teste rápido e calculei que eu poderia criar 200.000 instâncias por segundo, perguntei a ele se ele estava criando tantas, às quais ele respondeu "longe de tantas". Ele é um ótimo programador e todos os membros da equipe são altamente qualificados, por isso não temos problemas em entender o código resultante, mas foi claramente um caso de otimização onde não há necessidade real. Ele apoiou o código a meu pedido. O que você acha? É um caso de "otimização prematura" e quão ruim é realmente?

Craig Day
fonte
23
Eu acho que você precisa distinguir entre otimização prematura e otimização desnecessária. Prematuro para mim sugere 'muito cedo no ciclo de vida', onde o desnecessário sugere 'não agrega valor significativo'. OMI, requisito para otimização tardia implica em design de má qualidade.
110
Sim, mas o mal é um polinômio e tem muitas raízes, algumas delas são complexas.
Dan_waterworth 29/05
7
Você deve considerar que Knuth escreveu isso em 1974. Nos anos 70, não era tão fácil escrever programas lentos como hoje em dia. Ele escreveu com Pascal em mente e não com Java ou PHP.
ceving 02/10/2013
4
Não. A raiz de todo mal é a ganância.
Tulains Córdova
12
Nos anos 70, era tão fácil quanto hoje escrever programas lentos. Se você escolher o algoritmo errado ou a estrutura de dados incorreta, então o BAM! Mau desempenho em todo o lugar. Alguém poderia argumentar o contrário. Hoje, existem muito mais ferramentas e deve ser indesculpável que um programador ainda escreva software que sofre na operação de salvaguarda mais básica. O paralelismo se tornou quase uma mercadoria e ainda sofremos. O desempenho lento não pode ser responsabilizado pelo idioma, ferramenta, CPU ou memória. É um equilíbrio delicado de tantas coisas, e é por isso que é quase impossível otimizar cedo.
Alex

Respostas:

322

É importante ter em mente a citação completa:

Devemos esquecer as pequenas eficiências, digamos, 97% das vezes: a otimização prematura é a raiz de todo mal. No entanto, não devemos desperdiçar nossas oportunidades nesses 3% críticos.

O que isso significa é que, na ausência de problemas de desempenho medidos, você não deve otimizar porque acha que obterá um ganho de desempenho. Existem otimizações óbvias (como não fazer concatenação de strings dentro de um loop apertado), mas qualquer coisa que não seja uma otimização trivialmente clara deve ser evitada até que possa ser medida.

Os maiores problemas da "otimização prematura" são que ela pode apresentar bugs inesperados e pode ser uma grande perda de tempo.

Scott Dorman
fonte
7
Sendo de Donald Knuth, eu não ficaria surpreso se ele tivesse alguma evidência para apoiá-lo. BTW, Src: Programação Estruturada com ir para Declarações, ACM Journal Computing Surveys, Vol. 6, No. 4, Dez. 1974. p.268. citeseerx.ist.psu.edu/viewdoc/...
mctylr
28
... Um bom programador não será levado à complacência por esse raciocínio; será prudente olhar atentamente para o código crítico; mas só depois que o código foi identificado (resto da citação mais completa)
mctylr
21
Hoje, eu tinha um usuário com 20k de repetição e me disse que usar uma otimização prematura em HashSetvez de uma Listera prematuro. O caso de uso em questão era uma coleção inicializada estaticamente cujo único objetivo era servir como uma tabela de consulta. Eu não acho que estou errado em dizer que há uma distinção na seleção da ferramenta certa para o trabalho versus a otimização prematura. Acho que seu post confirma esta filosofia: There are obvious optimizations...anything that isn't trivially clear optimization should be avoided until it can be measured.A otimização de um HashSet foi completamente medida e documentada.
esmagar
9
@crush: yes: Settambém é mais semanticamente correto e informativo do que List, portanto, há mais do que o aspecto de otimização.
precisa saber é o seguinte
7
Gostaria de acrescentar que a otimização prematura não deve ser confundida com o design de toda a arquitetura de aplicativos para executar rapidamente em geral, escalar e ser facilmente otimizável.
precisa saber é o seguinte
111

As micro otimizações prematuras são a raiz de todo mal, porque as micro otimizações deixam de fora o contexto. Eles quase nunca se comportam como são esperados.

Quais são algumas boas otimizações iniciais na ordem de importância:

  • Otimizações arquiteturais (estrutura do aplicativo, a maneira como é componente e em camadas)
  • Otimizações de fluxo de dados (dentro e fora do aplicativo)

Algumas otimizações do ciclo de desenvolvimento intermediário:

  • Estruturas de dados, introduza novas estruturas de dados com melhor desempenho ou menor sobrecarga, se necessário
  • Algoritmos (agora é uma boa hora para começar a decidir entre quicksort3 e heapsort ;-))

Algumas otimizações do ciclo de desenvolvimento final

  • Localizando hotpots de código (loops apertados, que devem ser otimizados)
  • Otimizações baseadas em perfil de partes computacionais do código
  • As micro otimizações podem ser feitas agora, como são feitas no contexto do aplicativo, e seu impacto pode ser medido corretamente.

Nem todas as otimizações iniciais são ruins, as micro otimizações são ruins se forem feitas no momento errado no ciclo de vida do desenvolvimento , pois podem afetar negativamente a arquitetura, podem afetar negativamente a produtividade inicial, podem ter um desempenho irrelevante ou até mesmo um efeito prejudicial no final desenvolvimento devido a diferentes condições ambientais.

Se o desempenho é motivo de preocupação (e sempre deveria ser), pense sempre grande . O desempenho é uma imagem maior e não sobre coisas como: devo usar int ou long ? Vá para Top Down ao trabalhar com desempenho em vez de Bottom Up .

Pop Catalin
fonte
"Otimização: seu pior inimigo", de Joseph M. Iniciante: flounder.com/optimization.htm
Ron Ruble
53

a otimização sem a primeira medição é quase sempre prematura.

Acredito que seja verdade neste caso, e também no caso geral.

Jeff Atwood
fonte
Aqui aqui! A otimização não considerada torna o código insustentável e geralmente é a causa de problemas de desempenho. por exemplo, você multiencadeia um programa porque imagina que isso pode ajudar no desempenho, mas a solução real teria sido vários processos que agora são muito complexos para implementar.
James Anderson
a menos que esteja documentado.
Nawfal #
Sim. Concordo plenamente. Primeiro tem que ser medido. Não há como você saber onde estão os gargalos até testar algo de ponta a ponta e medir cada uma das etapas.
Oliver Watkins
As medições podem mentir. Vi especialistas experientes passarem semanas lendo traços e executando perfis para atingir uma parede onde eles pensavam que não havia mais nada a ganhar. Depois, li todo o código e, em poucas horas, fiz algumas alterações holísticas para obter uma melhoria de 10x. Os perfis não mostraram caminhos ativos porque o código inteiro foi mal projetado. Eu também vi criadores de perfil reivindicar caminhos quentes onde não deveria haver nenhum. Uma pessoa que "mede" teria otimizado o atalho, mas deveria ter percebido que o atalho era um sintoma de outro código ruim.
Bengie
42

A otimização é "má" se causar:

  • código menos claro
  • significativamente mais código
  • código menos seguro
  • tempo perdido do programador

No seu caso, parece que um pouco de tempo do programador já foi gasto, o código não era muito complexo (uma suposição do seu comentário de que todos da equipe seriam capazes de entender) e o código é um pouco mais à prova de futuro (sendo thread seguro agora, se eu entendi sua descrição). Parece apenas um pouco mal. :)

John Mulder
fonte
4
Somente se o custo, nos termos dos seus pontos principais, for maior que o valor amortizado entregue. Frequentemente, a complexidade introduz valor e, nesses casos, é possível encapsulá-lo para que ele passe nos seus critérios. Também é reutilizado e continua a fornecer mais valor.
11
Esses dois primeiros pontos são os principais para mim, com o quarto ponto sendo uma consequência negativa da otimização prematura. Em particular, é uma bandeira vermelha sempre que vejo alguém reimplementando recursos de uma biblioteca padrão. Assim, vi uma vez alguém implementar rotinas personalizadas para manipulação de strings porque estava preocupado com o fato de os comandos internos serem muito lentos.
Jhocking 29/05
8
Tornar o thread de código seguro não é otimização.
mattnz
38

Estou surpreso que essa pergunta tenha 5 anos e, no entanto, ninguém postou mais do que Knuth tinha a dizer do que algumas frases. Os parágrafos que cercam a famosa citação explicam muito bem. O artigo que está sendo citado é chamado de " Programação Estruturada com vá para Declarações " e, embora tenha quase 40 anos, trata de uma controvérsia e um movimento de software que não existe mais, além de exemplos em linguagens de programação que muitas pessoas nunca ouvido falar, uma quantidade surpreendentemente grande do que dizia ainda se aplica.

Aqui está uma citação maior (da página 8 do pdf, página 268 no original):

A melhoria na velocidade do Exemplo 2 para o Exemplo 2a é de apenas 12%, e muitas pessoas considerariam isso insignificante. A sabedoria convencional compartilhada por muitos dos engenheiros de software de hoje exige ignorar a eficiência no pequeno; mas acredito que isso é simplesmente uma reação exagerada aos abusos que eles veem sendo praticados por programadores tolos, que não conseguem depurar ou manter seus programas "otimizados". Nas disciplinas de engenharia estabelecidas, uma melhoria de 12%, facilmente obtida, nunca é considerada marginal; e acredito que o mesmo ponto de vista deve prevalecer na engenharia de software. É claro que eu não me incomodaria em fazer essas otimizações em um único trabalho, mas quando se trata de preparar programas de qualidade, não quero me restringir a ferramentas que me negam tais eficiências.

Não há dúvida de que o graal da eficiência leva ao abuso. Os programadores perdem muito tempo pensando ou se preocupando com a velocidade das partes não críticas de seus programas, e essas tentativas de eficiência têm um forte impacto negativo quando a depuração e a manutenção são consideradas. Nós deve esquecer-se sobre pequenas eficiências, digamos cerca de 97% do tempo: otimização prematura é a raiz de todo o mal.

No entanto, não devemos desperdiçar nossas oportunidades nesses 3% críticos. Um bom programador não será levado à complacência por esse raciocínio; será prudente olhar atentamente para o código crítico; mas somente após a identificação desse código. Muitas vezes, é um erro fazer julgamentos a priori sobre quais partes de um programa são realmente críticas, pois a experiência universal dos programadores que usam ferramentas de medição é que suas suposições intuitivas falham.

Outra boa parte da página anterior:

É claro que meu próprio estilo de programação mudou durante a última década, de acordo com as tendências dos tempos (por exemplo, não sou mais tão complicado e utilizo menos itens), mas a principal mudança no meu estilo deve-se a a esse fenômeno do loop interno. Agora olho com um olhar extremamente ictérico para todas as operações em um loop interno crítico, buscando modificar meu programa e estrutura de dados (como na mudança do Exemplo 1 para o Exemplo 2) para que algumas das operações possam ser eliminadas. As razões para essa abordagem são as seguintes: a) não demora muito, pois o loop interno é curto; b) o pagamento é real; ec) posso me permitir ser menos eficiente nas outras partes dos meus programas, que são, portanto, mais legíveis e mais fáceis de escrever e depurar.

Michael Shaw
fonte
20

Muitas vezes vi essa citação usada para justificar código ou código obviamente ruim que, embora seu desempenho não tenha sido medido, provavelmente poderia ser feito mais rapidamente com bastante facilidade, 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 macro (coisas como escolher um algoritmo O (log N) em vez de O (N ^ 2)) costumam valer a pena e devem ser feitas cedo, pois pode ser um desperdício escrever um algoritmo O (N ^ 2) e depois jogue fora completamente em favor de uma abordagem O (log N).

Observe que as palavras podem ser : se o algoritmo O (N ^ 2) for simples e fácil de escrever, você poderá jogá-lo fora mais tarde sem muita culpa, se parecer muito lento. Mas se os dois algoritmos forem igualmente complexos ou se a carga de trabalho esperada for tão grande que você já sabe que precisará da mais rápida, a otimização antecipada é uma boa decisão de engenharia que reduzirá sua carga de trabalho total a longo prazo.

Portanto, 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 mal" não é desculpa para ignorância. Os desenvolvedores de carreira devem ter uma idéia geral de quanto custa operações comuns; eles deveriam saber, por exemplo,

  • que strings custam mais que números
  • que linguagens dinâmicas são muito mais lentas do que linguagens estaticamente tipadas
  • as vantagens das listas de vetores / matrizes sobre listas vinculadas e vice-versa
  • quando usar uma hashtable, quando usar um mapa classificado e quando usar um heap
  • que (se eles funcionam com dispositivos móveis) "double" e "int" têm desempenho semelhante em desktops (o FP pode até ser mais rápido), mas "double" pode ser cem vezes mais lento em dispositivos móveis de última geração sem FPUs;
  • que a transferência de dados pela Internet é mais lenta que o acesso ao HDD, os HDDs são muito mais lentos que a RAM, a RAM é muito mais lenta que o cache e os registros L1, e as operações na 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 otimizar quase sem esforço. Colocar muito esforço em uma otimização que pode ser desnecessária é ruim (e admito que caí nessa armadilha mais de uma vez). Mas quando a otimização é tão fácil quanto escolher um conjunto / hashtable em vez de uma matriz ou armazenar uma lista de números em duplo [] em vez de string [], 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, essa citação é originalmente de 1974. Em 1974, os computadores eram lentos e o poder de computação era caro, o que deu a alguns desenvolvedores a tendência de otimizar demais, linha por linha. Eu acho que é isso que Knuth estava pressionando. Ele não estava dizendo "não se preocupe com o desempenho", porque em 1974 isso seria apenas uma conversa maluca. Knuth estava explicando como otimizar; em resumo, deve-se concentrar apenas nos gargalos e, antes disso, você deve realizar medições para encontrar os gargalos.

Observe que você não pode encontrar os gargalos até escrever um programa para medir, o que significa que algumas decisões de desempenho devem ser tomadas antes que exista algo para medir. Às vezes, essas decisões são difíceis de serem alteradas se você errar. Por esse motivo, é bom ter uma idéia geral de quanto custa as coisas, para que você possa tomar decisões razoáveis ​​quando não houver dados disponíveis.

A rapidez com que otimizar e o quanto se preocupar com o desempenho dependem do trabalho. Ao escrever scripts que você executará apenas algumas vezes, preocupar-se com o desempenho geralmente é uma completa perda de tempo. Mas se você trabalha para a Microsoft ou Oracle e está trabalhando em uma biblioteca que milhares de outros desenvolvedores usarão de milhares de maneiras diferentes, pode valer a pena otimizar tudo, para que você possa cobrir todas as diversas casos de uso com eficiência. Mesmo assim, a necessidade de desempenho sempre deve ser equilibrada com a necessidade de legibilidade, capacidade de manutenção, elegância, extensibilidade e assim por diante.

Qwertie
fonte
2
Amém. Nos dias de hoje, a otimização prematura é muito liberal para pessoas que tentam justificar o uso da ferramenta errada para o trabalho. Se você conhece a ferramenta certa com antecedência, não há desculpa para não usá-la.
esmaga
13

Pessoalmente, conforme abordado em um tópico anterior , não acredito que a otimização inicial seja ruim em situações nas quais você sabe que encontrará problemas de desempenho. Por exemplo, escrevo softwares de modelagem e análise de superfícies, onde lido regularmente com dezenas de milhões de entidades. Planejar o desempenho ideal no estágio de design é muito superior à otimização tardia de um design fraco.

Outra coisa a considerar é como o aplicativo será escalado no futuro. Se você considerar que seu código terá uma vida útil longa, otimizar o desempenho no estágio de design também é uma boa idéia.

Na minha experiência, a otimização tardia fornece poucas recompensas a um preço alto. A otimização no estágio de projeto, através da seleção e ajuste de algoritmos, é muito melhor. Dependendo de um criador de perfil para entender como seu código funciona não é uma ótima maneira de obter código de alto desempenho, você deve saber isso com antecedência.

Shane MacLaughlin
fonte
Isso certamente está correto. Eu acho que a otimização prematura ocorre quando o código se torna mais complexo / difícil de entender para benefícios pouco claros, de uma maneira que tem apenas impacto local (o design tem impacto global).
Paul de Vrieze
2
É tudo sobre definições. Tomo a otimização como projetar e escrever código para executar da maneira ideal. A maioria aqui parece tratá-lo como hackear o código depois que eles descobrem que não é rápido ou eficiente o suficiente. Passo muito tempo otimizando, geralmente durante o design.
3
Otimize o design no início, Otimize o código no final.
BCS
Você está certo no seu caso, no entanto, para a maioria dos programadores, eles acreditam que terão problemas de desempenho, mas na realidade nunca o farão. Muitos se preocupam com o desempenho ao lidar com 1000 entidades, quando um teste básico nos dados mostra que o desempenho é bom até atingir 1000000 entidades.
Toby Allen
11
"Planejar o desempenho ideal no estágio de design é muito superior à otimização tardia de um design fraco" e "a otimização tardia fornece recompensas escassas a um preço alto" muito bem colocado! Provavelmente não é verdade para 97% de todos os sistemas produzidos, mas é para muitos - desconcertantemente muitos - sistemas.
Olof Forshell
10

De fato, aprendi que a não otimização prematura é mais frequentemente a raiz de todo mal.

Quando as pessoas escrevem software, ele inicialmente apresenta problemas, como instabilidade, recursos limitados, usabilidade e desempenho ruins. Tudo isso geralmente é corrigido quando o software amadurece.

Tudo isso, exceto desempenho. Ninguém parece se importar com o desempenho. O motivo é simples: se um software falha, alguém corrige o erro e é isso, se um recurso está faltando, alguém o implementa e pronto; se o software tem um desempenho ruim, em muitos casos isso não ocorre por falta de microoptimização, mas devido ao mau design e ninguém vai tocar no design do software. SEMPRE.

Olhe para Bochs. É lento como o inferno. Será que vai ficar mais rápido? Talvez, mas apenas na faixa de alguns por cento. Ele nunca terá desempenho comparável ao software de virtualização como VMWare ou VBox ou mesmo QEMU. Porque é lento por design!

Se o problema de um software é lento, porque é MUITO lento e isso só pode ser corrigido melhorando o desempenho de várias pessoas. + 10% simplesmente não fazem um software lento rapidamente. E você normalmente não receberá mais de 10% pelas otimizações posteriores.

Portanto, se o desempenho for QUALQUER importante para o seu software, você deve levar isso em consideração desde o início, ao projetá-lo, em vez de pensar "ah, sim, é lento, mas podemos melhorar isso mais tarde". Porque você não pode!

Sei que isso realmente não se encaixa no seu caso específico, mas responde à pergunta geral "A otimização prematura é realmente a raiz de todo mal?" - com um NO claro.

Toda otimização, como qualquer recurso, etc. deve ser projetada com cuidado e implementada com cuidado. E isso inclui uma avaliação adequada de custo e benefício. Não otimize um algoritmo para salvar alguns ciclos aqui e ali, quando não criar um ganho de desempenho mensurável.

Apenas como exemplo: você pode melhorar o desempenho de uma função inserindo-a, possivelmente economizando alguns ciclos, mas ao mesmo tempo você provavelmente aumenta o tamanho do seu executável, aumentando as chances de falhas no TLB e no cache que custam milhares de ciclos ou até operações de paginação, que prejudicam totalmente o desempenho. Se você não entender essas coisas, sua "otimização" pode resultar ruim.

A otimização estúpida é mais maligna que a otimização "prematura", mas ambas ainda são melhores que a não otimização prematura.

mosquito
fonte
6

Existem dois problemas com o pedido de compra: primeiro, o tempo de desenvolvimento sendo usado para trabalhos não essenciais, que podem ser usados ​​para escrever mais recursos ou corrigir mais erros e, em segundo lugar, a falsa sensação de segurança de que o código está sendo executado com eficiência. O PO geralmente envolve a otimização do código que não será o gargalo da garrafa, sem perceber o código que será. O bit "prematuro" significa que a otimização é feita antes que um problema seja identificado usando medidas adequadas.

Então, basicamente, sim, isso soa como otimização prematura, mas eu não recuaria necessariamente, a menos que introduzisse bugs - afinal, ela foi otimizada agora (!)

harriyott
fonte
Você quer dizer "escrevendo mais testes" em vez de "escrever mais recursos", certo? :)
Greg Hewgill
11
mais recursos implica mais testes :)
workmad3
Sim! Isso é exatamente o que eu quis dizer ...
harriyott
2
O código apresenta mais complexidade e provavelmente não será usado universalmente. Fazer o backup (e coisas semelhantes) mantém o código limpo.
Paul de Vrieze
3

Acredito que é o que Mike Cohn chama de 'banalização' do código - ou seja, gastar tempo com coisas que poderiam ser boas, mas não necessárias.

Ele aconselhou contra isso.

O PS 'gold-plating' pode ser uma espécie de funcionalidade específica. Quando você olha para o código, ele assume a forma de otimização desnecessária, classes 'à prova de futuro' etc.

Ilya Kochetov
fonte
2
Eu acho que "revestimento de ouro" é diferente de otimizações. As otimizações geralmente tratam de obter o máximo desempenho, enquanto "revestimento a ouro" é sobre a adição de "sinos e assobios" (toda a funcionalidade extra) que não são essenciais para o produto, mas parecem legais.
21926 Scott Dorman
3

Como não há problema em entender o código, esse caso pode ser considerado uma exceção.

Mas, em geral, a otimização leva a um código menos legível e menos compreensível e deve ser aplicado somente quando necessário. Um exemplo simples - se você souber que precisa classificar apenas alguns elementos - use o BubbleSort. Mas se você suspeitar que os elementos possam aumentar e não souber quanto, otimizar com o QuickSort (por exemplo) não é ruim, mas obrigatório. E isso deve ser considerado durante o design do programa.

m_pGladiator
fonte
11
Não concordo. Eu diria que nunca use um tipo de bolha. O Quicksort tornou-se um padrão defacto e é bem compreendido e é tão fácil de implementar quanto uma espécie de bolha em todos os cenários. O menor denominador comum não é mais tão baixo;) #
11
Para um número realmente pequeno de itens, a recursão necessária para o quicksort pode torná-lo mais lento do que um decortador decente ... para não mencionar que um decortador é mais rápido no pior cenário do quicksort (ou seja, separar rapidamente uma lista classificada)
workmad3
sim, mas isso é apenas um exemplo de como selecionar algoritmos para diferentes necessidades;)
É verdade, mas eu teria quicksort como minha classificação padrão. Se eu pensasse que o bubblesort melhoraria o desempenho, isso seria uma otimização, e não o contrário. Eu escolho o quicksort como padrão porque é bem compreendido e geralmente melhor.
2
Minha idéia de uma classificação padrão é o que a biblioteca me fornece (qsort (), .sort (), (sort ...), o que for).
David Thornley
3

Descobri que o problema com a otimização prematura ocorre principalmente quando reescrever o código existente para ser mais rápido. Eu posso ver como poderia ser um problema escrever alguma otimização complicada em primeiro lugar, mas principalmente vejo otimização prematura elevando sua cabeça feia ao consertar o que não é (conhecido por ser) quebrado.

E o pior exemplo disso é sempre que vejo alguém reimplementando recursos de uma biblioteca padrão. Essa é uma grande bandeira vermelha. Assim, vi uma vez alguém implementar rotinas personalizadas para manipulação de strings porque estava preocupado com o fato de os comandos internos serem muito lentos.

Isso resulta em código que é mais difícil de entender (ruim) e gasta muito tempo no trabalho que provavelmente não é útil (ruim).

jhocking
fonte
3

De uma perspectiva diferente, é minha experiência que a maioria dos programadores / desenvolvedores não planeja ter sucesso e o "protótipo" quase sempre se torna a Versão 1.0. Eu tenho experiência em primeira mão com 4 produtos originais separados, nos quais o front-end elegante, sexy e altamente funcional (basicamente a interface do usuário) resultou em ampla adoção e entusiasmo do usuário. Em cada um desses produtos, os problemas de desempenho começaram a surgir em períodos relativamente curtos (1 a 2 anos), especialmente quando clientes maiores e mais exigentes começaram a adotar o produto. Muito em breve o desempenho dominou a lista de problemas, embora o desenvolvimento de novos recursos dominasse a lista de prioridades do gerenciamento. Os clientes ficaram cada vez mais frustrados, pois cada versão adicionava novos recursos que pareciam ótimos, mas eram quase inacessíveis devido a problemas de desempenho.

Portanto, falhas fundamentais de projeto e implementação, que eram de pouca ou nenhuma preocupação no "tipo protótipo", se tornaram grandes obstáculos para o sucesso a longo prazo dos produtos (e das empresas).

A demonstração do cliente pode ter uma ótima aparência e desempenho no seu laptop com XML DOMs, SQL Express e muitos dados em cache do lado do cliente. O sistema de produção provavelmente travará uma queimadura se você tiver êxito.

Em 1976, ainda estávamos debatendo as maneiras ideais de calcular uma raiz quadrada ou classificar uma grande variedade, e o ditado de Don Knuth foi direcionado ao erro de focar em otimizar esse tipo de rotina de baixo nível no início do processo de design, em vez de focar na solução do problema. e, em seguida, otimizando regiões localizadas de código.

Quando alguém repete o ditado como uma desculpa para não escrever código eficiente (C ++, VB, T-SQL ou outro), ou para não projetar adequadamente o repositório de dados ou por não considerar a arquitetura de trabalho líquida, então na IMO eles estão apenas demonstrando uma compreensão muito superficial da natureza real de nosso trabalho. Raio

Raio
fonte
11
Haha, ou quando a demo com três usuários se torna a versão 1.0 com mil.
amigos estão dizendo sobre olof forshell
1

Suponho que depende de como você define "prematuro". Tornar a funcionalidade de baixo nível rápida quando você está escrevendo não é inerentemente ruim. Eu acho que é um mal-entendido da citação. Às vezes acho que essa citação poderia ter mais qualificação. Eu ecoaria os comentários de m_pGladiator sobre legibilidade.

Dominic Rodger
fonte
1

A resposta é: depende. Argumentarei que a eficiência é importante para certos tipos de trabalho, como consultas complexas a bancos de dados. Em muitos outros casos, o computador gasta a maior parte do tempo aguardando a entrada do usuário, portanto, otimizar a maior parte do código é, na melhor das hipóteses, um desperdício de esforço e, na pior das hipóteses, contraproducente.

Em alguns casos, é possível projetar para obter eficiência ou desempenho (percebido ou real) - selecionando um algoritmo apropriado ou projetando uma interface com o usuário para que certas operações caras ocorram em segundo plano, por exemplo. Em muitos casos, a criação de perfil ou outras operações para determinar pontos de acesso oferecem um benefício 10/90.

Um exemplo disso que posso descrever é o modelo de dados que fiz para um sistema de gerenciamento de processos judiciais que continha cerca de 560 tabelas. Tudo começou normalizado ('lindamente normalizado' como o consultor de uma determinada empresa grande-5 colocou) e tivemos apenas que colocar quatro itens de dados desnormalizados:

  • Uma visão materializada para suportar uma tela de pesquisa

  • Uma tabela mantida por acionador para oferecer suporte a outra tela de pesquisa que não pôde ser feita com uma visualização materializada.

  • Uma tabela de relatório desnormalizada (isso só existia porque precisávamos receber alguns relatórios de taxa de transferência quando um projeto de data warehouse era enlatado)

  • Uma tabela mantida por acionador para uma interface que precisava procurar o número mais recente de eventos díspares mais recentes no sistema.

Esse era (na época) o maior projeto J2EE da Australásia - bem mais de 100 anos de tempo de desenvolvedor - e tinha 4 itens desnormalizados no esquema do banco de dados, um dos quais realmente não pertencia a ele.

ConcernedOfTunbridgeWells
fonte
1

A otimização prematura não é a raiz de TODOS os males, com certeza. No entanto, existem desvantagens:

  • você investe mais tempo durante o desenvolvimento
  • você investe mais tempo testando
  • você investe mais tempo corrigindo bugs que de outra forma não estariam lá

Em vez de otimização prematura, pode-se fazer testes de visibilidade antecipada, para ver se há uma necessidade real de uma otimização melhor.

Herr_Alien
fonte
1

A maioria dos que aderem ao "PMO" (ou seja, a cotação parcial) diz que as otimizações devem ser baseadas em medições e as medições não podem ser realizadas até o final.

Também é minha experiência no desenvolvimento de grandes sistemas que o teste de desempenho é realizado no final, à medida que o desenvolvimento está quase completo.

Se seguíssemos os "conselhos" dessas pessoas, todos os sistemas seriam terrivelmente lentos. Eles também seriam caros porque suas necessidades de hardware são muito maiores do que o inicialmente previsto.

Há muito tempo advogo a realização de testes de desempenho em intervalos regulares no processo de desenvolvimento: indicará a presença de um novo código (onde anteriormente não existia) e o estado do código existente.

  • O desempenho do código recém-implementado pode ser comparado ao do código existente existente. Uma "sensação" para o desempenho do novo código será estabelecida ao longo do tempo.
  • Se o código existente repentinamente der errado, você entenderá que algo aconteceu com ele e poderá investigá-lo imediatamente, não (muito) depois, quando isso afetar todo o sistema.

Outra idéia ideal é instrumentar o software no nível do bloco de funções. À medida que o sistema executa, ele reúne informações sobre os tempos de execução dos blocos de funções. Quando uma atualização do sistema é executada, pode-se determinar o desempenho dos blocos de funções como na versão anterior e os que se deterioraram. Na tela de um software, os dados de desempenho podem ser acessados ​​no menu de ajuda.

Confira esta excelente peça sobre o que o PMO pode ou não significar.

Olof Forshell
fonte