Qual é a melhor abordagem para codificar em um ambiente de compilação lenta

15

Eu costumava codificar em C # no estilo TDD - escrever / ou alterar um pequeno pedaço de código, recompilar em 10 segundos toda a solução, executar novamente os testes e novamente. Fácil...

Essa metodologia de desenvolvimento funcionou muito bem para mim por alguns anos, até o ano passado, quando eu tive que voltar à codificação C ++ e realmente sinto que minha produtividade diminuiu drasticamente desde então. O C ++ como linguagem não é um problema - eu tinha bastante experiência em desenvolvimento de C ++ ... mas no passado.

Minha produtividade ainda é boa para projetos pequenos, mas fica pior quando, com o aumento do tamanho do projeto, e quando o tempo de compilação atinge mais de 10 minutos, fica muito ruim. E se eu encontrar o erro, tenho que começar a compilar novamente etc. Isso é simplesmente frustrante.

Assim, concluí que, em pequenos pedaços (como antes), não é aceitável - qualquer recomendação, como posso me habituar ao antigo hábito de codificar por uma hora ou mais, ao revisar o código manualmente (sem depender de um compilador C # rápido) , e apenas recompilar / reexecutar testes de unidade uma vez a cada duas horas.

Com um C # e um TDD, era muito fácil escrever um código de maneira evolutiva - depois de uma dúzia de iterações, qualquer coisa com a qual eu comecei estava terminando em um bom código, mas simplesmente não funciona mais para mim (em uma compilação lenta meio Ambiente).

mosquito
fonte
stackoverflow.com/questions/5078409/… Estes provavelmente devem ser mesclados / em um só lugar.
Ben L
Consulte laso stackoverflow.com/questions/373142/… para acelerar os tempos de compilação em C ++.
Eclipse
2
Comece uma luta de espadas . ; p
Steven Jeuris
A última vez que usei o C ++ a sério, usando cabeçalhos pré-compilados, reduzi o tempo de compilação em um fator quatro.
gnasher729

Respostas:

16

Várias coisas me vêm à mente:

  1. Faça uso da compilação distribuída . Você pode fazer isso com o GCC ("distCC"?) Ou o VC (o Xedeax 'IncrediBuild não é exatamente barato, mas vale cada centavo gasto nele).

  2. Divida o seu projeto em bibliotecas carregadas dinamicamente e tente minimizar com cuidado as dependências delas. Os executáveis ​​menores são vinculados muito mais rapidamente.

  3. Programe em projetos de teste pequenos em vez de em todo o grande aplicativo.

  4. Empregue programação de meta-modelo para executar algoritmos em tempo de compilação . Sim, isso realmente aumentará o tempo de compilação, mas também diminuirá as reviravoltas necessárias para o teste: se compilar bem, está feito.

  5. Invista em hardware . Mais kernels de CPU (em sua máquina ou em outras) se surpreenderão com a compilação distribuída, e muita memória, além de um disco rápido (SSD em vez de HDD), ajudará bastante. Se você possui um sistema de 64 bits e quantidades obscenas de RAM, a compilação em um disco RAM pode fornecer um incrível aumento de velocidade.

sbi
fonte
1
caches de compilador são na verdade uma ideia melhor do que a compilação distribuída na minha experiência.
Pqnet
Falando em disco RAM versus SSD, fiquei bastante surpreso por não ter aumentado tanto a velocidade de compilação. Meu projeto atual (Java no Android) compila do estado limpo em ~ 45 segundos do SSD e em ~ 40 segundos do disco RAM (e toda a cadeia de ferramentas está no disco RAM, não apenas nas fontes). Não é um aumento dramático, eu diria.
Haspemulator
10

Outra solução técnica ainda não mencionada por outros é a mudança para unidades de estado sólido em vez de discos rígidos comuns. Em um projeto anterior em que trabalhei, os SSDs reduziram o tempo de construção do intervalo de 30 minutos para 3.

Claro, eles são caros. Para seu chefe, calcule o preço do tempo perdido do desenvolvedor em relação ao preço do investimento único. O investimento provavelmente se paga em alguns meses.

Péter Török
fonte
6
Isso é interessante. Isso indica que 90% do tempo de construção é latência do disco de E / S.
22811 Mike Dunlavey
Não vi uma diminuição de 90%, mas uma substancial. Parece não acelerar a compilação, mas definitivamente acelera a vinculação. Se você estiver fazendo pequenas alterações em um projeto grande (para que não haja muita compilação em uma alteração) e revincular, você poderá obter isso. (Este é o Visual Studio 2008, usando C ++.)
David Thornley
1
Essa é uma boa ideia. Além disso, montar uma parte da RAM no seu sistema de arquivos funcionaria rápido e é barato.
Goran Jovic
2
Ramdisk é ainda mais rápido (e mais barato).
SK-logic,
1
@ John: Sim, um compilador bem escrito (IMHO) deve ser vinculado à E / S.
Mike Dunlavey
3

Mais planejamento, codifique em partes maiores, escreva testes de integração em vez de testes de unidade e execute o conjunto de testes build + durante a noite.

Nemanja Trifunovic
fonte
3

Tempos de compilação longos às vezes são um problema, mas a modularização já mencionada pode ajudar a superar isso (principalmente).

Muito mais sério está sendo travado em um ambiente em que você não pode compilar, onde todas as alterações de código precisam ser enviadas para outro departamento em outro continente para aplicação no ambiente de teste / desenvolvimento, um processo que pode levar dias para ser concluído.

Agora estou trabalhando nesse ambiente, e esse sistema já me custou mais de uma semana (e o projeto só tem orçamento para 4 semanas de tempo total antes que o dinheiro acabe) apenas para instalar a versão inicial de nossas alterações (e eles cometeram erros que fazem com que parte dos arquivos não sejam coletados pelo servidor de aplicativos, por isso estamos analisando vários dias de atraso). Agora, cada pequena alteração (digamos que encontramos algo em teste que precisa ser corrigido, como uma condição de erro perdida) pode causar um atraso de outro dia ou mais.

Nessas condições, você tenta garantir o máximo possível que não há erros antes mesmo de tentar compilar seu código. Parece que estou de volta à programação de mainframe, onde tínhamos 5 minutos de CPU por mês disponíveis para todo o trabalho de compilação e teste.

jwenting
fonte
1
Rapaz, isso é uma situação do inferno. Eu me lembro dos dias do mainframe. Fizemos muitas "checagens" no código. É incrível o quanto isso foi feito, como simulações intermináveis ​​de voos para a lua.
Mike Dunlavey 22/02
3

Lembro-me facilmente de quando as construções demoraram muito tempo. Algumas abordagens atenuantes:

  • Crie o sistema combinando bibliotecas ou dlls. Dessa forma, quando você modifica algum código, a única parte que precisa ser recompilada é a sua parte.
  • O número de pontos no código que você precisa editar para implementar um recurso não apenas afeta a quantidade de edição que você precisa fazer, mas também a frequência com que você coloca bugs, amplificando o loop compile-debug-edit-compile. Tudo o que reduz a redundância do código, como DRY, ajuda.
  • Se você estiver no depurador e puder editar, recompilar e continuar sem sair do depurador, isso é realmente útil.
Mike Dunlavey
fonte
2

10+ minutos para uma compilação? Seriamente?

Você está usando um IDE que faz construção incremental (por exemplo, Eclipse)? Caso contrário, você provavelmente deve fazer, ele fará a compilação básica em segundos, em vez de minutos.

Ou você está falando sobre coisas de integração, nas quais precisa criar o aplicativo inteiro para testar suas alterações? Nesse caso, observe testes menores para garantir que os principais bugs estejam fora do seu código antes de fazer a compilação completa.

TrueDub
fonte
5
10 minutos é pequeno. Eu trabalhei em um projeto que levou uma hora para compilar e vincular do zero em uma máquina de núcleo único, PCHs e tudo. É claro que, exceto nas versões automáticas, ninguém o construiria em apenas um núcleo do processador, mas ainda assim ... Se você tivesse que alterar algo em um cabeçalho incluído em quase todos os lugares (manipulação de strings, manipulação de erros), você poderia ficar louco.
S22 22/11
2
Costumava trabalhar (anos atrás) em um sistema que levou, para uma compilação completa, 48 horas para ser compilado. Obviamente, uma compilação completa só foi iniciada na sexta-feira à noite, e esperamos que isso seja feito quando voltarmos ao escritório na segunda-feira. Em vez disso, criamos pequenos módulos conforme necessário (digamos uma única DLL).
jwenting
2
-1 para todos os comentários acima, se eu pudesse marcar com +1 no TrueDub. Sim, se você estiver recompilando tudo, poderá demorar muito tempo. No entanto, se algum pensamento for dado ao gerenciamento de dependências, os projetos de recompilação inteiros de 10 horas podem ter recompiles incrementais em menos de um minuto, a norma. Vocês todos devem ter vergonha de desperdiçar o tempo de seus empregadores, esperando suas recompilações, ao aplicar um pouco de inteligência, economizando muito tempo.
Dunk
2
E se você trabalha em uma pequena loja que fica em um projeto de vários MLoC, isso significa que uma parte considerável do código é antiga, iniciada há uma década como vários pequenos projetos, nos quais a velocidade de compilação nunca foi um problema, e o gerenciamento de dependências é abominavelmente ruim. Então, você vai dizer a uma empresa para jogar tudo isso fora e passar mais uma década reescrevendo?
sbi 22/02
2
@ Dunk: Era uma empresa pequena, com menos de uma dúzia de desenvolvedores trabalhando em um projeto de vários MLoC. Isso é muito diferente de centenas de desenvolvedores que estão fazendo isso: você não pode reescrever nada do zero, porque precisaria de anos para fazê-lo. Por mais que eu odiasse a idéia, investir em compilação distribuída era economicamente viável, a reescrita não era. Ah, e eu herdei essas interfaces. :-xEu não estava lá uma década atrás, quando eles foram pensados. (I mudou um monte de que o código de empregar TMP, para encontrar mais erros na compilação, e menos no campo.)
SBI
2

Primeiro, por que demora tanto tempo para compilar em primeiro lugar?

  • Seu ambiente (IDE, marca, qualquer que seja) suporta compilações incrementais? Verifique se você está apenas recompilando as alterações, e não a coisa toda.
  • Se você possui uma máquina com vários núcleos, seu IDE pode suportar compilação paralela. Sei que o Visual Studio faz isso. Aparentemente, o gcc também. Portanto, adquira uma máquina melhor e ative a compilação paralela.
  • Considere usar cabeçalhos pré-compilados.
  • Se você tentar tudo isso e a compilação ainda estiver lenta, revise seu código. Procure dependências desnecessárias. Você está incluindo um cabeçalho em que uma declaração de encaminhamento seria suficiente? Considere usar o idioma PIMPL para reduzir a dependência de cabeçalhos.

Se depois de tudo isso o tempo de compilação ainda estiver lento, resolva o problema: crie muitos projetos de teste pequenos e trabalhe em cada um individualmente. Verifique se você possui um sistema noturno automatizado de compilação que faz uma nova verificação geral, constrói tudo e executa todos os testes de unidade automaticamente.

Por fim, se você ainda demorar muito para testar suas alterações, pense mais nelas. Certifique-se de fazer uma diferença no seu sistema de controle de versão e revise cuidadosamente todas as alterações antes do teste. Em resumo, isso é muito parecido com o desenvolvimento de sistemas embarcados, onde o tempo de resposta de um teste é longo e sua capacidade de examinar o estado do sistema é limitada.

Isso me leva a outro pensamento: instrumentar seu código para usar o log. Dessa forma, você poderá ver qual é o problema sem reconstruir e executar novamente uma dúzia de vezes.

Dima
fonte
2
Não tenho certeza se o GCC suporta compilações paralelas, tanto quanto o fato de que as ferramentas make ou similares iniciarão várias cópias do GCC, se você também o contar.
Zachary K
1
+1 para PIMPL. Eu trabalhei em um projeto em que os tempos de construção ficaram fora de controle. Nesse projeto, não cuidei de quantos outros cabeçalhos foram incluídos em cada cabeçalho. No meu próximo projeto, fiz questão de minimizar isso usando amplamente o PIMPL. Os tempos de compilação continuam ótimos, embora o segundo projeto tenha provavelmente o dobro do tamanho do primeiro.
Jason B
1

Você provavelmente precisa de uma abordagem em várias frentes:

1) Sistemas de construção mais rápidos. Quantos núcleos / ram / disco rápido você pode pagar. Para projetos C ++ maiores, você encontrará que o disco geralmente é um limitador, portanto, verifique se possui discos rápidos.

2) Mais modularização do projeto. Divida tudo para que as alterações não possam facilmente causar recompilações completas de tudo. Francamente, insira o máximo possível de coisas básicas em arquivos dll / so separados para que parte do projeto possa ser completamente separada do resto.

3) Construções incrementais / construções distribuídas / armazenamento em cache conforme apropriado ao seu ambiente. Em alguns sistemas, distcc (edifício distribuído) e ccache (armazenamento em cache de coisas parcialmente construídas) podem economizar muito tempo de compilação.

4) Verifique se sua compilação pode ser bem paralelizada. Especialmente em um ambiente de makefile, não é difícil entrar em uma situação em que você acidentalmente configurou os Makefiles de forma que não possa criar construções paralelas.

Michael Kohne
fonte
0

Registro extensivo e validação interna têm sido úteis por longos tempos de resposta. Depois que sua compilação estiver concluída, uma única execução poderá revelar um grande conjunto de possíveis problemas ao mesmo tempo.

Ao lidar com algoritmos ou contabilidade bastante complexos, pode ser útil incluir uma versão altamente simplificada em paralelo com a versão "real". Em qualquer execução, você inclui dados de referência úteis.

Joris Geer
fonte
0

O que @sbi e @ Michael Kohne disseram.

Gaste tempo e energia no próprio processo de construção. Era uma vez um produto imponente e maduro, que levava mais de uma hora para uma compilação completa. Foi gasto muito tempo e energia consertando o que as dependências de compilação alegavam ser e, posteriormente, consertando / reduzindo o que realmente eram. O tempo de construção caiu para ~ 30 minutos.

A alteração das ferramentas de construção diminuiu ainda mais. Para um projeto de várias partes, 'scons' pode fazer todas as compilações antes de fazer qualquer link. 'make' usando vários makefiles faz a compilação de um único projeto antes dos links desse projeto e depois segue em frente.

Isso nos levou ao ponto de que todos os comandos individuais de compilação poderiam ser feitos massivamente em paralelo. 'distcc' em máquinas lentas, make / scons -j8 em máquinas multicore. Isso trouxe compilações completas para alguns minutos.

Sob uma luz diferente, crie um processo de criação noturno automatizado. Dessa forma, se algo problemático for confirmado no seu repositório de origem, a primeira pessoa a chegar ao trabalho, ver e corrigir o problema, poderá impedir que várias pessoas (re) façam várias compilações com falha.

Rick Berge
fonte