Qual è l'approccio migliore per la codifica in un ambiente di compilazione lento


15

Ero abituato a scrivere codice in C # in uno stile TDD: scrivere / o modificare un piccolo pezzo di codice, ricompilare in 10 secondi l'intera soluzione, rieseguire i test e di nuovo. Facile...

Quella metodologia di sviluppo ha funzionato molto bene per me per alcuni anni, fino all'ultimo anno in cui sono dovuto tornare alla codifica C ++ e da allora sembra davvero che la mia produttività sia notevolmente diminuita. Il C ++ come linguaggio non è un problema - ho avuto parecchie esperienze di sviluppo C ++ ... ma in passato.

La mia produttività è ancora OK per piccoli progetti, ma peggiora quando con l'aumento delle dimensioni del progetto e una volta che il tempo di compilazione raggiunge i 10+ minuti diventa davvero male. E se trovo l'errore devo ricominciare la compilazione, ecc. Questo è puramente frustrante.

Così ho concluso che in piccoli pezzi (come prima) non è accettabile - qualsiasi consiglio come posso farmi prendere la vecchia abitudine di codificare per un'ora o giù di lì, quando rivedo il codice manualmente (senza fare affidamento su un compilatore C # veloce) e ricompilare / rieseguire i test unitari solo una volta ogni due ore.

Con un C # e un TDD è stato molto semplice scrivere un codice in modo evolutivo - dopo una dozzina di iterazioni qualsiasi schifezza con cui ho iniziato finiva con un buon codice, ma non funziona più per me (in una compilation lenta ambiente).


stackoverflow.com/questions/5078409/… Questi dovrebbero probabilmente essere uniti / in un unico posto.
Ben L

Vedi laso stackoverflow.com/questions/373142/… per accelerare i tempi di compilazione C ++.
Eclipse,

2
Inizia uno scontro a spada . ; p
Steven Jeuris,

L'ultima volta che ho usato C ++ sul serio, usando le intestazioni precompilate ho ridotto i tempi di compilazione di un fattore quattro.
gnasher729,

Risposte:


16

Mi vengono in mente diverse cose:

  1. Utilizzare la compilazione distribuita . Puoi farlo con GCC ("distCC"?) O VC ( IncrediBuild di Xoreax non è esattamente economico, ma vale ogni centesimo speso per esso.).

  2. Dividi il tuo progetto in librerie caricate dinamicamente e cerca di ridurre al minimo le dipendenze da esse. Gli eseguibili più piccoli si collegano molto più velocemente.

  3. Programma contro piccoli progetti di test piuttosto che l'intera grande applicazione.

  4. Utilizza la programmazione meta-template per eseguire algoritmi in fase di compilazione . Sì, questo in realtà aumenterà i tempi di compilazione, ma ridurrà anche i tempi di risposta necessari per i test: se si compila bene, è fatto.

  5. Investi in hardware . Più kernel della CPU (nella tua macchina o in altri) ti stupiranno con la compilazione distribuita, e molta memoria più un disco veloce (SSD invece di HDD) ti aiuteranno molto. Se hai un sistema a 64 bit e quantità oscene di RAM, la compilazione su un disco RAM potrebbe fornire un incredibile aumento di velocità.


1
le cache del compilatore sono in realtà un'idea migliore della compilazione distribuita nella mia esperienza.
pqnet,

Parlando di disco RAM rispetto a SSD, sono rimasto piuttosto sorpreso dal fatto che non abbia portato così tanto aumento nella velocità di compilazione. Il mio progetto attuale (Java su Android) viene compilato dallo stato pulito in ~ 45 secondi da SSD e in ~ 40 secondi dal disco RAM (e l'intera toolchain si trova nel disco RAM, non solo nelle fonti). Non un aumento drammatico, direi.
Haspemulator il

10

Un'altra soluzione tecnica non ancora menzionata da altri è il passaggio a unità a stato solido anziché a normali dischi rigidi. In un precedente progetto a cui ho lavorato, gli SSD hanno ridotto i tempi di costruzione nell'intervallo da 30 minuti a 3.

Certo, sono costosi. Per il tuo capo, calcola il prezzo del tempo perso per gli sviluppatori rispetto al prezzo dell'investimento una tantum. L'investimento probabilmente si ripaga da solo in pochi mesi.


6
Interessante. Ciò significa che il 90% dei tempi di costruzione è la latenza del disco I / O.
Mike Dunlavey,

Non ho visto un calo del 90%, ma sostanziale. Non sembra accelerare la compilazione, ma accelera decisamente il collegamento. Se stai apportando piccole modifiche a un progetto di grandi dimensioni (quindi non c'è molta compilazione in una modifica) e ricollegandoti, potresti benissimo ottenere questo. (Questo è Visual Studio 2008, utilizzando C ++.)
David Thornley,

1
Questa è una buona idea. Inoltre, montare una parte di RAM sul tuo filesystem funzionerebbe velocemente ed è economico.
Goran Jovic,

2
Ramdisk è ancora più veloce (ed economico).
SK-logic,

1
@John: Sì, un compilatore ben scritto dovrebbe (IMHO) essere associato a I / O.
Mike Dunlavey,

3

Maggiore pianificazione, codifica in blocchi più grandi, scrittura di test di integrazione anziché unit-test ed esecuzione della suite build + test durante la notte.


3

A volte i tempi di compilazione lunghi sono un problema, ma la già menzionata modularizzazione può aiutare a superarlo (principalmente).

Molto più grave è essere bloccato in un ambiente in cui non è possibile compilare affatto, in cui ogni modifica del codice deve essere inviata a un altro reparto in un altro continente per l'applicazione all'ambiente di test / sviluppo, un processo che può richiedere giorni per essere completato.

Ora sto lavorando in un ambiente simile e questo sistema mi è già costato per una settimana (e il progetto ha un budget di 4 settimane in totale prima che finiscano i soldi) solo per installare la versione iniziale delle nostre modifiche (e poi hanno commesso errori che impediscono a parte dei file di non essere raccolti dal server delle applicazioni, quindi stiamo osservando altri giorni di ritardo). Ogni piccola modifica ora (diciamo che troviamo qualcosa nei test che deve essere riparato, come una condizione di errore mancata) può causare un ritardo di un altro giorno o più.

In tali condizioni si tenta di accertarsi che non vi siano errori di sorta prima ancora di provare a compilare il codice. Mi sembra quasi di tornare alla programmazione mainframe, dove avevamo 5 minuti di CPU al mese disponibili per tutte le operazioni di compilazione e test.


1
Ragazzo, questa è una situazione infernale. Ricordo i giorni del mainframe. Abbiamo fatto un sacco di "controllo da banco" del codice. È incredibile quanto sia stato fatto in quel modo, come infinite simulazioni di voli sulla luna.
Mike Dunlavey,

3

Ricordo facilmente quando le build hanno impiegato molto tempo. Alcuni approcci attenuanti:

  • Costruisci il sistema combinando librerie o dll. In questo modo, quando modifichi del codice, l'unica parte che deve essere ricompilata è la tua parte.
  • Il numero di punti nel codice che è necessario modificare per implementare una funzione non influisce solo sulla quantità di modifiche da eseguire, ma sulla frequenza con cui si inseriscono i bug, amplificando il ciclo compile-debug-edit-compile. Tutto ciò che riduce la ridondanza del codice, come DRY, aiuta.
  • Se sei nel debugger e puoi modificare, ricompilare e continuare senza uscire dal debugger, è davvero utile.

2

10+ minuti per una compilazione? Sul serio?

Stai utilizzando un IDE che esegue la costruzione incrementale (ad esempio Eclipse)? In caso contrario, probabilmente dovresti, eseguirà la compilazione di base in pochi secondi anziché in minuti.

Oppure stai parlando di elementi di integrazione, in cui devi creare l'intera app per testare le tue modifiche? In tal caso, guarda i test più piccoli per assicurarti che i principali bug siano fuori dal tuo codice prima di dover eseguire la build completa.


5
10 minuti è piccolo. Ho lavorato per un progetto che ha richiesto un'ora per la compilazione e il collegamento da zero su una macchina single-core, PCH e tutto il resto. Ovviamente, fatta eccezione per le versioni a rilascio automatico, nessuno lo costruirà su un solo core del processore, ma comunque ... Se dovessi cambiare qualcosa in un'intestazione che è inclusa praticamente ovunque (manipolazione delle stringhe, gestione degli errori), potresti impazzire.
sabato

2
Lavorava (anni fa) su un sistema che, per una compilazione completa, impiegava 48 ore per essere compilato. Ovviamente un build completo è stato avviato solo venerdì sera, si spera che possa essere fatto quando torneremo in ufficio lunedì. Abbiamo invece creato piccoli moduli secondo necessità (diciamo una singola DLL).
jwenting

2
-1 a tutti i commenti sopra se potessi fare +1 su TrueDub. Sì, se stai ricompilando tutto, potrebbe richiedere molto tempo. Tuttavia, se si pensa alla gestione delle dipendenze, i progetti di ricompilazione completi per 10 ore possono avere ricompilazioni incrementali in meno di un minuto come norma. Tutti voi dovreste vergognarvi di sprecare il tempo dei vostri datori di lavoro in attesa dei vostri ricompilamenti quando applicate un po 'di intelligenza vi farà risparmiare una grande quantità di tempo.
Dunk il

2
E se lavori in un piccolo negozio che si trova su un progetto di diversi MLoC, ciò significa che una parte considerevole del codice è vecchia, iniziata dieci anni fa come piccoli progetti multipli, in cui la velocità di compilazione non è mai stata un problema, e la gestione delle dipendenze è abominevolmente negativa. Quindi hai intenzione di dire a una simile compagnia di buttare via tutto questo e passare un altro decennio a riscriverlo?
sabato

2
@Dunk: era una piccola azienda, con meno di una dozzina di sviluppatori che lavoravano a un progetto multi-MLoC. È molto diverso da centinaia di sviluppatori che lo fanno: non è possibile riscrivere nulla da zero, perché per farlo occorrerebbero anni. Per quanto odiassi l'idea, investire nella compilazione distribuita era economicamente fattibile, la riscrittura no. Oh, e ho ereditato quelle interfacce. :-xNon ci sono stato dieci anni fa, quando sono stati pensati. (Ho modificato molto di quel codice per utilizzare TMP, per trovare più errori durante la compilazione e meno nel campo.)
sbi,

2

Innanzitutto, perché ci vuole così tanto tempo per compilare in primo luogo?

  • Il tuo ambiente (IDE, make, qualunque cosa) supporta build incrementali? Assicurati di ricompilare solo le modifiche, anziché l'intera cosa.
  • Se si dispone di una macchina multi-core, l'IDE potrebbe supportare la compilazione parallela. So per certo che Visual Studio lo fa. Apparentemente anche gcc. Quindi procurati una macchina migliore e abilita la compilazione parallela.
  • Prendi in considerazione l'utilizzo di intestazioni precompilate.
  • Se provi tutto ciò e la compilazione è ancora lenta, rivedi il tuo codice. Cerca dipendenze non necessarie. Stai includendo un'intestazione in cui una dichiarazione a termine sarebbe sufficiente? Prendi in considerazione l'uso del linguaggio PIMPL per ridurre la dipendenza dalle intestazioni.

Se dopo tutto questo il tempo di costruzione è ancora lento, allora risolvi il problema: crea molti piccoli progetti di test e lavora su ciascuno di essi. Assicurati di avere un sistema automatico notturno di build che esegua un nuovo checkout, costruisca tutto ed esegua automaticamente tutti i test dell'unità.

Infine, se ti ci vuole ancora molto tempo per testare le modifiche, allora rifletti su di esse. Assicurati di fare una differenza nel tuo sistema di controllo della versione e rivedi attentamente tutte le modifiche prima del test. In breve, questo è molto simile allo sviluppo di sistemi embedded, in cui i tempi di consegna di un test sono lunghi e la capacità di esaminare lo stato del sistema è limitata.

Questo mi porta a un altro pensiero: strumento il tuo codice per utilizzare la registrazione. In questo modo potresti essere in grado di vedere qual è il problema senza ricostruire e rieseguire una dozzina di volte.


2
Non sono sicuro che GCC supporti compilazioni parallele tanto quanto il fatto che strumenti simili o simili avvieranno diverse copie di GCC se lo dici anche tu.
Zaccaria K,

1
+1 per PIMPL. Ho lavorato su un progetto in cui i tempi di costruzione sono andati fuori controllo. In quel progetto, non mi importava di quante altre intestazioni fossero incluse in ciascuna intestazione. Nel mio prossimo progetto, ho cercato di minimizzare questo aspetto facendo ampio uso di PIMPL. I tempi di compilazione continuano ad essere grandi anche se il secondo progetto è probabilmente il doppio del primo.
Jason B,

1

Probabilmente hai bisogno di un approccio multiplo:

1) Sistemi di costruzione più veloci. Il maggior numero di core / ram / disco veloce che puoi permetterti. Per i progetti C ++ più grandi, troverai che il disco è spesso un limitatore, quindi assicurati di averne di veloci.

2) Più modularizzazione del progetto. Rompi le cose in modo che le modifiche non possano facilmente causare la ricompilazione completa di tutto. Francamente, inserisci quante più cose possibili in file dll / so separati in modo che parte del progetto possa essere completamente separata dal resto.

3) Build incrementali / build distribuite / memorizzazione nella cache in base al proprio ambiente. Su alcuni sistemi, distcc (edificio distribuito) e ccache (memorizzazione nella cache di elementi parzialmente costruiti) possono risparmiare molto tempo di compilazione.

4) Assicurati che la tua build possa essere ben parallelizzata. Soprattutto in un ambiente di makefile, non è difficile entrare in una situazione in cui hai creato accidentalmente i Makefile in modo tale da non poter costruire parallelamente.


0

La registrazione estesa e la convalida interna sono state utili per lunghi tempi di consegna. Al termine della compilazione, una singola esecuzione può rivelare contemporaneamente una vasta gamma di possibili problemi.

Quando si ha a che fare con algoritmi o contabilità piuttosto complessi, può essere utile includere una versione altamente semplificata in parallelo a quella "reale". In ogni esecuzione, sono inclusi utili dati di riferimento.


0

Cosa hanno detto @sbi e @Michael Kohne.

Dedica tempo ed energia al processo di costruzione stesso. C'era una volta un prodotto maestoso e maturo che impiegava più di un'ora per una costruzione completa. Molto tempo ed energia sono stati spesi per riparare ciò che le dipendenze di build hanno affermato di essere, e poi, per riparare / ridurre ciò che erano effettivamente. Il tempo di costruzione è sceso a ~ 30 minuti.

Il cambio degli strumenti di compilazione lo ha lasciato cadere di più. Per un progetto in più parti, "scons" può eseguire tutte le compilazioni prima di eseguire qualsiasi collegamento. 'make' usando più makefile fa le compilazioni di un singolo progetto prima dei collegamenti di quel progetto, quindi passa avanti.

Questo ci ha portato al punto che tutti i singoli comandi di compilazione potevano essere eseguiti in modo massiccio parallelo. 'distcc' su macchine lente, make / scons -j8 su macchine multicore. Ciò ha portato le build complete a una manciata di minuti.

Sotto una luce diversa, crea un processo di costruzione notturno automatizzato. In questo modo se qualcosa di problematico si impegna nel tuo repository di origine, la prima persona che arriva al lavoro, vede e risolve il problema, può impedire a più persone di (ri) eseguire più build fallite.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.