Por uma razão que é amplamente irrelevante, instalei o Delphi 7 mais uma vez em tanto tempo. Devo dizer que fiquei completamente impressionado - de uma maneira que não faz muito tempo. Não é assim que me lembro das coisas. A instalação levou cerca de 30 segundos. O lançamento demorou 2 segundos e foi imediatamente utilizável. Posso pressionar "Executar" no segundo após o início e, menos de um segundo depois, o programa em branco já está visível e em execução. Hurrah para computadores ficando muito mais rápidos!
Mas o motivo pelo qual fiquei impressionado é que, geralmente, uso o Visual Studio 2010, que não parece nada fácil assim. É verdade que o Delphi 7 é um sistema muito menor que o Visual Studio 2010, mas tem a aparência de ter todas as coisas realmente necessárias lá: uma paleta de controle, um designer de formulários, um editor de código com conclusão de código. Eu percebo que a linguagem pode ser mais simples, e a conclusão do código pode ser muito menos poderosa, e o IDE pode não ser tão extensível e rico em recursos, mas ainda assim: eu não entendo como (ou seja, por qual mecanismo) muitos recursos extras (que eu talvez ainda nem tenha acionado) fazem com que um sistema como o Visual Studio pareça sempre lento em comparação.
Gostaria de perguntar às pessoas com experiência no trabalho com sistemas a escala do Visual Studio: o que as torna lentas? São as camadas e mais as abstrações necessárias para manter a base de código dentro dos recursos de compreensão humana? É a grande quantidade de código que precisa ser executada? É a tendência moderna para abordagens de economia de tempo de programadores às custas (incrivelmente grandes) do departamento de ciclos de clock / uso de memória?
fonte
Respostas:
Astronáutica arquitetônica
O Visual Studio 2010 é desenvolvido sobre o Windows Presentation Foundation. Dê uma olhada na classe Button para WPF. É o nono filho de uma classe base. Possui cerca de 5 páginas de propriedades, métodos e eventos. Nos bastidores, há outras cinco páginas de definições de estilo que descrevem seus cantos lindamente arredondados e as sutis transições de animação quando um cursor do mouse se move sobre ele. Isso é tudo para algo que exibe fundamentalmente algum texto ou figura e produz um evento de clique quando detecta um botão do mouse pressionado.
Pare um programa como o Visual Studio em qualquer ponto aleatório. Veja o rastreamento da pilha. É muito provável que você tenha 20 níveis na pilha de chamadas e que cinco DLLs tenham sido carregadas para chegar lá.
Agora, compare essas duas coisas com o Delphi. Aposto que você acha que um botão Delphi tem apenas 20 propriedades, métodos e eventos. Aposto que o Delphi IDE possui apenas um rastreamento de pilha com níveis de profundidade de 5 a 7. Porque quando os computadores eram mais lentos, você não conseguia suportar a sobrecarga do Visual Studio 2010 sem que o IDE levasse 40 minutos para iniciar :-)
Um é melhor que o outro? Bem, geralmente posso dizer a um programa Delphi quando ele carrega porque parece plano, as cores estão mudas (talvez 8 bits?) E não há sombreamento ou animação sutil. Eu me sinto 'barato' hoje em dia. Barato, mas rápido.
Estamos melhor? Essa é uma pergunta para os filósofos, não para os codificadores.
fonte
Acho que você adivinhou vários deles, mas gostaria de oferecer o que considero o maior fator, tendo trabalhado em uma base de código razoavelmente grande (não tenho certeza se é tão grande quanto o Visual Studio) estava nas milhões de linhas de código categoria e cerca de mil plugins) por cerca de 10 anos e ocorrem fenômenos de observação.
Também é um pouco menos controverso, pois não entra em APIs ou recursos de linguagem ou algo assim. Esses estão relacionados a "custos", que podem gerar um debate em vez de "gastos", e eu quero focar em "gastos".
Coordenação e legado frouxos
O que observei é que uma coordenação frouxa e um longo legado tendem a levar a muito desperdício acumulado.
Por exemplo, encontrei cerca de cem estruturas de aceleração nessa base de código, muitas delas redundantes.
Teríamos como uma árvore KD para acelerar um mecanismo de física, outra para um novo mecanismo de física que frequentemente rodava em paralelo com o antigo, teríamos dezenas de implementações de octrees para vários algoritmos de malha, outra árvore KD para renderizar , picking, etc. etc. etc. Todas essas são estruturas de árvores grandes e volumosas usadas para acelerar as pesquisas. Cada indivíduo pode levar centenas de megabytes a gigabytes de memória para obter uma entrada de tamanho muito médio. Eles nem sempre eram instanciados e usados o tempo todo, mas a qualquer momento, 4 ou 5 deles podiam estar na memória simultaneamente.
Agora, todos eles estavam armazenando exatamente os mesmos dados para acelerar as pesquisas por eles. Você pode imaginá-lo como o antigo banco de dados analógico, que armazena todos os seus campos em 20 mapas / dicionários / árvores B + redundantes diferentes de uma só vez, organizados identicamente pelas mesmas chaves e pesquisa todos eles o tempo todo. Agora estamos gastando 20 vezes a memória e o processamento.
Além disso, devido à redundância, há pouco tempo para otimizar qualquer um deles com o preço de manutenção que acompanha o produto e, mesmo se o fizéssemos, teria apenas 5% do efeito ideal.
O que causa esse fenômeno? Coordenação frouxa foi a causa número um que eu vi. Muitos membros da equipe geralmente trabalham em seus ecossistemas isolados, desenvolvendo ou usando estruturas de dados de terceiros, mas não usando as mesmas estruturas que outros membros da equipe estavam usando, mesmo que fossem duplicatas flagrantes das mesmas preocupações.
O que causa esse fenômeno persistir? Legado e compatibilidade foram a causa número um que eu vi. Como já pagamos o custo para implementar essas estruturas de dados e grandes quantidades de código dependiam dessas soluções, muitas vezes era muito arriscado tentar consolidá-las em menos estruturas de dados. Embora muitas dessas estruturas de dados fossem altamente redundantes conceitualmente, elas nem sempre eram nem de longe idênticas em seus designs de interface. Portanto, substituí-los teria sido uma mudança grande e arriscada, em vez de apenas deixá-los consumir memória e tempo de processamento.
Eficiência de memória
Normalmente, o uso e a velocidade da memória tendem a estar relacionados pelo menos no nível de massa. Muitas vezes, é possível detectar softwares lentos pela forma como está consumindo memória. Nem sempre é verdade que mais memória leva a uma desaceleração, uma vez que o que importa é memória "quente" (que memória está sendo acessada o tempo todo - se um programa usa um barco cheio de memória, mas apenas 1 megabyte está sendo usado todo o tempo, então não é tão importante em termos de velocidade).
Assim, você pode identificar os possíveis porcos com base no uso de memória a maior parte do tempo. Se um aplicativo leva dezenas a centenas de megabytes de memória na inicialização, provavelmente não será muito eficiente. Dezenas de megabytes podem parecer pequenos quando temos gigabytes de DRAM atualmente, mas os caches de CPU maiores e mais lentos ainda estão na faixa de megabytes e os mais rápidos ainda na faixa de kilobytes. Como resultado, um programa que usa 20 megabytes apenas para iniciar e não faz nada ainda está usando muita "memória" do ponto de vista do cache da CPU do hardware, especialmente se todos os 20 megabytes dessa memória forem acessados repetidamente e frequentemente como o programa está sendo executado.
Solução
Para mim, a solução é buscar equipes menores e mais coordenadas para criar produtos, que possam acompanhar seus "gastos" e evitar "comprar" os mesmos itens repetidamente.
Custo
Vou mergulhar no lado mais controverso do "custo" apenas um pouquinho com um fenômeno de "gasto" que observei. Se um idioma acaba tendo um preço inevitável para um objeto (como um que fornece reflexão em tempo de execução e não pode forçar alocação contígua para uma série de objetos), esse preço é caro apenas no contexto de um elemento muito granular, como um solteiro
Pixel
ouBoolean
.Apesar disso, vejo um monte de código-fonte de programas que fazem lidar com uma carga pesada (ex: lidar com centenas de milhares a milhões de
Pixel
ouBoolean
casos) pagar esse custo em um nível tão granular.A programação orientada a objetos pode exacerbar isso. No entanto, não é o custo dos "objetos" propriamente ditos, nem mesmo da OOP, é simplesmente que esses custos estão sendo pagos em um nível tão granular de um elemento pequenino que será instanciado aos milhões.
Então esse é o outro fenômeno de "custo" e "gasto" que estou observando. O custo é de centavos, mas os centavos se somam se estamos comprando um milhão de latas de refrigerante individualmente, em vez de negociar com um fabricante uma compra a granel.
A solução aqui para mim é a compra "em massa". Os objetos são perfeitamente adequados, mesmo em idiomas que têm um preço de centavos para cada um, desde que esse custo não seja pago individualmente um milhão de vezes pelo equivalente analógico de uma lata de refrigerante.
Otimização prematura
Eu nunca gostei da redação usada por Knuth aqui, porque a "otimização prematura" raramente faz com que os programas de produção do mundo real sejam mais rápidos. Alguns interpretam isso como "otimizar cedo" quando Knuth significava mais como "otimizar sem o conhecimento / experiência adequados para conhecer seu verdadeiro impacto no software". De qualquer forma, o efeito prático da otimização prematura verdadeira muitas vezes tornará o software mais lento , pois a degradação da capacidade de manutenção significa que há pouco tempo para otimizar os caminhos críticos que realmente importam .
Esse é o fenômeno final que observei, em que os desenvolvedores que tentavam economizar centavos na compra de uma única lata de refrigerante, para nunca mais serem comprados, ou pior, uma casa, estavam perdendo todo o tempo comprando centavos (ou, pior, centavos imaginários de falhando em entender seu compilador ou a arquitetura do hardware) quando havia bilhões de dólares sendo desperdiçados em outros lugares.
O tempo é muito finito; portanto, tentar otimizar absolutos sem ter as informações contextuais apropriadas costuma nos privar a oportunidade de otimizar os lugares que realmente importam e, portanto, em termos de efeito prático, eu diria que "a otimização prematura torna o software muito mais lento. "
O problema é que existem tipos de desenvolvedores que pegam o que escrevi acima sobre objetos e tentam estabelecer um padrão de codificação que proíbe a programação orientada a objetos ou algo louco desse tipo. A otimização eficaz é uma priorização efetiva e é absolutamente inútil se estivermos nos afogando em um mar de problemas de manutenção.
fonte
--force
dos gerentes gritando "você será demitido se não implementar isso até amanhã", que destrói anos de boas práticas de engenharia de software, TDD, testes de unidade e qualquer princípio de programação humano e são , mais duas outras vezes em que você estava cansado .. aquele cara que deixou a empresa louca porque foi demitido sem motivo e estragou a base de código .. aquelas bibliotecas descontinuadas que você nunca atualizou ... e aqui está: deliciosa base de código de espaguete e software inchado. Bon Appetit