在C#中构造大型Winforms应用程序的项目和依赖项
更新:
这是我的访问量最大的一个问题,但我还没有真正找到了我的项目一个满意的解决方案。我在回答另一个问题时读到的一个想法是创建一个工具,该工具可以为我们从列表中选择的项目"即时"构建解决方案。我还没有尝试过。
我们如何构造一个非常大的应用程序?
- 一个大解决方案中有多个小型项目/装配体?
- 一些大项目?
- 每个项目一个解决方案?
你如何管理在你没有一个解决方案的情况下依赖。
注意:我在寻找基于经验的建议,而不是我们在Google上找到的答案(我可以自己做)。
我目前正在开发一个包含80个dll的应用程序,每个dll都有自己的解决方案。管理依赖项几乎是一项全职工作。有一个自定义的内部"源代码控制",具有添加的功能,可在各处复制依赖项dll。对我来说似乎是次佳的解决方案,但是有更好的方法吗?我担心,在实践中使用80个项目的解决方案在实践中会非常困难。
(上下文:winforms,而不是网络)
编辑:(如果我们认为这是一个不同的问题,请给我评论)
在我看来,以下两者之间存在相互依存关系:
- 应用程序的项目/解决方案结构
- 文件夹/文件结构
- 源代码控制的分支结构(如果使用分支)
但是,即使有可能,我也很难将它们分开来单独考虑。
我在这里问了另一个相关的问题。
解决方案
我认为拥有一个包含所有80个项目的解决方案非常重要,即使大多数开发人员大多数时候都使用其他解决方案也是如此。以我的经验,我倾向于使用一个大型解决方案,但是为了避免每次我按F5时都要重建所有项目的麻烦,我转到解决方案资源管理器,右键单击我现在不感兴趣的项目,并执行"卸载项目"。这样,该项目就可以保留在解决方案中,但不会花我任何钱。
话虽如此,80是一个很大的数字。根据这80个分解成不同的子系统的程度,我可能还会创建其他解决方案文件,每个文件都包含一个有意义的子集。这样可以节省大量右键单击/卸载操作的工作量。但是,我们将拥有一个大的解决方案这一事实意味着,人们始终对它们之间的相互依赖关系持肯定态度。
在我使用过的所有源代码管理系统中,它们的VS集成都选择将.sln文件放入源代码管理中,除非该.sln文件位于源代码管理中,否则许多文件将无法正常工作。我发现这很有趣,因为.sln文件曾经被认为是个人事物,而不是项目范围内的事物。我认为,绝对值得源代码控制的唯一一种.sln文件是包含所有项目的"一个大解决方案"。例如,我们可以将其用于自动构建。就像我说的那样,为了方便起见,个人可能会创建自己的解决方案,我并不反对那些进行源代码控制的人,但是他们对个人比对项目更有意义。
我认为最好的解决方案是将其分解为较小的解决方案。在我目前工作的公司,我们遇到了同样的问题。解决方案中有80个项目++。我们要做的是,将几个较小的解决方案拆分为多个项目,这些项目属于同一项目。构建来自其他项目的依赖dll,并将其链接到该项目,然后与该项目一起签入源代码控制系统。它使用更多的磁盘空间,但磁盘价格便宜。这样,我们就可以保留项目的版本1,直到绝对有必要升级到版本1.5. 但是,当我们决定升级到其他版本的dll时,仍然可以添加dll。谷歌代码上有一个名为TreeFrog的项目,该项目显示了如何构建解决方案和开发树。它还不包含糊糊的文档,但是我想我们可以通过查看结构来了解如何做。
我见过的一种有效的方法是拥有一个包含所有项目的大型解决方案,以允许测试整个项目的构建(尽管规模太大,但没有人真正使用此构建)。较小的项目供开发人员使用,这些项目将各种相关项目组合在一起。
这些在其他项目上确实存在缺陷,但是,除非接口发生更改,或者他们需要更新所使用的dll版本,否则他们可以继续使用较小的项目,而不必担心其他任何事情。
这样,他们可以在处理项目时检入项目,然后在其他用户应开始使用它们时将它们固定(在更改版本号之后)。
最后,每周一次或者两次,甚至更频繁地,仅使用固定代码来重建整个解决方案,从而检查集成是否正常工作,并为测试人员提供一个良好的测试基础。
我们经常发现大量的代码段不会经常更改,因此始终加载它毫无意义。 (当我们处理较小的项目时。)
使用这种方法的另一个优势是,在某些情况下,我们使用上述方法需要花费数月的时间才能完成一些功能,这意味着可以继续进行而不会中断其他工作流。
我猜这的一个关键标准是整个解决方案中没有太多的交叉依赖关系,如果这样做,这种方法可能不合适,但是如果依赖关系受到更多限制,那么这可能就是解决之道。
源代码控制
我们将20或者30个项目构建为4或者5个离散解决方案。我们将Subversion用于SCM。
1)SVN中有一棵树,其中包含按名称空间和项目名称逻辑组织的所有项目。在根目录下有一个.sln可以构建所有文件,但这不是必需的。
2)对于每个实际的解决方案,我们在SVN中都有一个带有SVN的新的trunks文件夹:对所有必需项目的外部引用,以便从主树下的位置对其进行更新。
3)在每个解决方案中都有.sln文件以及一些其他必需文件,以及该解决方案唯一且未在所有解决方案之间共享的任何代码。
拥有许多较小的项目有时会有些痛苦(例如,TortoiseSVN更新消息会弄乱所有这些外部链接),但确实具有巨大的优势,即依赖关系不允许循环,因此我们的UI项目依赖于BO项目,但BO项目不能引用UI(也不能!)。
建筑学
我们已经完全转换为使用MS SCSF和CAB企业模式来管理我们的各个项目在Win Forms界面中组合和交互的方式。我不确定我们是否遇到相同的问题(多个模块需要在一个公共表单环境中共享空间),但是如果这样做,则很可能会给我们设计和组装解决方案的方式带来一些理智和约定。
我提到这是因为SCSF倾向于将BO和UI类型的功能合并到同一个模块中,而以前我们维护了严格的3级策略:
固件框架代码。功能与软件相关的代码。
BO业务对象。其功能与问题域相关的代码。
与UI相关的UI代码。
在这种情况下,依赖关系严格是UI-> BO-> FW
我们发现即使使用SCSF生成的模块,我们也可以维护该结构,因此世界上的一切都很好:-)
在主分支的源代码管理中,我们有一个巨大的解决方案。
但是,每个从事项目较小部分的开发人员/团队都拥有自己的分支,其中包含一个解决方案,只需要很少的项目。这样,该解决方案足够小,可以轻松维护,并且不会影响较大解决方案中的其他项目/ dll。
但是,这样做有一个条件:解决方案中不应有太多相互关联的项目。
要管理依赖项,无论我们拥有多少程序集/名称空间/项目,都可以浏览一下工具NDepend。
就个人而言,我需要一些大型项目,如果需要的话,可以在一个或者多个解决方案中进行。我在这里写下了这样做的动机:受益于Cand VB.NET编译器性能
好,在消化了这些信息,并回答了有关项目引用的问题之后,我目前正在使用此配置,该配置似乎对我有用:
- 一个大的解决方案,包含应用程序项目和所有依赖项组装项目
- 我保留了所有项目引用,并对一些动态实例化的程序集进行了一些额外的手动依赖项调整(在项目上单击鼠标右键)。
- 我有三个解决方案文件夹(_Working,Synchronized和Xternal)-鉴于我的源代码控件未与VS(sob)集成,这使我可以在_Working和Synchronized之间快速拖放项目,因此我不会失去跟踪变化。 XTernal文件夹用于"属于"同事的程序集。
- 我为自己创建了一个" WorkingSetOnly"配置("调试/发布"下拉菜单中的最后一个选项),它使我能够限制在F5 / F6上重建的项目。
- 就磁盘而言,我所有的项目文件夹都在少数几个文件夹之一中(因此,项目上方只有一个分类级别)
- 所有项目都将(dll,pdb和xml)构建到相同的输出文件夹,并且具有与参考路径相同的文件夹。 (并且所有引用都设置为"请勿复制")-这使我可以选择从解决方案中删除项目,然后轻松切换到文件引用(我有一个宏)。
- 与"项目"文件夹位于同一级别,我有一个"解决方案"文件夹,在该文件夹中维护一些程序集的单独解决方案-以及特定于程序集的测试代码(例如)和文档/设计等。
目前,这种配置对我来说还可以,但是最大的考验是尝试将其出售给我的同事,并查看它是否会像一个团队安装一样进行。
当前未解决的缺点:
- 我仍然对单个装配解决方案有疑问,因为我并不总是希望包括所有从属项目。这与"主"解决方案产生了冲突。我已经(再次)使用了一个宏来解决此问题,该宏将损坏的项目引用转换为文件引用,并在添加回项目后将文件引用恢复为项目引用。
- 不幸的是,到目前为止,我还没有办法将"构建配置"链接到解决方案文件夹-能够说"在此文件夹中构建所有内容"会很有用-就目前而言,我必须手动进行更新(痛苦,并且容易忘记)。 (我们可以右键单击"解决方案文件夹"进行构建,但这不能解决F5方案)
- 解决方案文件夹实现中有一个(小)错误,这意味着当我们重新打开解决方案时,项目按添加的顺序显示,而不是按字母顺序显示。 (我已经打开了MS的错误,现在已经纠正了,但是我猜是VS2010)
- 我必须卸载CodeRushXPress加载项,因为它阻塞了所有代码,但这是在修改构建配置之前,因此我将再次尝试。
在问这个问题之前我不知道的摘要事实被证明是有用的:
- 使用解决方案文件夹来组织解决方案而不会弄乱磁盘
- 创建构建配置以排除某些项目
- 能够手动定义项目之间的依赖关系,即使它们正在使用文件引用
这是我最受欢迎的问题,因此希望此答案对读者有所帮助。我仍然对其他用户的进一步反馈非常感兴趣。
对于我工作过的几个系统,我们为不同的组件提供了不同的解决方案。每个解决方案都有一个公共的Output文件夹(带有Debug和Release子文件夹)
我们在解决方案中使用了项目引用,并在它们之间使用了文件引用。每个项目都使用"参考路径"来定位其他解决方案中的程序集。我们必须手动编辑.csproj.user文件,以将$(Configuration)msbuild变量添加到参考路径,因为VS坚持要验证路径。
对于VS之外的构建,我编写了msbuild脚本来递归地标识项目依赖项,从subversion获取它们并进行构建。