O que torna um produto de software grande e complexo lento? [fechadas]

16

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?

Roman Starkov
fonte
7
Simples: à medida que a massa aumenta, é necessária mais força para superar a inércia.
Shog9
Alguém me disse uma vez gerentes, mas eu não acredito nisso.
precisa saber é o seguinte
1
Esta é uma grande parte do motivo pelo qual ainda uso principalmente o D7 na programação Delphi.
GrandmasterB
O código mais rápido é aquele que nunca é executado.
Henry
4
@romkyns: Acho que muitos softwares da era moderna são incrivelmente inchados, desnecessariamente grandes e difíceis de manejar. Muitos softwares agora resolvem os mesmos problemas que foram resolvidos há dez, até vinte anos, com uma fração da energia e do espaço. Por que ainda está tão ruim quanto antes, se não mais? Ineficiência e inchaço.
Orbling

Respostas:

20

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.

Jay Beavers
fonte
4
Um programa delphi não parece plano. Em vez disso, um programador programa um programa para parecer simples. Você pode criar interfaces modernas, bonitas e coloridas com o Delphi da mesma forma que em C # ou C ++.
GrandmasterB
2
Esta é uma resposta perspicaz; mas não tenho certeza se está completo. O Visual Studio 2008 (o antecessor de 2010) não possui WPF e ainda é um mundo mais lento que o Delphi 7. Você ainda diria o mesmo sobre a profundidade da pilha de chamadas e o número de DLLs carregadas?
Timwi 22/01
3
@ Timwi Sim, absolutamente eu faria. Meu argumento era menos sobre os males do WPF (na verdade, eu gosto do WPF) e mais sobre como tendemos a adicionar camadas e mais camadas de abstração de software quando recebíamos a opção. Talvez Visual Studio 2008 não tinha tão grande sobrecarga, mas como você observou que tinha o bastante :-)
Jay Beavers
@GrandmasterB, não estou criticando Delphi porque ele vem com menos suposições e bibliotecas mais simples. O WPF foi projetado assumindo que a aceleração de hardware da GPU permitiria que os programas usassem cores mais profundas, animações frequentes, mistura de alfa, sombras etc. O Delphi foi projetado em um momento em que essas suposições não podiam ser feitas. Você poderia reimplementar tudo isso no Delphi? Claro, mas você teria que colocar muita codificação apenas para obter o comportamento de um botão WPF. No lado positivo, um botão Delphi não vem com os requisitos de CPU, memória e GPU que um botão WPF possui, que era a pergunta do @ OP.
Jay Beavers
10
Seu argumento para a interface simples e simples é completamente invalidado pela nova interface moderna do Windows 10. Agora temos toda essa sobrecarga para criar botões planos, quadrados e lisos, como há 30 anos.
Gbjbaanb
11

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?

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 Pixelou Boolean.

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 Pixelou Booleancasos) 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.

Thomas Owens
fonte
2
Dívida técnica, em outras palavras. Dívida técnica que nunca é paga.
Robert Harvey
1
Robert está correto. Um erro de um cara, duzentos erros --forcedos 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
user3834459
2
Interessante, especialmente em como você viu uma granularidade excessiva mal usada. Eu me peguei fazendo algo semelhante em ocasiões no passado e obtive um desempenho ruim como resultado. Isso é bastante semelhante à sua resposta de alguns dias atrás sobre o uso de coleções e algoritmos em massa, em preferência à granularidade excessiva . Não acredito que a resposta não tenha sido mais apreciada por sua profundidade. Isso me faz repensar vários dos projetos que construí ao longo dos anos. Eu me pergunto por que essas técnicas não são mais amplamente promovidas?
Mike suporta Monica
2
@ Mike Eu sou um pouco quebrado em relação a tentar promover mais uma mentalidade orientada a dados. É popular na indústria de jogos, onde eles estão tentando utilizar cada centímetro do hardware. Dito isto, é certo que reduz a flexibilidade. Se você tem uma classe abstrata de pixels, pode fazer coisas loucas com isso, como ter uma única imagem que mistura dois ou mais formatos de pixel diferentes! No entanto, quando lidamos com caminhos críticos, provavelmente nenhuma imagem se beneficiaria desse nível de flexibilidade, e o desempenho começa a se tornar uma preocupação real com qualquer coisa que envolva imagens e pixels.
1
Nos velhos tempos, eu implementava algum código para ignorar as APIs gráficas e acessar diretamente os pixels na memória para uma parte crítica do meu código. A diferença entre as muitas camadas de abstração e acesso direto era algo como 100x, que importava em um computador naqueles dias. Agora, seus computadores são rápidos o suficiente para poder percorrer qualquer quantidade de abstração, se necessário.
precisa saber é o seguinte