Visual Studio(2008)中大型解决方案的最佳实践

89

我们有一个涉及到100多个项目的解决方案,其中大部分是C#。自然而然地,打开和构建速度都很慢,因此我正在寻找这类庞大项目的最佳实践。希望得到回答的问题如下:

  • 如何处理项目之间的引用最佳
    • "拷贝本地"应该打开还是关闭?
  • 每个项目是否应该构建到自己的文件夹中,还是它们都构建到同一个输出文件夹中(它们都是同一个应用程序的一部分)?

  • 解决方案的文件夹是组织东西的好方法吗?

我知道将解决方案拆分为多个较小的解决方案是一种选择,但这会带来自己的重构和构建困难,因此也许我们可以将其保留到另一个主题中 :-)


2
我可以问一下为什么一个单一的解决方案需要100多个项目吗?它们每个都在创建自己的程序集吗? - Neil N
1
是的,它们是独立的,每个模块代表一个逻辑上单独的功能块。 - Eyvind
2
@Eyvind - 难道这不是类和命名空间的作用吗?分离的程序集给你带来了什么好处?我可以想到一些,比如可能更小的升级和内存使用(如果没有加载某些程序集),但是编译和管理100多个程序集肯定会有成本。 - si618
1
@Mark 我感同身受。我们这里已经有94个项目了。现在我们无法做太多事情,因为我们必须停止多个团队的开发来进行重组。我们有3个EXE项目引用了其他91个项目。我正在尝试使用一个共同的输出文件夹,到目前为止收益非常显著。 - Kevin
2
哥们,100+?这对于我们来说算不了什么...我们现在已经接近600了... - C.J.
显示剩余3条评论
12个回答

43

您可能会对我撰写的这两篇有关MSBuild的文章感兴趣。

MSBuild:创建可靠构建的最佳实践,第1部分

MSBuild:创建可靠构建的最佳实践,第2部分

特别是在第2部分中,有一个名为构建大型源树的部分,您可能想要查看一下。

但在这里简要回答您的问题:

  • CopyLocal?肯定要关闭
  • 构建到一个或多个输出文件夹?构建到一个输出文件夹
  • 解决方案文件夹?这是个人口味问题。

Sayed Ibrahim Hashimi

我的书: 深入了解Microsoft Build Engine:使用MSBuild和Team Foundation Build


谢谢,我一定会去看看的! - Eyvind
1
我要说我有这本书,它非常棒。它帮助我广泛地自动化了我的TFS构建和本地开发构建。现在我正在研究增量构建,这本书深入探讨了这个主题。物有所值。谢谢Sayed。继续保持良好的工作。 - irperez
感谢irperez的评论。 - Sayed Ibrahim Hashimi
2
禁止无条件建议禁用CopyLocal。将CopyLocal=false设置可能会在部署期间引起不同的问题。请参阅我的博客文章“除非理解后果,否则不要将”Copy Local“项目引用更改为false。”(http://geekswithblogs.net/mnf/archive/2012/12/09/do-not-change-copy-local-project-references-to-false-unless.aspx) - Michael Freidgeim
“将构建到一个输出文件夹”在使用多线程编译时会引起问题吗? - BrunoLM
或者,如果您的解决方案包含多个“顶级”构建 - 例如共享许多库的网站或可执行文件 - 这些构建是独立部署的呢?(当然 - 这可能是解决方案拆分的情况,但假设此时不可能进行拆分)将编译到单个输出目录中是不可行的。那么建议是:对于库,CopyLocal应该为“False”,但对于这些“顶级”项目,应该保留为“True”吗? - fourpastmidnight

9

对于使用解决方案文件夹来帮助组织内容的节约使用,我给予赞同。

对于项目构建到其自己的文件夹中,我也给予赞同。我们最初尝试了一个共同的输出文件夹,但这可能会导致难以发现的过时引用问题。

顺便说一下,我们在解决方案中使用项目引用,虽然现在nuget可能是更好的选择,但我们发现svn:externals对于第三方和内部程序集(框架类型)都很有效。只需养成使用特定修订号而不是HEAD引用svn:externals的习惯即可(我承认有罪:)


2
+1 我也遇到了常见的输出文件夹问题。我不明白“解决方案的项目引用”是什么意思,请再解释一下... - Mauricio Scheffer
就像我们使用VS->添加引用->项目,而不是VS->添加引用->浏览。我知道这只是一个小点,但有些人会以不同的方式做(我认为这会引起更多的问题)。如果你查看MSBuild csproj文本,你将看到ProjectReference属性,而不是Reference。 - si618
有趣的回答!我认为我们在你反向移动时走曲线。我们根本没有解决方案文件夹,而是依赖于项目命名(项目的名称与命名空间相同)。我们的所有输出都放在一个单独的文件夹中,这使得开发人员的设置更接近部署设置。如果依赖项设置正确,那么我们就不会有过时的引用。 - Thomas Bratt
哎,通用的输出目录会带来很多痛苦,特别是在使用resharper时。确实会出现过时的引用。 - Florian Doyon
如果您在项目引用中使用此功能,共享输出文件夹的问题并不是很清楚。 - Kevin
1
@Kevin,虽然已经过去了几年,但是从记忆中可以举一个例子:两个项目引用同一个程序集,比如一个未被项目引用的外部库。当它们使用相同版本时一切正常,但是当这个库有新版本发布时,只有一个项目更新了引用,那么在共同的输出文件夹中会使用哪个版本呢? - si618

8

卸载不常用的项目,并购买固态硬盘。固态硬盘不能提高编译时间,但是Visual Studio打开/关闭/构建速度会快两倍。


3
值得注意的是,卸载项目是每个用户的设置,因此您团队中的开发人员可以仅加载他们关心的项目。这确实帮助了我们的团队。 - Page
你可以使用“解决方案加载管理器扩展”(http://visualstudiogallery.msdn.microsoft.com/66350dbe-ed01-4120-bea2-5564eff7b0b2)来定义默认情况下不加载的内容。 - Michael Freidgeim

6
我们有一个类似的问题,需要处理109个单独的项目。根据我们的经验回答以下原始问题: 1. 如何最好地处理项目之间的引用? 我们使用“添加引用”上下文菜单选项。如果选择了“项目”,则默认将依赖项添加到我们的单个全局解决方案文件中。 2. “复制本地”应该开启还是关闭? 根据我们的经验,关闭。额外的复制只会增加构建时间。 3. 每个项目都应该构建到自己的文件夹中,还是它们都应该构建到同一个输出文件夹中(它们都是同一个应用程序的一部分)? 我们所有的输出都放在一个名为“bin”的单个文件夹中。这样做的想法是这个文件夹与软件部署时相同。这有助于防止开发者设置与部署设置不同而导致的问题。 4. 解决方案文件夹是组织东西的好方法吗? 根据我们的经验,不是。一个人的文件夹结构可能是另一个人的噩梦。深度嵌套的文件夹只会增加查找任何内容所需的时间。我们完全采用扁平结构,但是将项目文件、程序集和命名空间命名相同。
我们构建项目的方式依赖于一个单一的解决方案文件。即使项目本身没有改变,构建这个文件也需要很长时间。为了解决这个问题,我们通常创建另一个“当前工作集”解决方案文件。我们正在处理的任何项目都会被添加到其中。构建时间大大缩短,尽管我们遇到的一个问题是Intellisense无法识别当前集中未定义的类型。
我们解决方案布局的部分示例:
\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]

“将构建到一个输出文件夹”在使用多线程编译时会引起问题吗? - BrunoLM

4
我们这里正在进行一个类似的大型项目。解决方案文件夹被证明是一种很好的组织方式,我们倾向于将“复制本地”设置为true。每个项目都会构建到自己的文件夹中,然后我们就知道每个可部署项目中需要正确的二进制文件子集。
至于打开时间和构建时间,除非将其分解成较小的解决方案,否则很难修复。您可以调查并行构建(谷歌“Parallel MS Build”以了解如何执行此操作并将其集成到UI中)以提高速度。此外,查看设计并查看是否重构一些项目以减少总体数量可能会有所帮助。

3

在缓解项目构建问题方面,您可以使用“配置管理器...”选项来启用或禁用特定项目的构建。您可以创建一个“项目[n]构建”,其中排除某些项目,并在针对特定项目时使用此功能。

至于100多个项目,我知道您不想在这个问题上讨论减少解决方案大小的好处,但是我认为当涉及到加快devenv的加载时间(和内存使用)时,您别无选择。


嗯,这个被踩是因为错误还是不同意?如果你能告诉我原因,我可以接受前者。 - Michael Meadows
同意,我不喜欢没有评论就给负评,所以 Michael,你得到我的 +1 来平衡方程式;-) - si618
2
顺便说一句,我个人不喜欢在这种情况下搞配置管理。为什么?因为如果你意外提交了修改后的配置,那么你的构建服务器或其他开发人员将会受到影响。 - si618
同意。实际上,对于有太多项目的解决方案也存在同样的问题。 :) - Michael Meadows

3

我通常会根据"debug"过程的实际情况来处理这个问题。但通常情况下,我不会将复制本地设置为true。我会为每个项目设置构建目录,将所有内容输出到所需的终点。

因此,在每次构建之后,我都会有一个填充好的文件夹,其中包含所有的dll和任何Windows/Web应用程序,并且所有项目都在正确的位置上。由于dll最终会出现在正确的位置上,因此不需要复制本地。

注意:

以上方法适用于我的解决方案,通常是Web应用程序,我没有遇到任何引用问题,但这可能是可能存在的!


3
我们有类似的问题。我们使用较小的解决方案来解决它。我们有一个主解决方案,可以打开所有内容。但性能不佳。因此,我们通过开发人员类型将较小的解决方案分段。因此,DB开发人员有一个加载他们关心的项目的解决方案,服务开发人员和UI开发人员也是如此。在日常工作中,很少有人需要打开整个解决方案来完成所需工作。这并非万能之策 - 它有其优缺点。请参见“多解决方案模型”在本文中(忽略使用VSS的部分 :)

2
我们有60多个项目,并且不使用解决方案文件。我们有C#和VB.net项目的混合。性能一直是一个问题。我们不会同时处理所有项目。每个开发人员根据他们正在处理的项目创建自己的解决方案文件。这些解决方案文件没有被检入我们的源代码控制系统。
所有的类库项目都会构建到源代码目录根目录下的CommonBin文件夹中。可执行文件或Web项目则构建到它们各自的文件夹中。
我们不使用项目引用,而是使用基于CommonBin文件夹的文件引用。我编写了一个自定义MSBuild任务来检查项目并确定构建顺序。
我们已经使用了几年,没有任何抱怨。

3
你介意分享你的自定义msbuild任务吗? - andreapier

2
我认为对于如此大的解决方案,最佳实践是将其分解成若干部分。您可以将“解决方案”视为一个地方,汇集必要的项目和其他元素,以便解决问题。通过将 100 多个项目分成多个专门针对整体问题的一部分开发解决方案,您可以在给定时间内处理较少的内容,从而加速与所需项目的交互并简化问题域。
每个解决方案都会生成其负责的输出。这个输出应该有版本信息,可以在自动化过程中设置。当输出稳定后,您可以使用最新的内部分发更新依赖项目和解决方案中的引用。如果您仍然想进入代码并访问源代码,实际上可以使用 Microsoft 符号服务器,Visual Studio 可以使用它允许您进入引用的程序集甚至获取源代码。
通过预先指定接口并模拟正在等待不完整但您希望针对其进行开发的依赖项的组件,可以同时进行开发。
我认为这是最佳实践,因为当您以这种方式物理地分解时,整体工作的复杂度是没有限制的。将所有项目放在单个解决方案中最终会达到一个上限。
希望这些信息能够帮助到您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接