24

更新:
这是我访问量最大的问题之一,但我仍然没有真正为我的项目找到令人满意的解决方案。我在另一个问题的答案中读到的一个想法是创建一个工具,该工具可以为您从列表中选择的项目“即时”构建解决方案。不过,我还没有尝试过。


如何构建一个非常大的应用程序?

  • 一个大型解决方案中的多个小型项目/组件?
  • 几个大项目?
  • 每个项目一个解决方案?

以及在没有一种解决方案的情况下如何管理依赖项。注意:我正在寻找基于经验的建议,而不是您在 Google 上找到的答案(我可以自己做)。

我目前正在开发一个应用程序,它有超过 80 个 dll,每个都有自己的解决方案。管理依赖项几乎是一项全职工作。有一个自定义的内部“源代码控制”,添加了用于在各处复制依赖 dll 的功能。对我来说似乎是一个次优的解决方案,但有更好的方法吗?我担心,在实践中处理一个包含 80 个项目的解决方案会非常困难。

(上下文:winforms,而不是 web)

编辑:(如果您认为这是一个不同的问题,请给我留言)

在我看来,以下之间存在相互依赖关系:

  • 应用程序的项目/解决方案结构
  • 文件夹/文件结构
  • 源代码控制的分支结构(如果使用分支)

但是,如果可能的话,我很难将它们分开来单独考虑。

我在这里问了另一个相关的问题。

4

9 回答 9

5

源代码控制

我们有 20 或 30 个项目被构建到 4 或 5 个离散解决方案中。我们正在为 SCM 使用 Subversion。

1) 我们在 SVN 中有一棵树,其中包含按名称空间和项目名称逻辑组织的所有项目。根目录中有一个 .sln 可以构建它们,但这不是必需的。

2) 对于每个实际解决方案,我们在 SVN 中都有一个新的 trunks 文件夹,其中包含 SVN:对所有必需项目的外部引用,以便它们从主树下的位置更新。

3) 在每个解决方案中是 .sln 文件加上一些其他必需的文件,以及该解决方案独有且不跨解决方案共享的任何代码。

拥有许多较小的项目有时会有点痛苦(例如,TortoiseSVN 更新消息会被所有这些外部链接弄乱)但确实具有不允许循环依赖的巨大优势,因此我们的 UI 项目依赖于 BO项目,但 BO 项目不能引用 UI(也不应该!)。

架构 我们已经完全切换到使用MS SCSF 和 CAB 企业模式来管理我们的各种项目在 Win Forms 界面中组合和交互的方式。我不确定你是否有同样的问题(多个模块需要在一个通用表单环境中共享空间),但如果你这样做了,那么这很可能会给你如何构建和组装你的解决方案带来一些理智和惯例。

我提到这是因为 SCSF 倾向于将 BO 和 UI 类型的函数合并到同一个模块中,而之前我们保持严格的 3 级策略:

FW - 框架代码。功能与软件相关的代码。BO - 业务对象。其功能与问题域关注点相关的代码。UI - 与 UI 相关的代码。

在那种情况下,依赖关系严格是 UI -> BO -> FW

我们发现即使在使用 SCSF 生成的模块时我们也可以保持这种结构,所以世界上一切都很好:-)

于 2008-09-30T08:07:45.250 回答
2

To manage dependencies, whatever the number of assemblies/namespaces/projects you have, you can have a glance at the tool NDepend.

Personnaly, I foster few large projects, within one or several solutions if needed. I wrote about my motivations to do so here: Benefit from the C# and VB.NET compilers perf

于 2008-10-27T18:12:25.987 回答
1

我认为拥有一个包含所有 80 个项目的解决方案非常重要,即使大多数开发人员大部分时间都使用其他解决方案。根据我的经验,我倾向于使用一个大型解决方案,但为了避免每次按 F5 时都重新构建所有项目的痛苦,我转到解决方案资源管理器,右键单击我现在不感兴趣的项目,并执行“卸载项目”。这样,该项目将保留在解决方案中,但不会花费我任何费用。

话虽如此,80是一个很大的数字。根据这 80 个分解成离散子系统的程度,我还可能创建其他解决方案文件,每个文件都包含一个有意义的子集。这将为我节省大量右键单击/卸载操作的工作量。尽管如此,您将拥有一个大解决方案这一事实意味着始终对它们的相互依赖关系有明确的看法。

在我使用过的所有源代码管理系统中,他们的 VS 集成选择将 .sln 文件置于源代码管理中,除非.sln 文件在源代码管理中,否则许多系统无法正常工作。我觉得这很有趣,因为 .sln 文件曾经被认为是个人的东西,而不是项目范围的东西。我认为唯一一种绝对值得源代码控制的 .sln 文件是包含所有项目的“一个大解决方案”。例如,您可以将其用于自动构建。正如我所说,个人可能会为了方便而创建自己的解决方案,我并不反对那些进入源代码控制的人,但它们对个人比对项目更有意义。

于 2008-09-30T07:26:04.197 回答
1

我认为最好的解决方案是将其分解为更小的解决方案。在我现在工作的公司,我们也有同样的问题;80 个项目++ 在解决方案中。我们所做的是将项目分成几个较小的解决方案。来自其他项目的依赖 dll 被构建并链接到项目中,并与项目一起签入源代码控制系统。它使用更多的磁盘空间,但磁盘很便宜。这样做,我们可以保留项目的版本 1,直到绝对需要升级到版本 1.5。不过,在决定升级到其他版本的 dll 时,您仍然需要添加 dll。谷歌代码上有一个名为TreeFrog的项目这显示了如何构建解决方案和开发树。它还不包含 mush 文档,但我想您可以通过查看结构来了解如何做到这一点。

于 2008-09-30T07:48:26.530 回答
1

我见过的一种很好的方法是拥有一个包含所有项目的大型解决方案,以允许测试项目范围的构建(尽管它太大了,但没有人真正使用它来构建。),然后拥有供开发人员使用的较小项目,其中将各种相关项目组合在一起。

这些确实依赖于其他项目,但除非接口发生变化,或者他们需要更新他们正在使用的 dll 的版本,否则他们可以继续使用较小的项目而不必担心其他一切。因此,他们可以在处理项目时签入项目,然后在其他用户应该开始使用它们时固定它们(在更改版本号之后)。

最后一周一次或两次甚至更频繁地仅使用固定代码重建整个解决方案,从而检查集成是否正常工作,并为测试人员提供一个良好的构建来进行测试。

我们经常发现大段代码不会经常更改,所以一直加载它是没有意义的。(当您从事较小的项目时。)

使用这种方法的另一个优点是在某些情况下,我们有一些功能需要几个月才能完成,通过使用上述方法意味着这可以继续进行而不会中断其他工作流。

我想对此的一个关键标准是在您的解决方案中没有很多交叉依赖关系,如果这样做,这种方法可能不合适,但是如果依赖关系更加有限,那么这可能是要走的路。

于 2008-09-30T08:04:48.330 回答
1

对于我参与过的几个系统,我们为不同的组件提供了不同的解决方案。每个解决方案都有一个通用的输出文件夹(带有调试和发布子文件夹)

我们在解决方案中使用项目引用并在它们之间使用文件引用。每个项目都使用参考路径来定位来自其他解决方案的程序集。我们必须手动编辑 .csproj.user 文件以将 $(Configuration) msbuild 变量添加到引用路径,因为 VS 坚持验证路径。

对于 VS 之外的构建,我编写了 msbuild 脚本,这些脚本递归地识别项目依赖项,从 subversion 中获取它们并构建它们。

于 2009-09-29T05:56:18.637 回答
1

我放弃了项目参考(虽然你的宏听起来很棒),原因如下:

  • 在有时存在依赖项目而有时不存在的不同解决方案之间切换并不容易。
  • 需要能够自行打开项目并构建它,并独立于其他项目进行部署。如果使用项目引用构建,这有时会导致部署问题,因为项目引用导致它寻找特定版本或更高版本,或类似的东西。它限制了交换不同版本依赖项的混合和匹配能力。
  • 此外,我有一些项目指向不同的 .NET Framework 版本,因此真正的项目引用并不总是发生。

(仅供参考,我所做的一切都是针对 VB.NET,所以不确定 C# 的行为是否有任何细微差别)

所以我:

  • 我从全局文件夹(如 C:\GlobalAssemblies)针对解决方案中打开的任何项目以及未打开的项目进行构建
  • 我的持续集成服务器在网络共享上保持最新状态,并且我有一个批处理文件可以将任何新内容同步到我的本地文件夹。
  • 我有另一个本地文件夹,例如 C:\GlobalAssembliesDebug,其中每个项目都有一个后期构建步骤,仅在 DEBUG 模式下将其 bin 文件夹的内容复制到此调试文件夹。
  • 每个项目都将这两个全局文件夹添加到它们的参考路径中。(首先是 C:\GlobalAssembliesDebug,然后是 C:\GlobalAssemblies)。我必须手动将此引用路径添加到 .vbproj 文件,因为 Visual Studio 的 UI 会将它们添加到 .vbprojuser 文件中。
  • 我有一个预构建步骤,如果处于 RELEASE 模式,则从 C:\GlobalAssembliesDebug 中删除内容。
  • 在作为宿主项目的任何项目中,如果有我需要复制的非 dll(输出到我需要的其他项目的 bin 文件夹的文本文件),那么我在该项目上放置一个预构建步骤以将它们复制到宿主项目中。
  • 我必须在解决方案属性中手动指定项目依赖项,才能让它们以正确的顺序构建。

所以,它的作用是:

  • 允许我在任何解决方案中使用项目,而不会弄乱项目引用。
  • Visual Studio 仍然允许我进入解决方案中打开的依赖项项目。
  • 在 DEBUG 模式下,它针对打开的加载项目进行构建。因此,首先它查看 C:\GlobalAssembliesDebug,然后如果不存在,则查看 C:\GlobalAssemblies
  • 在 RELEASE 模式下,由于它会删除 C:\GlobalAssembliesDebug 中的所有内容,因此它只查找 C:\GlobalAssemblies。我想要这样做的原因是,发布的构建不会针对我的解决方案中临时更改的任何内容构建。
  • 无需太多努力即可轻松加载和卸载项目。

当然,它并不完美。调试体验不如项目参考。(不能做诸如“去定义”之类的事情并让它正常工作),以及其他一些古怪的小事情。

无论如何,这就是我试图让事情对我们最有利的地方。

于 2012-02-13T15:26:27.077 回答
0

好的,消化了这些信息,并回答了这个关于项目参考的问题,我目前正在使用这个配置,这似乎“为我工作”:

  • 一个大解决方案,包含应用程序项目和所有依赖组装项目
  • 我保留了所有项目引用,并对一些动态实例化的程序集进行了一些额外的手动依赖项调整(右键单击项目)。
  • 我有三个解决方案文件夹(_Working、Synchronized 和 Xternal)——考虑到我的源代码控制未与 VS(sob)集成,这使我可以在 _Working 和 Synchronized 之间快速拖放项目,这样我就不会迷失方向的变化。XTernal 文件夹用于“属于”同事的程序集。
  • 我为自己创建了一个“WorkingSetOnly”配置(Debug/Release 下拉菜单中的最后一个选项),它允许我限制在 F5/F6 上重建的项目。
  • 就磁盘而言,我将所有项目文件夹都放在几个文件夹之一中(因此只有项目上方的一级分类)
  • 所有项目都构建(dll、pdb 和xml)到相同的输出文件夹,并具有相同的文件夹作为参考路径。(并且所有引用都设置为不复制) - 这让我可以选择从我的解决方案中删除一个项目并轻松切换到文件引用(我有一个宏)。
  • 在与我的“项目”文件夹相同的级别上,我有一个“解决方案”文件夹,我在其中维护一些程序集的单独解决方案 - 以及特定于程序集的测试代码(例如)和文档/设计等。

目前,这种配置对我来说似乎还可以,但最大的考验是尝试将它卖给我的同事,看看它是否能作为一个团队设置飞行。

目前未解决的缺点:

  • 我仍然对单独的组装解决方案有疑问,因为我并不总是想包含所有依赖项目。这会与“主”解决方案产生冲突。我已经(再次)使用一个宏来解决这个问题,该宏将损坏的项目引用转换为文件引用,如果项目被添加回来,则将文件引用恢复为项目引用。
  • 不幸的是,没有办法(到目前为止我发现)将构建配置链接到解决方案文件夹 - 能够说“在这个文件夹中构建所有东西”会很有用 - 就目前而言,我必须手动更新它(痛苦,容易忘记)。(您可以右键单击解决方案文件夹进行构建,但这不能处理 F5 场景)
  • 解决方案文件夹实现中有一个(小)错误,这意味着当您重新打开解决方案时,项目按添加顺序显示,而不是按字母顺序显示。(我已经用 MS 打开了一个错误,显然现在已更正,但我猜是 VS2010)
  • 我不得不卸载CodeRushXPress加载项,因为它会阻塞所有代码,但这是在修改构建配置之前,所以我要再试一次。

总结 - 在问这个问题之前我不知道的事情已经证明是有用的:

  1. 使用解决方案文件夹来组织解决方案而不会弄乱磁盘
  2. 创建构建配置以排除某些项目
  3. 能够手动定义项目之间的依赖关系,即使它们使用文件引用

这是我最受欢迎的问题,所以我希望这个答案对读者有所帮助。我仍然对其他用户的进一步反馈非常感兴趣。

于 2008-11-18T11:14:02.863 回答
0

我们在主分支上的源代码控制上有一个巨大的解决方案。

但是,在项目的较小部分工作的每个开发人员/团队都有自己的分支,其中包含一个解决方案,只需要很少的项目。这样,该解决方案足够小,易于维护,并且不会影响较大解决方案中的其他项目/dll。

但是,这样做有一个条件:解决方案中不应有太多相互关联的项目。

于 2008-09-30T08:43:42.637 回答