Prácticas recomendadas para grandes soluciones en Visual Studio (2008) [cerrado]

87

Tenemos una solución con alrededor de 100 proyectos, la mayoría de ellos C #. Naturalmente, lleva mucho tiempo abrir y construir, por lo que estoy buscando las mejores prácticas para tales bestias. En la línea de preguntas a las que espero obtener respuestas están:

  • ¿Cómo manejas mejor las referencias entre proyectos?
    • ¿Debería estar activado o desactivado "copia local"?
  • si cada proyecto debe compilarse en su propia carpeta, o si todos deben compilarse en la misma carpeta de salida (todos son parte de la misma aplicación)

  • ¿Son las carpetas de soluciones una buena forma de organizar las cosas?

Sé que dividir la solución en varias soluciones más pequeñas es una opción, pero eso viene con su propio conjunto de dolores de cabeza de refactorización y construcción, por lo que tal vez podamos guardar eso para un hilo separado :-)

Eyvind
fuente
2
¿Puedo preguntar por qué una sola solución necesita más de 100 proyectos? ¿Están creando cada uno su propio montaje?
Neil N
1
Sí, lo son, y cada uno de ellos representa una función lógicamente separada.
Eyvind
2
@Eyvind - ¿No son para eso las clases y los espacios de nombres? ¿Qué beneficio le aportan los montajes separados? Puedo pensar en algunas, como actualizaciones potencialmente más pequeñas y uso de memoria (si algunas no están cargadas), pero ciertamente hay un costo por tener más de 100 conjuntos para compilar y administrar.
si618
1
@Mark siento tu dolor. Tenemos hasta 94 proyectos aquí. No se puede hacer mucho al respecto ahora, ya que tendríamos que detener el desarrollo en varios equipos para reestructurarlo. Tenemos 3 proyectos EXE que hacen referencia a los otros 91. Estoy experimentando con una carpeta de salida común, hasta ahora las ganancias son muy impresionantes.
Kevin
2
Hombre, 100+? Eso no es nada para lo que tenemos ... empujando casi 600 aquí ahora ...
C Johnson

Respuestas:

41

Puede que le interesen estos dos artículos de MSBuild que he escrito.

MSBuild: mejores prácticas para crear compilaciones confiables, parte 1

MSBuild: mejores prácticas para crear compilaciones confiables, parte 2

Específicamente, en la Parte 2, hay una sección sobre la construcción de grandes árboles de origen que es posible que desee ver.

Sin embargo, para responder brevemente a sus preguntas aquí:

  • CopyLocal? Seguro que apaga esto
  • ¿Construir en una o varias carpetas de salida? Construir en una carpeta de salida
  • Carpetas de soluciones? Esto es cuestión de gustos.

Sayed Ibrahim Hashimi

My Book: Inside the Microsoft Build Engine: uso de MSBuild y Team Foundation Build

Sayed Ibrahim Hashimi
fuente
Gracias hombre, ¡me aseguraré de comprobarlos!
Eyvind
1
Diré que tengo este libro y es genial. Me ha ayudado a automatizar mis compilaciones de TFS y las compilaciones de desarrolladores locales de manera muy extensa. Ahora estoy trabajando en compilaciones incrementales y el libro profundiza en el tema. Vale el precio. Gracias Sayed. Mantener el buen trabajo.
irperez
Gracias irperez por los comentarios
Sayed Ibrahim Hashimi
2
-1 para recomendación INCONDICIONAL para deshabilitar CopyLocal. Establecer CopyLocal = false puede causar diferentes problemas durante el tiempo de implementación. Consulte la publicación de mi blog "No cambie las referencias del proyecto" Copiar local "a falso, a menos que comprenda las subsecuencias". ( Geekswithblogs.net/mnf/archive/2012/12/09/… )
Michael Freidgeim
¿Podría "construir en una carpeta de salida" causar problemas al compilar con varios subprocesos?
BrunoLM
9

+1 para ahorrar en el uso de carpetas de soluciones para ayudar a organizar las cosas.

+1 para la construcción del proyecto en su propia carpeta. Inicialmente probamos una carpeta de salida común y esto puede conducir a sutiles y dolorosos para encontrar referencias desactualizadas.

FWIW, usamos referencias de proyectos para soluciones, y aunque nuget es probablemente una mejor opción en estos días, hemos descubierto que svn: externals funciona bien tanto para ensamblajes internos de terceros como (tipo marco). Simplemente adquiera el hábito de usar un número de revisión específico en lugar de HEAD al hacer referencia a svn: externals (culpable según los cargos :)

si618
fuente
2
+1 También tengo problemas con la solución de carpeta de salida común. No entendía lo que "las referencias del proyecto para soluciones" significa, por favor explique un poco más ...
Mauricio Scheffer
Como en, usamos VS-> Agregar referencia-> Proyectos, en lugar de VS-> Agregar referencia-> Examinar. Lo sé, pero algunas personas lo hacen de manera diferente (y creo que esto causa más dolores de cabeza). Si observa el texto csproj de MSBuild, verá la propiedad ProjectReference en lugar de Reference.
si618
Interesante respuesta! Creo que hicimos zigzag donde tú hiciste zag. No tenemos carpetas de soluciones y dependemos de la nomenclatura de los proyectos (los proyectos se nombran igual que el espacio de nombres). Toda nuestra salida va a una sola carpeta, lo que hace que la configuración del desarrollador sea mucho más cercana a la de implementación. Si las dependencias están configuradas correctamente, entonces no tenemos referencias desactualizadas.
Thomas Bratt
sí, el directorio de salida común genera muchos problemas, especialmente cuando se usa resharper. Ciertamente referencias desactualizadas.
Florian Doyon
1
@Kevin, han pasado varios años, pero de la memoria un ejemplo son dos proyectos que hacen referencia al mismo ensamblaje, digamos una biblioteca externa que no está referenciada al proyecto. Todo bien cuando están en la misma versión, pero luego sale una nueva versión de esta biblioteca, pero solo un proyecto actualiza su referencia, ¿qué versión se usa en la carpeta de salida común?
si618
8

Descargue proyectos que no usa con frecuencia y compre un SSD. Un SSD no mejora el tiempo de compilación, pero Visual Studio se vuelve dos veces más rápido para abrir / cerrar / compilar.

Nicolas Dorier
fuente
3
Vale la pena señalar que descargar un proyecto es una configuración por usuario, por lo que los desarrolladores de su equipo pueden cargar solo los proyectos que les interesan. Esto realmente ha ayudado a nuestro equipo.
Página
Puede usar la extensión de Solution Load Manager visualstudiogallery.msdn.microsoft.com/… para definir qué no cargar de forma predeterminada
Michael Freidgeim
6

Tenemos un problema similar ya que tenemos 109 proyectos separados de los que tratar. Para responder a las preguntas originales basadas en nuestras experiencias:

1. ¿Cómo maneja mejor las referencias entre proyectos?

Usamos la opción de menú contextual 'agregar referencia'. Si se selecciona 'proyecto', entonces la dependencia se agrega a nuestro archivo de solución global único de forma predeterminada.

2. ¿Debería estar activado o desactivado "copia local"?

Fuera de nuestra experiencia. La copia adicional solo aumenta los tiempos de construcción.

3. ¿Cada proyecto debe compilarse en su propia carpeta o todos deben compilarse en la misma carpeta de salida (todos son parte de la misma aplicación)?

Toda nuestra salida se coloca en una sola carpeta llamada 'bin'. La idea es que esta carpeta sea la misma que cuando se implementa el software. Esto ayuda a prevenir problemas que ocurren cuando la configuración del desarrollador es diferente a la configuración de implementación.

4. ¿Son las carpetas de soluciones una buena forma de organizar las cosas?

No en nuestra experiencia. La estructura de carpetas de una persona es la pesadilla de otra. Las carpetas profundamente anidadas solo aumentan el tiempo que lleva encontrar cualquier cosa. Tenemos una estructura completamente plana, pero los nombres de nuestros archivos de proyecto, ensamblajes y espacios de nombres son los mismos.


Nuestra forma de estructurar proyectos se basa en un único archivo de solución. Construir esto lleva mucho tiempo, incluso si los proyectos en sí no han cambiado. Para ayudar con esto, normalmente creamos otro archivo de solución de 'conjunto de trabajo actual'. Cualquier proyecto en el que estemos trabajando se agrega a esto. Los tiempos de construcción mejoran enormemente, aunque un problema que hemos visto es que Intellisense falla para los tipos definidos en proyectos que no están en el conjunto actual.

Un ejemplo parcial del diseño de nuestra solución:

\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]
Thomas Bratt
fuente
¿Podría "construir en una carpeta de salida" causar problemas al compilar con varios subprocesos?
BrunoLM
4

Trabajamos en un gran proyecto similar aquí. Las carpetas de soluciones han demostrado ser una buena forma de organizar las cosas, y tendemos a dejar la copia local configurada como verdadera. Cada proyecto se crea en su propia carpeta, y luego sabemos que para cada proyecto implementable allí tenemos el subconjunto correcto de los binarios en su lugar.

En cuanto a la apertura del tiempo y la construcción del tiempo, eso será difícil de arreglar sin irrumpir en soluciones más pequeñas. Podrías investigar el paralelismo de la compilación (google "Parallel MS Build" para una forma de hacer esto e integrarse en la IU) para mejorar la velocidad aquí. Además, observe el diseño y vea si refactorizar algunos de sus proyectos para que resulten en menos en general podría ayudar.

David M
fuente
3

En términos de aliviar el problema de la construcción, puede usar la opción "Administrador de configuración ..." para que las compilaciones habiliten o deshabiliten la construcción de proyectos específicos. Puede tener un "Proyecto [n] Compilación" que podría excluir ciertos proyectos y usarlo cuando se oriente a proyectos específicos.

En lo que respecta a los más de 100 proyectos, sé que no quiere que le molesten en esta pregunta sobre los beneficios de reducir el tamaño de su solución, pero creo que no tiene otra opción cuando se trata de acelerar el tiempo de carga (y uso de memoria) de devenv.

Michael Meadows
fuente
Hm, ¿se votó negativamente por estar equivocado o simplemente por no estar de acuerdo? Puedo vivir con el primero si me puedes decir por qué.
Michael Meadows
De acuerdo, no me gusta votar negativamente sin comentarios, así que Michael obtienes mi +1 para equilibrar la ecuación ;-)
si618
2
por cierto, personalmente no me gusta perder el tiempo con la gestión de la configuración para este tipo de cosas. ¿Por qué? porque si confirma accidentalmente su configuración modificada, su servidor de compilación u otros desarrolladores se verán afectados.
si618
Convenido. En realidad, el mismo problema se aplica a las soluciones con demasiados proyectos. :)
Michael Meadows
3

Lo que hago normalmente con esto depende un poco de cómo ocurre realmente el proceso de "depuración". Normalmente, aunque NO configuro la copia local como verdadera. Configuré el directorio de compilación para cada proyecto para generar todo en el punto final deseado.

Por lo tanto, después de cada compilación, tengo una carpeta llena con todos los dll y cualquier aplicación de Windows / web y todos los elementos están en la ubicación adecuada. No era necesario copiar local ya que los dll terminan en el lugar correcto al final.

Nota

Lo anterior funciona para mis soluciones, que normalmente son aplicaciones web y no he experimentado ningún problema con las referencias, ¡pero podría ser posible!

Vendedores de Mitchel
fuente
3

Tenemos un problema similar. Lo resolvemos usando soluciones más pequeñas. Tenemos una solución maestra que lo abre todo. Pero perf. en eso es malo. Por lo tanto, segmentamos las soluciones más pequeñas por tipo de desarrollador. Entonces, los desarrolladores de bases de datos tienen una solución que carga los proyectos que les interesan, los desarrolladores de servicios y los desarrolladores de UI lo mismo. Es raro cuando alguien tiene que abrir la solución completa para hacer lo que necesita en el día a día. No es una panacea, tiene sus ventajas y desventajas. Consulte el "modelo de múltiples soluciones" en este artículo (ignore la parte sobre el uso de VSS :)

JP Alioto
fuente
2

Creo que con soluciones de este tamaño, la mejor práctica debería ser dividirlas. Puede pensar en la "solución" como un lugar para reunir los proyectos necesarios y quizás otras piezas para trabajar en una solución a un problema. Al dividir los más de 100 proyectos en múltiples soluciones especializadas para desarrollar soluciones para solo una parte del problema general, puede lidiar con menos en un momento dado allí, acelerando sus interacciones con los proyectos requeridos y simplificando el dominio del problema.

Cada solución produciría la salida de la que es responsable. Esta salida debe tener información de la versión que se puede configurar en un proceso automatizado. Cuando la salida es estable, puede actualizar las referencias en proyectos y soluciones dependientes con la última distribución interna. Si aún desea ingresar al código y acceder a la fuente, puede hacerlo con el servidor de símbolos de Microsoft que Visual Studio puede usar para permitirle ingresar a ensamblajes referenciados e incluso obtener el código fuente.

El desarrollo simultáneo se puede realizar especificando interfaces por adelantado y simulando los ensamblados en desarrollo mientras espera las dependencias que no están completas pero que desea desarrollar.

Encuentro que esta es una mejor práctica porque no hay límite para cuán complejo puede ser el esfuerzo general cuando lo descompone físicamente de esta manera. Poner todos los proyectos en una sola solución eventualmente alcanzará un límite superior.

Espero que esta información ayude.

Blake Taylor
fuente
2

Tenemos alrededor de 60 proyectos y no usamos archivos de solución. Tenemos una combinación de proyectos C # y VB.Net. La actuación siempre fue un problema. No trabajamos en todos los proyectos al mismo tiempo. Cada desarrollador crea sus propios archivos de solución en función de los proyectos en los que está trabajando. Los archivos de la solución no se registran en nuestro control de código fuente.

Todos los proyectos de biblioteca de clases se construirían en una carpeta CommonBin en la raíz del directorio de origen. Los proyectos ejecutables / web se crean en su carpeta individual.

No utilizamos referencias de proyectos, sino referencias basadas en archivos de la carpeta CommonBin. Escribí una tarea de MSBuild personalizada que inspeccionaría los proyectos y determinaría el orden de compilación.

Hemos estado usando esto durante algunos años y no tenemos ninguna queja.

Vasu Balakrishnan
fuente
3
¿Le importaría compartir su tarea personalizada de msbuild?
andreapier
0

Todo tiene que ver con su definición y visión de lo que son una solución y un proyecto. En mi opinión, una solución es solo eso, una agrupación lógica de proyectos que resuelven un requisito muy específico. Desarrollamos una gran aplicación de Intranet. Cada aplicación dentro de esa Intranet tiene su propia solución, que también puede contener proyectos para exes o servicios de Windows. Y luego tenemos un marco centralizado con cosas como clases base y ayudantes y httphandlers / httpmodules. El marco base es bastante grande y lo utilizan todas las aplicaciones. Al dividir las muchas soluciones de esta manera, se reduce la cantidad de proyectos que requiere una solución, ya que la mayoría de ellos no tienen nada que ver entre sí.

Tener tantos proyectos en una solución es simplemente un mal diseño. No debería haber ninguna razón para tener tantos proyectos bajo una solución. El otro problema que veo es con las referencias de proyectos, que realmente pueden arruinarte eventualmente, especialmente si alguna vez quieres dividir tu solución en otras más pequeñas.

Mi consejo es que haga esto y desarrolle un marco centralizado (su propia implementación de Enterprise Library si lo desea). Puede GAC para compartirlo o puede hacer referencia directamente a la ubicación del archivo para tener un almacén central. También puede utilizar la misma táctica para los objetos comerciales centralizados.

Si desea hacer referencia directamente a la DLL, querrá hacer referencia a ella en su proyecto con copy local false (en algún lugar como c: \ mycompany \ bin \ mycompany.dll). En un tiempo de ejecución, deberá agregar algunas configuraciones a su app.config o web.config para que haga referencia a un archivo que no se encuentra en el contenedor de tiempo de ejecución o GAC. En realidad, no importa si es una copia local o no, o si el dll termina en el contenedor o incluso en el GAC, porque la configuración anulará ambos. Creo que es una mala práctica copiar local y tener un sistema desordenado. Sin embargo, lo más probable es que tenga que copiar local temporalmente si necesita depurar en uno de esos ensamblados.

Puede leer mi artículo sobre cómo usar una DLL a nivel mundial sin el GAC. Realmente no me gusta el GAC principalmente porque evita la implementación de xcopy y no activa un reinicio automático en las aplicaciones.

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

user306031
fuente
0

Establecer CopyLocal = false reducirá el tiempo de compilación, pero puede causar diferentes problemas durante el tiempo de implementación.

Hay muchos escenarios en los que es necesario dejar Copiar local en Verdadero, por ejemplo, proyectos de nivel superior, dependencias de segundo nivel, archivos DLL llamados por reflexión.

Mi experiencia con la configuración de CopyLocal = false no fue exitosa. Consulte el resumen de los pros y los contras en la publicación de mi blog "NO cambie las referencias del proyecto" Copiar local "a falso, a menos que comprenda las subsecuencias".

Michael Freidgeim
fuente