Meilleures pratiques pour les grandes solutions dans Visual Studio (2008)

Nous avons une solution avec plus de 100 projets, la plupart d’entre eux C #. Naturellement, il faut beaucoup de temps pour ouvrir et construire, alors je cherche les meilleures pratiques pour de telles bêtes. J’espère avoir des réponses aux questions suivantes:

Je sais que diviser la solution en plusieurs solutions plus petites est une option, mais cela inclut son propre ensemble de problèmes de refactorisation et de construction, alors peut-être pouvons-nous l’enregistrer pour un thread séparé 🙂

Vous pourriez être intéressé par ces deux articles MSBuild que j’ai écrits.

MSBuild: meilleures pratiques pour créer des builds fiables, partie 1

MSBuild: meilleures pratiques pour créer des builds fiables, partie 2

Spécifiquement dans la partie 2, il y a une section Construire de grandes arborescences de sources que vous voudrez peut-être consulter.

Pour répondre brièvement à vos questions ici cependant:

  • CopyLocal? Bien sûr, éteignez ça
  • Construire sur un ou plusieurs dossiers de sortie? Construire dans un dossier de sortie
  • Dossiers de solution? C’est une question de goût.

Sayed Ibrahim Hashimi

My Book: Inside the Microsoft Build Engine: Utilisation de MSBuild et de Team Foundation

+1 pour épargner l’ utilisation des dossiers de solution pour aider à organiser les choses.

+1 pour la construction du projet dans son propre dossier. Nous avons d’abord essayé un dossier de sortie commun, ce qui peut conduire à des références subtiles et douloureuses.

FWIW, nous utilisons des références de projet pour des solutions, et bien que nuget soit probablement un meilleur choix de nos jours, nous avons trouvé svn: externals fonctionnant bien pour les assemblages internes de tiers et de type (framework). Prenez l’habitude d’utiliser un numéro de révision spécifique à la place de HEAD lors du référencement de svn: externals (coupable comme facturé 🙂

Déchargez les projets que vous n’utilisez pas souvent et achetez un SSD. Un SSD n’améliore pas le temps de compilation, mais Visual Studio devient deux fois plus rapide à ouvrir / fermer / construire.

Nous avons un problème similaire car nous avons 109 projets distincts à traiter. Répondre aux questions originales basées sur nos expériences:

1. Comment gérez-vous le mieux les références entre projets

Nous utilisons l’option de menu contextuel “Ajouter une référence”. Si ‘projet’ est sélectionné, alors la dépendance est ajoutée à notre fichier de solution unique et global par défaut.

2. “copie local” doit-il être activé ou désactivé?

Off dans notre expérience. La copie supplémentaire ajoute simplement aux temps de construction.

3. Chaque projet doit-il être créé dans son propre dossier ou doit-il être généré dans le même dossier de sortie (ils font tous partie de la même application)?

Toutes nos sorties sont placées dans un seul dossier appelé «bin». L’idée étant que ce dossier est le même que lorsque le logiciel est déployé. Cela permet d’éviter les problèmes qui surviennent lorsque la configuration du développeur est différente de la configuration du déploiement.

4. Les dossiers de solutions sont-ils un bon moyen d’organiser les choses?

Non dans notre expérience. La structure de dossiers d’une personne est le cauchemar d’un autre. Les dossiers profondément nesteds augmentent simplement le temps nécessaire pour trouver quelque chose. Nous avons une structure complètement plate, mais nommons les fichiers, assemblages et espaces de noms de nos projets.


Notre façon de structurer les projets repose sur un seul fichier de solution. Construire cela prend du temps, même si les projets eux-mêmes n’ont pas changé. Pour vous aider, nous créons généralement un autre fichier de solution «ensemble de travail actuel». Tous les projets sur lesquels nous travaillons y sont ajoutés. Les temps de construction sont considérablement améliorés, bien que l’un des problèmes rencontrés soit que Intellisense échoue pour les types définis dans les projets qui ne sont pas dans l’ensemble actuel.

Un exemple partiel de la mise en page de notre solution:

\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] 

Nous travaillons sur un grand projet similaire ici. Les dossiers de solutions se sont révélés être un bon moyen d’organiser les choses, et nous avons tendance à laisser la copie locale à true. Chaque projet est construit dans son propre dossier, et nous soaps que pour chaque projet déployable, nous avons le sous-ensemble correct des binarys en place.

Pour ce qui est de l’ouverture du temps et de la mise en place du temps, il sera difficile de le résoudre sans casser des solutions plus petites. Vous pouvez étudier la parallélisation de la construction (google “Parallel MS Build” pour une manière de procéder et l’intégration dans l’interface utilisateur) pour améliorer la vitesse ici. De plus, examinez la conception et voyez si la refactorisation de certains de vos projets pour réduire le nombre total de projets pourrait vous aider.

En ce qui concerne le soulagement de la construction, vous pouvez utiliser l’option “Configuration Manager …” pour que les builds activent ou désactivent la construction de projets spécifiques. Vous pouvez avoir un “Projet [n] Build” qui pourrait exclure certains projets et l’utiliser lorsque vous ciblez des projets spécifiques.

En ce qui concerne les plus de 100 projets, je sais que vous ne voulez pas vous poser de questions sur les avantages de réduire la taille de votre solution, mais je pense que vous n’avez pas d’autre option pour accélérer le chargement (et utilisation de la mémoire) de devenv.

Ce que je fais généralement avec cela dépend un peu de la façon dont le processus de “débogage” se produit réellement. En règle générale, je ne mets pas la copie locale pour être vraie. Je configure le répertoire de construction pour chaque projet pour tout sortir au point final souhaité.

Par conséquent, après chaque version, j’ai un dossier rempli avec toutes les DLL et toutes les applications Windows / Web et tous les éléments sont au bon endroit. La copie locale n’était pas nécessaire, car le fichier dll se termine au bon endroit.

Remarque

Ce qui précède fonctionne pour mes solutions, qui sont généralement des applications Web et je n’ai rencontré aucun problème avec les références, mais cela pourrait être possible!

Nous avons un problème similaire. Nous le résolvons en utilisant des solutions plus petites. Nous avons une solution maîtresse qui ouvre tout. Mais perf. sur c’est mauvais. Nous segmentons donc des solutions plus petites par type de développeur. Ainsi, les développeurs de firebase database ont une solution qui charge les projets qui les intéressent, les développeurs de services et les développeurs d’interface utilisateur de la même manière. Il est rare que quelqu’un doive ouvrir la solution complète pour obtenir ce dont il a besoin sur une base quotidienne. Ce n’est pas une panacée – il y a des avantages et des inconvénients. Voir “modèle multi-solution” dans cet article (ignorez la partie concernant l’utilisation de VSS 🙂

Je pense qu’avec des solutions aussi grandes, la meilleure pratique devrait être de les séparer. Vous pouvez penser à la “solution” comme un lieu où rassembler les projets nécessaires et peut-être d’autres éléments pour travailler sur une solution à un problème. En décomposant les plus de 100 projets en plusieurs solutions spécialisées dans le développement de solutions pour une partie seulement du problème, vous pouvez réduire le temps nécessaire en accélérant vos interactions avec les projets requirejs et en simplifiant le domaine problématique.

Chaque solution produirait le résultat dont elle est responsable. Cette sortie doit avoir des informations de version qui peuvent être définies dans un processus automatisé. Lorsque la sortie est stable, vous pouvez mettre à jour les références dans les projets dépendants et les solutions avec la dernière dissortingbution interne. Si vous souhaitez toujours entrer dans le code et accéder à la source, vous pouvez le faire avec le serveur de symboles Microsoft que Visual Studio peut utiliser pour vous permettre d’accéder aux assemblys référencés et même d’extraire le code source.

Le développement simultané peut être effectué en spécifiant les interfaces à l’avance et en simulant les assemblages en cours de développement pendant que vous attendez des dépendances qui ne sont pas complètes, mais que vous souhaitez développer.

Je trouve que c’est une bonne pratique car il n’y a pas de limite à la complexité de l’effort global lorsque vous le décomposez physiquement de cette manière. Mettre tous les projets dans une solution unique atteindra éventuellement une limite supérieure.

J’espère que cette information aide.

Nous avons plus de 60 projets et nous n’utilisons pas de fichiers de solution. Nous avons un mélange de projets C # et VB.Net. La performance a toujours été un problème. Nous ne travaillons pas sur tous les projets en même temps. Chaque développeur crée ses propres fichiers de solution en fonction des projets sur lesquels ils travaillent. Les fichiers de solution ne sont pas vérifiés dans notre contrôle de source.

Tous les projets de bibliothèque de classes seraient générés dans un dossier CommonBin à la racine du répertoire source. Executable / Web Projects construisent dans leur dossier individuel.

Nous n’utilisons pas de références de projet, mais des références basées sur des fichiers du dossier CommonBin. J’ai écrit une tâche MSBuild personnalisée qui inspecterait les projets et déterminerait l’ordre de génération.

Nous l’utilisons depuis quelques années maintenant et n’avons aucune plainte à formuler.

Tout est lié à votre définition et à votre vision de la solution et du projet. Pour moi, une solution est justement cela, un regroupement logique de projets qui résolvent un besoin très spécifique. Nous développons une grande application Intranet. Chaque application de cet intranet possède sa propre solution, qui peut également contenir des projets pour des services exes ou Windows. Et puis nous avons un framework centralisé avec des choses comme les classes de base et les helpers et les httphandlers / httpmodules. Le framework de base est assez volumineux et est utilisé par toutes les applications. En divisant les nombreuses solutions de cette manière, vous réduisez le nombre de projets requirejs par une solution, car la plupart d’entre eux n’ont rien à voir.

Avoir autant de projets dans une solution est une mauvaise conception. Il ne devrait y avoir aucune raison d’avoir autant de projets sous une solution. L’autre problème que je vois est lié aux références de projet, elles peuvent vraiment vous gâcher éventuellement, surtout si vous souhaitez diviser votre solution en plus petites.

Mon conseil est de le faire et de développer un cadre centralisé (votre propre implémentation d’Enterprise Library si vous voulez). Vous pouvez soit le partager avec GAC, soit directement référencer l’emplacement du fichier afin de disposer d’un magasin central. Vous pouvez également utiliser la même tactique pour les objects métier centralisés.

Si vous souhaitez référencer directement la DLL, vous devrez la référencer dans votre projet avec la copie locale false (quelque part comme c: \ mycompany \ bin \ mycompany.dll). Un runtime vous devrez append des parameters à votre app.config ou web.config pour qu’il fasse référence à un fichier qui ne se trouve pas dans le GAC ou le bac d’exécution. En réalité, cela n’a pas d’importance si la copie est locale ou non, ou si la DLL se retrouve dans la corbeille ou même dans le GAC, car la configuration aura priorité sur les deux. Je pense que c’est une mauvaise pratique de copier un système local et d’avoir un système désordonné. Vous devrez probablement copier localement temporairement si vous devez déboguer dans l’un de ces assemblys.

Vous pouvez lire mon article sur l’utilisation globale d’une DLL sans le GAC. Je n’aime pas vraiment le GAC car il empêche le déploiement de xcopy et ne déclenche pas de redémarrage automatique sur les applications.

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

Définir CopyLocal = false réduira le temps de génération, mais peut entraîner différents problèmes lors du déploiement.

Il existe de nombreux scénarios, lorsque vous devez avoir Copy Local ‘laissé à True, par exemple des projets de niveau supérieur, des dépendances de second niveau, des DLL appelées par reflection.

Mon expérience avec la configuration de CopyLocal = false n’a pas réussi. Voir le résumé des avantages et des inconvénients dans mon article de blog “Ne PAS modifier les références de projet” Copie locale “en false, à moins de comprendre les sous-séquences.”