Todos sabemos que a otimização prematura é a raiz de todo mal, porque leva a um código ilegível / não-sustentável. Pior ainda é a pessimização, quando alguém implementa uma "otimização" porque acha que será mais rápida, mas acaba sendo mais lenta, além de ser de buggy, insustentável etc. Qual é o exemplo mais ridículo disso que você já viu ?
performance
optimization
dsimcha
fonte
fonte
Respostas:
Em um projeto antigo, herdamos alguns programadores de sistemas embarcados (de outra forma excelentes) que possuíam uma enorme experiência com o Z-8000.
Nosso novo ambiente era o Sparc Solaris de 32 bits.
Um dos rapazes mudou todas as entradas para shorts para acelerar nosso código, já que pegar 16 bits da RAM era mais rápido do que pegar 32 bits.
Eu tive que escrever um programa de demonstração para mostrar que capturar valores de 32 bits em um sistema de 32 bits era mais rápido do que capturar valores de 16 bits e explicar que, para capturar um valor de 16 bits, a CPU precisava criar uma largura de 32 bits acesso à memória e, em seguida, oculte ou altere os bits não necessários para o valor de 16 bits.
fonte
Eu acho que a frase "otimização prematura é a raiz de todo mal" é muito, muito usada. Para muitos projetos, tornou-se uma desculpa para não levar em consideração o desempenho até o final de um projeto.
Essa frase costuma ser uma muleta para as pessoas evitarem o trabalho. Eu vejo essa frase usada quando as pessoas realmente deveriam dizer "Nossa, nós realmente não pensamos nisso de antemão e não temos tempo para lidar com isso agora".
Eu já vi muitos exemplos "ridículos" de problemas de desempenho burros do que exemplos de problemas introduzidos devido à "pessimização"
O que eu acho que é uma afirmação melhor é a seguinte: "otimização sem medir e entender não é otimização - é apenas uma mudança aleatória".
Um bom trabalho de desempenho consome tempo - geralmente mais do que o desenvolvimento do recurso ou componente em si.
fonte
Bancos de dados são campos de pessimização.
Favoritos incluem:
Isso está no topo da minha cabeça.
fonte
Acho que não existe uma regra absoluta: algumas coisas são melhor otimizadas antecipadamente e outras não.
Por exemplo, trabalhei em uma empresa em que recebemos pacotes de dados de satélites. Cada pacote custa muito dinheiro e, portanto, todos os dados são altamente otimizados (ou seja, compactados). Por exemplo, latitude / longitude não foi enviada como valores absolutos (flutuantes), mas como compensações em relação ao canto "noroeste" de uma zona "atual". Tivemos que descompactar todos os dados antes que pudessem ser usados. Mas acho que isso não é pessimização, é otimização inteligente para reduzir os custos de comunicação.
Por outro lado, nossos arquitetos de software decidiram que os dados descompactados deveriam ser formatados em um documento XML muito legível e armazenados em nosso banco de dados como tal (em vez de ter cada campo armazenado em uma coluna correspondente). A idéia deles era que "XML é o futuro", "espaço em disco é barato" e "processador é barato", portanto não havia necessidade de otimizar nada. O resultado foi que nossos pacotes de 16 bytes foram transformados em documentos de 2kB armazenados em uma coluna e, para consultas simples, tivemos que carregar megabytes de documentos XML na memória! Recebemos mais de 50 pacotes por segundo, para que você possa imaginar o quão horrível o desempenho se tornou (BTW, a empresa faliu).
Então, novamente, não há regra absoluta. Sim, às vezes a otimização muito cedo é um erro. Mas, às vezes, o lema "CPU / espaço em disco / memória é barato" é a verdadeira raiz de todo mal.
fonte
Oh, bom Deus, acho que já vi todos eles. Na maioria das vezes, é um esforço para corrigir problemas de desempenho por alguém com muita preguiça de solucionar seus problemas até a CAUSA desses problemas de desempenho ou até mesmo pesquisar se há realmente um problema de desempenho. Em muitos desses casos, me pergunto se não é apenas o caso daquela pessoa querendo experimentar uma determinada tecnologia e procurando desesperadamente por uma unha que se encaixe no seu novo e brilhante martelo.
Aqui está um exemplo recente:
O arquiteto de dados me apresenta uma proposta elaborada para particionar verticalmente uma tabela-chave em um aplicativo bastante grande e complexo. Ele quer saber que tipo de esforço de desenvolvimento seria necessário para ajustar a mudança. A conversa foi assim:
Eu: Por que você está considerando isso? Qual é o problema que você está tentando resolver?
Ele: A Tabela X é muito ampla, estamos particionando por motivos de desempenho.
Eu: O que faz você pensar que é muito grande?
Ele: O consultor disse que são colunas demais para haver em uma tabela.
Eu: E isso está afetando o desempenho?
Ele: Sim, os usuários relataram lentidão intermitente no módulo XYZ do aplicativo.
Eu: Como você sabe que a largura da tabela é a fonte do problema?
Ele: Essa é a tabela principal usada pelo módulo XYZ, e tem 200 colunas. Deve ser o problema.
Eu (explicando): Mas o módulo XYZ, em particular, usa a maioria das colunas nessa tabela, e as colunas que ele usa são imprevisíveis porque o usuário configura o aplicativo para mostrar os dados que deseja exibir nessa tabela. É provável que 95% das vezes acabássemos juntando todas as tabelas novamente, o que prejudicaria o desempenho.
Ele: O consultor disse que é muito amplo e precisamos mudar isso.
Eu: Quem é esse consultor? Eu não sabia que contratamos um consultor, nem eles conversaram com a equipe de desenvolvimento.
Ele: Bem, ainda não os contratamos. Isso faz parte de uma proposta que eles ofereceram, mas insistiram que precisávamos re-arquitetar esse banco de dados.
Eu: Uh huh. Portanto, o consultor que vende serviços de redesenho de banco de dados acha que precisamos de um redesenho de banco de dados ....
A conversa continuou assim. Depois, dei uma outra olhada na tabela em questão e determinei que ela provavelmente poderia ser reduzida com alguma normalização simples, sem a necessidade de estratégias de particionamento exóticas. Isso, é claro, acabou sendo um ponto discutível depois que eu investiguei os problemas de desempenho (anteriormente não relatados) e os localizei em dois fatores:
É claro que o arquiteto ainda está pressionando por um particionamento vertical da tabela pendurado no meta-problema "muito amplo". Ele até reforçou seu caso ao receber uma proposta de outro consultor de banco de dados que foi capaz de determinar que precisávamos de grandes alterações de design no banco de dados sem olhar o aplicativo ou executar qualquer análise de desempenho.
fonte
Eu já vi pessoas usando o alphadrive-7 para incubar totalmente o CHX-LT. Essa é uma prática incomum. A prática mais comum é inicializar o transformador ZT para reduzir a bufferização (devido à maior resistência à sobrecarga líquida) e criar bytegraphications no estilo java.
Totalmente pessimista!
fonte
Nada que abale a Terra, admito, mas já peguei pessoas usando o StringBuffer para concatenar Strings fora de um loop em Java. Era algo simples como virar
para dentro
Costumava ser uma prática bastante comum usar a técnica em loop, porque era mensurável mais rápido. O problema é que o StringBuffer é sincronizado, portanto, há sobrecarga extra se você estiver concatenando apenas algumas Strings. (Sem mencionar que a diferença é absolutamente trivial nessa escala.) Dois outros pontos sobre essa prática:
fonte
Uma vez vi um banco de dados MSSQL que usava uma tabela 'Root'. A tabela Raiz tinha quatro colunas: GUID (identificador exclusivo), ID (int), LastModDate (datetime) e CreateDate (datetime). Todas as tabelas no banco de dados foram chave estrangeira na tabela raiz. Sempre que uma nova linha foi criada em qualquer tabela no banco de dados, era necessário usar alguns procedimentos armazenados para inserir uma entrada na tabela Raiz antes de poder chegar à tabela real com a qual você se importava (em vez de o banco de dados fazer o trabalho para você com alguns gatilhos simples).
Isso criou uma bagunça inútil de ouvir e de cabeça, exigiu que qualquer coisa escrita em cima dela usasse sprocs (e eliminando minhas esperanças de apresentar o LINQ à empresa. Era possível, mas não merecia a dor de cabeça), e ainda por cima não ' nem realizar o que deveria fazer.
O desenvolvedor que escolheu esse caminho o defendeu sob a suposição de que isso economizava muito espaço porque não estávamos usando Guids nas próprias tabelas (mas ... não é um GUID gerado na tabela Raiz para todas as linhas que fazemos?) , melhorou o desempenho de alguma forma e tornou "fácil" auditar alterações no banco de dados.
Ah, e o diagrama do banco de dados parecia uma aranha mutante do inferno.
fonte
E se pessimização do POBI obviamente por intenção?
Um colega meu nos anos 90 estava cansado de ser chutado pelo CEO apenas porque o CEO passou o primeiro dia de cada lançamento de software ERP (personalizado) com a localização de problemas de desempenho nas novas funcionalidades. Mesmo que as novas funcionalidades esmagassem gigabytes e tornassem o impossível possível, ele sempre encontrava alguns detalhes, ou mesmo um problema aparentemente importante, para reclamar. Ele acreditava saber muito sobre programação e se divertia chutando as bundas dos programadores.
Devido à natureza incompetente das críticas (ele era um CEO, não um cara de TI), meu colega nunca conseguiu acertar. Se você não tiver um problema de desempenho, não poderá eliminá-lo ...
Até um lançamento, ele colocou muitas chamadas de função Delay (200) (era Delphi) no novo código. Foram necessários apenas 20 minutos após a entrada em operação e ele recebeu ordem de comparecer no escritório do CEO para buscar pessoalmente seus insultos em atraso.
Até agora, a única coisa incomum que meus colegas ficaram mudos quando ele voltou, sorrindo, brincando, saindo para um BigMac ou dois, enquanto normalmente chutava mesas, brigava com o CEO e a empresa e passava o resto do dia morto. .
Naturalmente, meu colega agora descansava por um ou dois dias em sua mesa, aprimorando suas habilidades de mira no Quake - então, no segundo ou terceiro dia, ele excluiu as chamadas de atraso, reconstruiu e lançou um "patch de emergência" do qual espalhou a palavra que ele passou 2 dias e 1 noite para consertar os buracos no desempenho.
Esta foi a primeira (e única) vez em que o CEO do mal disse "ótimo trabalho!" para ele. Isso é tudo o que importa, certo?
Este era um verdadeiro POBI.
Mas também é um tipo de otimização de processos sociais, por isso é 100% ok.
Eu acho que.
fonte
"Independência do banco de dados". Isso significava que não havia procs armazenados, gatilhos, etc - nem mesmo chaves estrangeiras.
fonte
Melhor uso de um StringBuilder que eu já vi.
fonte
Usando um regex para dividir uma string quando um simples string.split é suficiente
fonte
Muito tarde para esta discussão, eu sei, mas vi isso recentemente:
Sabe, no caso de um booleano ter alguns valores extras ...
fonte
O pior exemplo que posso imaginar é um banco de dados interno da minha empresa que contém informações sobre todos os funcionários. Ele recebe uma atualização noturna do RH e tem um serviço da Web ASP.NET na parte superior. Muitos outros aplicativos usam o serviço da web para preencher itens como campos de pesquisa / lista suspensa.
O pessimismo é que o desenvolvedor pensou que as chamadas repetidas para o serviço da web seriam muito lentas para fazer consultas SQL repetidas. então, o que ele fez? O evento de início do aplicativo lê todo o banco de dados e converte tudo em objetos na memória, armazenados indefinidamente até que o pool de aplicativos seja reciclado. Esse código era tão lento que levaria 15 minutos para carregar menos de 2000 funcionários. Se você inadvertidamente reciclou o pool de aplicativos durante o dia, isso poderia levar 30 minutos ou mais, porque cada solicitação de serviço da Web iniciaria várias recargas simultâneas. Por esse motivo, novas contratações não apareceriam no banco de dados no primeiro dia em que sua conta foi criada e, portanto, não poderiam acessar a maioria dos aplicativos internos nos primeiros dois dias, mexendo nos polegares.
O segundo nível de pessimismo é que o gerente de desenvolvimento não deseja tocá-lo por medo de quebrar aplicativos dependentes, mas ainda continuamos a ter interrupções esporádicas de aplicativos críticos em toda a empresa devido ao mau design de um componente tão simples.
fonte
Parece que ninguém mencionou a classificação, então eu irei.
Várias vezes diferentes, descobri que alguém havia criado uma bolha de bolhas, porque a situação "não exigia" uma chamada para o algoritmo de classificação rápida "muito sofisticado" que já existia. O desenvolvedor ficou satisfeito quando sua bolha artesanal trabalhou bem o suficiente nas dez linhas de dados que eles estavam usando para teste. Não foi tão bom assim depois que o cliente adicionou algumas milhares de linhas.
fonte
Certa vez, trabalhei em um aplicativo cheio de código como este:
Basta remover
found
, retornarnull
no final e alterar a sexta linha para:Duplicou o desempenho do aplicativo.
fonte
Uma vez eu tive que tentar modificar o código que incluía essas gemas na classe Constants
Cada um deles foi usado várias vezes no restante do aplicativo para diferentes propósitos. COMMA_DELIMINATOR encheu o código com mais de 200 usos em 8 pacotes diferentes.
fonte
O maior número um de todos os tempos, que repito várias vezes no software interno:
Não uso dos recursos do DBMS por motivos de "portabilidade" porque "podemos querer mudar para outro fornecedor posteriormente".
Leia meus lábios. Para qualquer trabalho interno: NÃO ACONTECE!
fonte
Eu tinha um colega de trabalho que estava tentando superar o otimizador de nosso compilador C e reescrever o código de rotina que somente ele poderia ler. Um de seus truques favoritos era mudar um método legível como (criando algum código):
nisso:
Ou seja, a primeira linha de um método que antes era legível se tornaria "
return
" e toda a outra lógica seria substituída por expressões ternárias profundamente aninhadas. Quando você tentava argumentar sobre como isso era impossível de manter, ele apontava para o fato de que a saída do método de montagem era três ou quatro instruções de montagem mais curtas. Não era necessariamente qualquer mais rápido , mas ele sempre foi um minúsculo pouco mais curto. Este era um sistema embutido onde o uso de memória ocasionalmente importava, mas havia otimizações muito mais fáceis que poderiam ter sido feitas do que aquelas que deixariam o código legível.Depois disso, por algum motivo, ele decidiu que
ptr->structElement
era ilegível demais, então começou a mudar tudo isso para(*ptr).structElement
a teoria de que era mais legível e mais rápido também.Transformar código legível em código ilegível para uma melhoria máxima de 1% e, às vezes, de fato, um código mais lento.
fonte
if
. A insistência em declarações sobre expressões em C é um dogma cultural / religioso, e não qualquer tipo de prática objetiva. (Melhor orientação: se o ternário aninhado for muito longo para ser lido, você não deve usarif
qualquer um.)if
em uma função e substituí-lo por um ternário. Tudo bem, e muitas vezes mais legível. Estou falando de substituir um método inteiro de mais de 30 linhas por uma única declaração de retorno e ternários aninhados. Ninguém achou que o novo código era mais legível, mas um desenvolvedor achou que era mais rápido.Em um dos meus primeiros trabalhos como desenvolvedor de pleno direito, assumi o projeto de um programa que estava sofrendo problemas de dimensionamento. Funcionaria razoavelmente bem em pequenos conjuntos de dados, mas travaria completamente quando recebesse grandes quantidades de dados.
Ao pesquisar, descobri que o programador original procurava acelerar as coisas paralelizando a análise - lançando um novo encadeamento para cada fonte de dados adicional. No entanto, ele cometera um erro, pois todos os threads exigiam um recurso compartilhado, no qual estavam em conflito. Obviamente, todos os benefícios da concorrência desapareceram. Além disso, ele travou a maioria dos sistemas ao lançar mais de 100 threads apenas para bloquear todos, exceto um. Minha máquina de desenvolvimento robusta era uma exceção, pois agitava um conjunto de dados de 150 fontes em cerca de 6 horas.
Portanto, para corrigi-lo, removi os componentes com vários threads e limpei a E / S. Sem outras alterações, o tempo de execução no conjunto de dados de 150 fontes caiu abaixo de 10 minutos na minha máquina e do infinito para menos de meia hora na máquina média da empresa.
fonte
Suponho que eu poderia oferecer esta jóia:
Como a raiz quadrada foi calculada em um local muito sensível, tive a tarefa de procurar uma maneira de torná-la mais rápida. Essa pequena refatoração reduziu o tempo de execução em um terço (para a combinação de hardware e compilador usado, YMMV):
É claro que existem maneiras mais rápidas e melhores de fazer isso, mas acho que é um exemplo bastante interessante de pessimização.
Edit: Venha para pensar sobre isso, o loop desenrolado também era na verdade uma pessimização pura. Indo além do controle de versão, também posso apresentar o segundo estágio da refatoração, que teve um desempenho ainda melhor do que o descrito acima:
Este é exatamente o mesmo algoritmo, embora uma implementação ligeiramente diferente, então suponho que seja qualificado.
fonte
isqrt()
calculefloor(sqrt())
, mas, por que esse código funciona?Isso pode estar em um nível mais alto do que o que você buscava, mas corrigi-lo (se você puder) também envolve um nível mais alto de dor:
Insistindo na rolagem manual de um Gerenciador de Relacionamento com Objetos / Camada de Acesso a Dados, em vez de usar uma das bibliotecas estabelecidas, testadas e maduras existentes no mercado (mesmo depois de indicadas a você).
fonte
Todas as restrições de chave estrangeira foram removidas de um banco de dados, porque, caso contrário, haveria muitos erros.
fonte
Isso não se encaixa exatamente na questão, mas mencionarei de qualquer maneira uma história de advertência. Eu estava trabalhando em um aplicativo distribuído que estava sendo executado lentamente e voei até o DC para participar de uma reunião destinada principalmente a resolver o problema. O líder do projeto começou a esboçar uma re-arquitetura destinada a resolver o atraso. Ofereci que havia realizado algumas medições no fim de semana que isolaram o gargalo em um único método. Aconteceu que havia um registro ausente em uma pesquisa local, fazendo com que o aplicativo tivesse que ir para um servidor remoto em todas as transações. Ao adicionar o registro de volta à loja local, o atraso foi eliminado - problema resolvido. Observe que a re-arquitetura não teria resolvido o problema.
fonte
Verificando antes de CADA operação javascript se o objeto em que você está operando existe.
Meu problema com esse tipo de código é que ninguém parece se importar, e se ele não existir? Apenas não faz nada? Não dê o feedback ao usuário?
Concordo que os
Object expected
erros são irritantes, mas esta não é a melhor solução para isso.fonte
E o extremismo YAGNI? É uma forma de pessimização prematura. Parece que sempre que você aplica o YAGNI, acaba precisando dele, resultando em 10 vezes mais esforço para adicioná-lo do que se você o tivesse adicionado no início. Se você criar um programa bem-sucedido, é provável que VOCÊ PRECISA NECESSÁRIO. Se você está acostumado a criar programas cuja vida se esgota rapidamente, continue praticando o YAGNI porque, suponho, o YAGNI.
fonte
Não é exatamente uma otimização prematura - mas certamente equivocada - isso foi lido no site da BBC, em um artigo que discute o Windows 7.
Agora, ainda não testei o Windows 7, por isso posso estar errado, mas estou disposto a apostar que existem outros problemas que são mais importantes do que o tempo que leva para desligar. Afinal, quando vejo a mensagem 'Desligando o Windows', o monitor é desligado e eu vou embora - como esses 400 milissegundos me beneficiam?
fonte
Alguém do meu departamento escreveu uma aula de cordas. Uma interface como
CString
, mas sem a dependência do Windows.Uma "otimização" que eles fizeram foi não alocar mais memória do que o necessário. Aparentemente, não percebendo que o motivo pelo qual as classes
std::string
alocam excesso de memória é para que uma sequência de+=
operações possa ser executada em O (n) tempo.Em vez disso, todas as
+=
chamadas forçavam uma realocação, que transformava anexos repetidos em um algoritmo de O (n²) Schlemiel, o Pintor .fonte
Um ex-colega de trabalho meu (um sabão , na verdade) foi designado para criar um novo módulo para o nosso Java ERP que deveria ter coletado e analisado os dados dos clientes (setor de varejo). Ele decidiu dividir TODOS os campos Calendário / Data e hora em seus componentes (segundos, minutos, horas, dia, mês, ano, dia da semana, bimestre, trimestre (!)) Porque "de que outra forma eu procuraria por 'toda segunda-feira'?"
fonte
Sem ofender ninguém, mas acabei de classificar uma tarefa (java) que tinha essa
fonte