Best practice per soluzioni di grandi dimensioni in Visual Studio (2008) [chiuso]


87

Abbiamo una soluzione con circa 100+ progetti, la maggior parte dei quali C #. Naturalmente, ci vuole molto tempo sia per aprire che per costruire, quindi sto cercando le migliori pratiche per tali bestie. Sulla falsariga delle domande a cui spero di ottenere risposte, ci sono:

  • come gestisci al meglio i riferimenti tra i progetti
    • "copia locale" dovrebbe essere attivato o disattivato?
  • ogni progetto dovrebbe essere compilato nella propria cartella o dovrebbero essere compilati tutti nella stessa cartella di output (fanno tutti parte della stessa applicazione)

  • Le cartelle delle soluzioni sono un buon modo per organizzare le cose?

So che suddividere la soluzione in più soluzioni più piccole è un'opzione, ma viene fornita con il proprio set di refactoring e costruzione di grattacapi, quindi forse possiamo salvarlo per un thread separato :-)


2
Posso chiedere perché una singola soluzione richiede più di 100 progetti? Ognuno di loro crea la propria assemblea?
Neil N

1
Sì, lo sono e ciascuno di essi rappresenta una funzionalità logicamente separata.
Eyvind

2
@Eyvind - Non è a questo che servono le classi e gli spazi dei nomi? Quali vantaggi vi portano le assemblee separate? Posso pensare ad alcuni, come aggiornamenti potenzialmente più piccoli e l'uso della memoria (se alcuni non vengono caricati), ma c'è sicuramente un costo per avere più di 100 assemblaggi da compilare e gestire.
si618

1
@ Marco sento il tuo dolore. Siamo fino a 94 progetti qui. Non posso fare molto al riguardo ora, poiché dovremmo interrompere lo sviluppo su più team per ristrutturarli. Abbiamo 3 progetti EXE che fanno riferimento agli altri 91. Sto sperimentando una cartella di output comune, finora i guadagni sono molto impressionanti.
Kevin

2
Uomo, 100+? Non è niente per quello che abbiamo ... spingendo quasi 600 qui ora ...
C Johnson

Risposte:


41

Potresti essere interessato a questi due articoli su MSBuild che ho scritto.

MSBuild: best practice per la creazione di build affidabili, parte 1

MSBuild: best practice per la creazione di build affidabili, parte 2

Nello specifico nella Parte 2 c'è una sezione Costruire grandi alberi sorgente che potresti voler dare un'occhiata.

Per rispondere brevemente alle tue domande qui però:

  • CopyLocal? Di sicuro spegnilo
  • Costruire in una o più cartelle di output? Crea in una cartella di output
  • Cartelle della soluzione? Questa è una questione di gusti.

Sayed Ibrahim Hashimi

Il mio libro: Dentro il motore di build di Microsoft: utilizzo di MSBuild e Team Foundation Build


Grazie amico, mi assicurerò di dare un'occhiata a quelli!
Eyvind

1
Dirò che ho questo libro ed è fantastico. Mi ha aiutato ad automatizzare le mie build TFS e le build di sviluppo locale in modo molto esteso. Ora sto lavorando a build incrementali e il libro approfondisce l'argomento. Vale il prezzo. Grazie Sayed. Continuate così.
irperez

Grazie irperez per i commenti
Sayed Ibrahim Hashimi

2
-1 per il consiglio UNCONDITIONAL di disabilitare CopyLocal. Impostare CopyLocal = false può causare diversi problemi durante il tempo di distribuzione. Vedere il mio post sul blog "Non modificare" Copia locale "riferimenti al progetto in false, a meno che non si comprendano le sottosequenze ." ( Geekswithblogs.net/mnf/archive/2012/12/09/… )
Michael Freidgeim

Potrebbe "creare una cartella di output" causare problemi durante la compilazione con più thread?
BrunoLM

9

+1 per un uso parsimonioso delle cartelle della soluzione per aiutare a organizzare le cose.

+1 per la creazione del progetto nella propria cartella. Inizialmente abbiamo provato una cartella di output comune e questo può portare a trovare riferimenti non aggiornati e complicati.

FWIW, utilizziamo riferimenti a progetti per le soluzioni e, sebbene nuget sia probabilmente una scelta migliore in questi giorni, abbiamo riscontrato che svn: externals funziona bene sia per gli assembly interni di terze parti che (di tipo framework). Prendi l'abitudine di usare un numero di revisione specifico invece di HEAD quando fai riferimento a svn: externals (colpevole come addebitato :)


2
+1 Ho anche problemi con la soluzione della cartella di output comune. Non ho capito cosa significhi "riferimenti di progetto per soluzioni", per favore spiega un po 'di più ...
Mauricio Scheffer

Come in usiamo VS-> Aggiungi riferimento-> Progetti, invece di VS-> Aggiungi riferimento-> Sfoglia. Piccolo punto lo so, ma alcune persone lo fanno in modo diverso (e penso che questo causi più mal di testa). Se guardi il testo csproj di MSBuild vedrai la proprietà ProjectReference invece di Reference.
si618

Risposta interessante! Penso che abbiamo zigzato dove hai zigzagato. Non abbiamo affatto cartelle di soluzioni e ci basiamo sulla denominazione dei progetti (i progetti hanno lo stesso nome dello spazio dei nomi). Tutto il nostro output va in una singola cartella, il che rende la configurazione dello sviluppatore molto più vicina a quella della distribuzione. Se le dipendenze sono impostate correttamente, non abbiamo riferimenti non aggiornati.
Thomas Bratt

sì, la directory di output comune porta a molti problemi, specialmente quando si usa resharper. Riferimenti obsoleti davvero.
Florian Doyon

1
@ Kevin, sono passati diversi anni, ma dalla memoria un esempio sono due progetti che fanno riferimento allo stesso assembly, ad esempio una libreria esterna a cui non si fa riferimento al progetto. Tutto bene quando sono sulla stessa versione, ma poi esce una nuova versione di questa libreria, ma solo un progetto aggiorna il loro riferimento, quale versione viene utilizzata nella cartella di output comune?
si618

8

Scarica i progetti che non usi spesso e acquista un SSD. Un SSD non migliora i tempi di compilazione, ma Visual Studio diventa due volte più veloce da aprire / chiudere / compilare.


3
Vale la pena notare che lo scaricamento di un progetto è un'impostazione per utente, quindi gli sviluppatori del tuo team possono caricare solo i progetti a cui tengono. Questo ha davvero aiutato il nostro team.
Pagina

È possibile utilizzare l'estensione Solution Load Manager visualstudiogallery.msdn.microsoft.com/… per definire cosa non caricare per impostazione predefinita
Michael Freidgeim

6

Abbiamo un problema simile poiché abbiamo 109 progetti separati da affrontare. Per rispondere alle domande originali basate sulle nostre esperienze:

1. Come gestire al meglio i riferimenti tra i progetti

Usiamo l'opzione del menu contestuale "aggiungi riferimento". Se è selezionato "progetto", la dipendenza viene aggiunta al nostro singolo file di soluzione globale per impostazione predefinita.

2. "Copia locale" dovrebbe essere attivato o disattivato?

Fuori dalla nostra esperienza. La copia extra si aggiunge ai tempi di costruzione.

3. Ogni progetto dovrebbe essere compilato nella propria cartella o tutti dovrebbero essere compilati nella stessa cartella di output (fanno tutti parte della stessa applicazione)

Tutto il nostro output viene messo in una singola cartella chiamata "bin". L'idea è che questa cartella sia la stessa di quando viene distribuito il software. Questo aiuta a prevenire problemi che si verificano quando la configurazione dello sviluppatore è diversa dalla configurazione della distribuzione.

4. Le cartelle delle soluzioni sono un buon modo per organizzare le cose?

No nella nostra esperienza. La struttura delle cartelle di una persona è l'incubo di un'altra. Le cartelle nidificate in profondità aumentano solo il tempo necessario per trovare qualsiasi cosa. Abbiamo una struttura completamente piatta ma denominiamo i nostri file di progetto, assembly e spazi dei nomi allo stesso modo.


Il nostro modo di strutturare i progetti si basa su un unico file di soluzione. Costruire questo richiede molto tempo, anche se i progetti stessi non sono cambiati. Per aiutare con questo, di solito creiamo un altro file di soluzione "set di lavoro corrente". Tutti i progetti su cui stiamo lavorando vengono aggiunti a questo. I tempi di compilazione sono notevolmente migliorati, anche se un problema che abbiamo riscontrato è che Intellisense non riesce per i tipi definiti nei progetti che non sono nel set corrente.

Un esempio parziale del layout della nostra soluzione:

\bin

OurStuff.SLN

OurStuff.App.Administrator
OurStuff.App.Common
OurStuff.App.Installer.Database
OurStuff.App.MediaPlayer
OurStuff.App.Operator
OurStuff.App.Service.Gateway
OurStuff.App.Service.CollectionStation
OurStuff.App.ServiceLocalLauncher
OurStuff.App.StackTester
OurStuff.Auditing
OurStuff.Data
OurStuff.Database
OurStuff.Database.Constants
OurStuff.Database.ObjectModel
OurStuff.Device
OurStuff.Device.Messaging
OurStuff.Diagnostics
...
[etc]

Potrebbe "creare una cartella di output" causare problemi durante la compilazione con più thread?
BrunoLM

4

Lavoriamo su un grande progetto simile qui. Le cartelle delle soluzioni si sono dimostrate un buon modo per organizzare le cose e tendiamo a lasciare solo copy local impostato su true. Ogni progetto viene compilato nella propria cartella, quindi sappiamo che per ogni progetto distribuibile al suo interno è presente il sottoinsieme corretto dei file binari.

Per quanto riguarda l'apertura del tempo e la costruzione del tempo, sarà difficile da risolvere senza interrompere le soluzioni più piccole. Potresti studiare il parallelismo della build (google "Parallel MS Build" per un modo per farlo e integrarlo nell'interfaccia utente) per migliorare la velocità qui. Inoltre, guarda il design e verifica se il refactoring di alcuni dei tuoi progetti per ottenere un numero complessivo inferiore potrebbe essere d'aiuto.


3

In termini di alleviare i problemi di costruzione, puoi utilizzare l'opzione "Configuration Manager ..." per le build per abilitare o disabilitare la creazione di progetti specifici. Puoi avere un "Progetto [n] Build" che potrebbe escludere determinati progetti e utilizzarlo quando scegli come target progetti specifici.

Per quanto riguarda gli oltre 100 progetti, so che non vuoi essere martellato in questa domanda sui vantaggi di ridurre le dimensioni della tua soluzione, ma penso che tu non abbia altra opzione quando si tratta di accelerare il tempo di caricamento (e utilizzo della memoria) di devenv.


Hm, questo è stato screditato per aver sbagliato o solo per non essere d'accordo? Posso convivere con il primo se puoi dirmi perché.
Michael Meadows

D'accordo, non mi piace il downvoting senza commento, quindi Michael ottieni il mio +1 per bilanciare l'equazione ;-)
si618

2
a proposito, personalmente non mi piace scherzare con la gestione della configurazione per questo genere di cose. Perché? perché se commetti accidentalmente la configurazione modificata, il tuo server di compilazione o altri sviluppatori ne saranno interessati.
si618

Concordato. In realtà, lo stesso problema si verifica con soluzioni con troppi progetti. :)
Michael Meadows

3

Quello che di solito faccio con questo dipende un po 'da come avviene effettivamente il processo di "debug". In genere, però, NON imposto copy local come true. Ho impostato la directory di compilazione per ogni progetto per inviare tutto al punto finale desiderato.

Pertanto, dopo ogni build, ho una cartella popolata con tutte le DLL e qualsiasi applicazione Web / Windows e tutti gli elementi si trovano nella posizione corretta. La copia locale non era necessaria poiché la dll alla fine finisce nel posto giusto.

Nota

Quanto sopra funziona per le mie soluzioni, che in genere sono applicazioni web e non ho riscontrato alcun problema con i riferimenti, ma potrebbe essere possibile!


3

Abbiamo un problema simile. Lo risolviamo utilizzando soluzioni più piccole. Abbiamo una soluzione master che apre tutto. Ma perf. su questo è un male. Quindi, segmentiamo le soluzioni più piccole per tipo di sviluppatore. Quindi, gli sviluppatori DB hanno una soluzione che carica i progetti a cui tengono, gli sviluppatori di servizi e gli sviluppatori dell'interfaccia utente la stessa cosa. È raro che qualcuno debba aprire l'intera soluzione per ottenere ciò di cui ha bisogno fatto giorno per giorno. Non è una panacea - ha i suoi lati positivi e negativi. Vedi "modello multi-soluzione" in questo articolo (ignora la parte sull'uso di VSS :)


2

Penso che con soluzioni così ampie la migliore pratica dovrebbe essere quella di suddividerle. Puoi pensare alla "soluzione" come a un luogo in cui riunire i progetti necessari e forse altri pezzi per lavorare su una soluzione a un problema. Suddividendo gli oltre 100 progetti in più soluzioni specializzate per lo sviluppo di soluzioni solo per una parte del problema generale, è possibile affrontarne meno in un dato momento accelerando le interazioni con i progetti richiesti e semplificando il dominio del problema.

Ogni soluzione produrrebbe l'output di cui è responsabile. Questo output dovrebbe contenere informazioni sulla versione che possono essere impostate in un processo automatizzato. Quando l'output è stabile, è possibile aggiornare i riferimenti nei progetti e nelle soluzioni dipendenti con l'ultima distribuzione interna. Se vuoi ancora entrare nel codice e accedere alla fonte, puoi effettivamente farlo con il server dei simboli Microsoft che Visual Studio può utilizzare per consentirti di accedere agli assembly di riferimento e persino recuperare il codice sorgente.

Lo sviluppo simultaneo può essere eseguito specificando le interfacce in anticipo e deridendo gli assembly in fase di sviluppo mentre si aspettano le dipendenze che non sono complete ma su cui si desidera sviluppare.

Trovo che questa sia una best practice perché non c'è limite alla complessità dello sforzo complessivo quando lo scomponi fisicamente in questo modo. Mettere tutti i progetti in un'unica soluzione finirà per raggiungere un limite massimo.

Spero che queste informazioni siano utili.


2

Abbiamo circa 60+ progetti e non usiamo file di soluzioni. Abbiamo un mix di progetti C # e VB.Net. La performance è sempre stata un problema. Non lavoriamo su tutti i progetti contemporaneamente. Ogni sviluppatore crea i propri file di soluzione in base ai progetti su cui sta lavorando. I file della soluzione non vengono archiviati nel nostro controllo del codice sorgente.

Tutti i progetti della libreria di classi verranno compilati in una cartella CommonBin nella radice della directory di origine. I progetti eseguibili / Web vengono creati nella loro cartella individuale.

Non usiamo riferimenti al progetto, invece riferimenti basati su file dalla cartella CommonBin. Ho scritto un'attività MSBuild personalizzata che ispezionasse i progetti e determinasse l'ordine di compilazione.

Lo usiamo da alcuni anni e non possiamo lamentarci.


3
Ti dispiacerebbe condividere la tua attività msbuild personalizzata?
andreapier

0

Tutto ha a che fare con la tua definizione e visione su cosa sono una soluzione e un progetto. Nella mia mente una soluzione è proprio questo, un raggruppamento logico di progetti che risolvono un requisito molto specifico. Sviluppiamo una grande applicazione Intranet. Ogni applicazione all'interno di quella Intranet ha la propria soluzione, che può contenere anche progetti per exes o servizi Windows. E poi abbiamo un framework centralizzato con cose come classi base e helper e httphandlers / htpmodules. Il framework di base è abbastanza grande e viene utilizzato da tutte le applicazioni. Suddividendo le molte soluzioni in questo modo si riduce la quantità di progetti richiesti da una soluzione, poiché la maggior parte di essi non ha nulla a che fare l'uno con l'altro.

Avere così tanti progetti in una soluzione è solo un cattivo design. Non dovrebbe esserci motivo per avere tanti progetti sotto una soluzione. L'altro problema che vedo è con i riferimenti al progetto, possono davvero rovinarti alla fine, soprattutto se vuoi dividere la tua soluzione in quelle più piccole.

Il mio consiglio è di farlo e sviluppare un framework centralizzato (la tua implementazione di Enterprise Library, se vuoi). Puoi condividere con GAC o puoi fare riferimento direttamente al percorso del file in modo da avere un archivio centrale. È possibile utilizzare la stessa tattica anche per gli oggetti aziendali centralizzati.

Se vuoi fare riferimento direttamente alla DLL, vorrai fare riferimento a essa nel tuo progetto con copy local false (da qualche parte come c: \ mycompany \ bin \ mycompany.dll). In un runtime dovrai aggiungere alcune impostazioni al tuo app.config o web.config per fare in modo che faccia riferimento a un file non nel GAC o nel bin di runtime. In realtà non importa se è una copia locale o meno, o se la dll finisce nel cestino o è anche nella GAC, perché la configurazione sovrascriverà entrambi. Penso che sia una cattiva pratica copiare locale e avere un sistema disordinato. Molto probabilmente dovrai copiare temporaneamente il locale se devi eseguire il debug in uno di quegli assembly.

Puoi leggere il mio articolo su come utilizzare una DLL a livello globale senza GAC. Non mi piace molto il GAC principalmente perché impedisce la distribuzione di xcopy e non attiva un riavvio automatico sulle applicazioni.

http://nbaked.wordpress.com/2010/03/28/gac-alternative/


0

Impostare CopyLocal = false ridurrà il tempo di compilazione, ma può causare diversi problemi durante il tempo di distribuzione.

Esistono molti scenari in cui è necessario lasciare "Copia locale" su True, ad esempio progetti di primo livello, dipendenze di secondo livello, DLL chiamate per riflessione.

La mia esperienza con l'impostazione di CopyLocal = false non ha avuto successo. Vedere il riepilogo dei pro e dei contro nel mio post sul blog "NON modificare i riferimenti del progetto" Copia locale "in falso, a meno che non si comprendano le sottosequenze."

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.