代码之家  ›  专栏  ›  技术社区  ›  Ken

Subversion外部是否是反模式?

  •  68
  • Ken  · 技术社区  · 16 年前

    Subversion允许您使用 externals ,允许在项目中轻松控制第三方库软件的版本。

    尽管这些对于重用库和版本控制 vendor software 他们不是没有 their critics :

    请不要使用Subversion Externals(或其他工具中的类似工具),它们是反模式的,因此不必要

    使用外部产品是否存在潜在风险?请解释为什么它们被认为是反模式。

    7 回复  |  直到 12 年前
        1
  •  70
  •   Community CDub    8 年前

    我是这个问题的引语的作者,它来自 previous answer .

    杰森对我这样的简短陈述持怀疑态度,并要求作出解释是正确的。当然,如果我完全解释了答案中的所有内容,我就需要写一本书。

    Mike也正确地指出了 svn:external -类似的特性是,目标源中的更改可能会破坏您自己的源,特别是如果目标源位于您不拥有的存储库中。

    在进一步解释我的评论时,首先让我说有一些“安全”的方法可以使用 外部的 -像特征一样,就像其他工具或特征一样。但是,我把它称为 antipattern 因为这个特性更容易被误用。根据我的经验,它一直被误用,我发现自己不太可能以这种安全的方式使用它,也不建议使用它。请进一步注意,我的意思是不轻视颠覆团队——我喜欢颠覆,尽管我打算搬到集市上。

    这个特性的主要问题是它鼓励并且通常用于将一个构建的源(“项目”)直接链接到另一个构建的源,或者将项目链接到它所依赖的二进制文件(dll、jar等)。这两种用法都不是明智的,它们构成了反模式。

    正如我在另一个答案中所说,我相信软件构建的一个基本原则是每个项目只构建一个二进制或主要的可交付成果。这可以看作是 separation of concerns 到构建过程。对于一个直接引用另一个源的项目来说,这尤其正确,这也违反了 encapsulation . 这种违反的另一种形式是试图通过递归调用子构建来创建构建层次结构来构建整个系统或子系统。Maven强烈鼓励/强制这种行为,这是我不推荐的众多原因之一。

    最后,我发现有很多实际问题使得这个特性不受欢迎。一方面, 外部的 有一些有趣的行为特征(但细节暂时让我无法理解)。另一方面,我总是发现我需要这样的依赖关系对我的项目(构建过程)显式可见,而不是作为一些源代码管理元数据隐藏起来。

    那么,使用这个特性的“安全”方式是什么?我认为只有一个人临时使用它,例如“配置”工作环境的方法。我可以看到程序员可以在存储库中创建自己的文件夹(或为每个程序员创建一个文件夹),在那里他们可以配置 外部的 链接到他们当前正在处理的存储库的其他各个部分。然后,签出该文件夹将创建所有当前项目的工作副本。当添加或完成项目时, 外部的 可以调整定义并适当更新工作副本。但是,我更喜欢一种不绑定到特定源代码管理系统的方法,例如使用调用签出的脚本来执行此操作。

    据记录,我最近一次接触这个问题是在2008年夏天,在一个使用 外部的 在一个巨大的规模上——所有的东西都相互关联,产生一个单一的主工作副本。他们的基于Ant&Jython(用于WebLogic)的构建脚本是在此主工作副本的基础上构建的。最终结果是:没有任何东西可以独立建造,实际上有几十个子项目,但没有一个是安全的,可以自己结帐/工作。因此,在这个系统上的任何工作首先都需要签出/更新超过2GB的文件(它们也将二进制文件放在存储库中)。做任何事情都是徒劳的,我尝试了三个月后就离开了(还有很多其他的反模式存在)。

    编辑:在递归生成上导出-

    多年来(尤其是过去的十年),我为财富500强企业和大型政府机构建立了庞大的系统,涉及数十个子项目,这些子项目按目录层次排列,层次结构很深。我已经使用微软VisualStudio项目/解决方案来组织基于.NET的系统,Ant或Maven 2用于基于Java的系统,并且我已经开始使用基于Python的系统的ditudil和Set UpToice(EasySo安装)。这些系统还包括大型数据库,通常在Oracle或Microsoft SQL Server中。

    为了便于使用和重复性,我成功地设计了这些大型构建。我的设计标准是,新的开发人员可以在他们的第一天出现,获得一个新的工作站(可能直接从戴尔获得,只有一个典型的操作系统安装),获得一个简单的设置文档(通常只有一页安装说明),并且能够完全设置工作站,并从源代码构建完整的系统,无需监督。在半天或更少的时间里。调用构建本身包括打开命令shell、更改到源树的根目录,以及发出一行命令来构建所有内容。

    尽管如此成功,但是构建如此庞大的构建系统需要非常小心并严格遵守可靠的设计原则,就像构建一个庞大的业务关键型应用程序/系统一样。我发现一个关键的部分是每个项目(产生单个工件/可交付成果)必须有一个单独的构建脚本,该脚本必须有一个定义良好的接口(用于调用构建过程部分的命令),并且它必须独立于所有其他(子)项目。历史上,构建整个系统很容易,但仅构建一个系统很难/不可能。直到最近,我才学会了谨慎地确保每个项目真正独立。

    实际上,这意味着必须至少有两层构建脚本。最底层是生成每个可交付结果/工件的项目构建脚本。每个这样的脚本都位于它的项目源代码树的根目录中(实际上,这个脚本定义了它的项目源代码树),这些脚本对源代码管理一无所知,它们希望从命令行运行,它们引用项目中与构建脚本相关的所有内容,并引用它们的外部依赖项(工具r二进制工件,没有其他源项目)基于一些可配置的设置(环境变量、配置文件等)。

    第二层构建脚本也打算从命令行调用,但这些脚本知道源代码管理。实际上,第二层通常是使用项目名称和版本调用的单个脚本,然后它将命名项目的源签出到新的临时目录(可能在命令行上指定)并调用其生成脚本。

    可能需要更多的变化来适应持续集成服务器、多个平台和各种发布场景。

    有时需要第三层脚本来调用第二层脚本(调用第一层),以便构建整个项目集的特定子集。例如,每个开发人员可能都有自己的脚本来构建他们今天正在处理的项目。可能有一个脚本来构建所有东西,以便生成主文档,或者计算度量。

    无论如何,我发现试图将系统视为项目的层次结构是适得其反的。它将项目相互关联,这样它们就不能单独、在任意位置(连续集成服务器上的临时目录)或以任意顺序(假定满足依赖关系)自由构建。通常,试图强制层次结构会破坏任何可能尝试的IDE集成。

    最后,构建一个庞大的项目层次结构可能会过于注重性能。例如,在2007春季期间,我尝试使用Ant构建了一个适度的源层次结构(Java + Oracle),它最终失败了,因为生成总是用Java OutOfMeMyExtExchange中止。这是在一个2 GB的RAM工作站上,具有3.5 GB的交换空间,我已经将JVM调到可以使用所有可用内存的位置。应用程序/系统在代码量方面相对来说是微不足道的,但是递归的构建调用最终耗尽了内存,不管我给它多少内存。当然,它也需要永远执行(30-60分钟是常见的,在它中止之前)。我知道如何很好地调整,但最终我只是超出了工具的限制(Java/Ant在这种情况下)。

    所以帮自己一个忙,把构建构建成独立的项目,然后将它们组成一个完整的系统。保持轻盈灵活。享受。

    编辑:有关反模式的详细信息

    严格地说,反模式是一种常见的解决方案,看起来它解决了问题,但没有解决,要么是因为它留下了重要的空白,要么是因为它引入了额外的问题(通常比原始问题更糟)。解决方案必须包括一个或多个工具以及将它们应用到手头问题的技术。因此,将工具或工具的特定特性称为反模式是一种延伸,人们似乎正在检测并对该延伸作出反应——这是足够公平的。

    另一方面,由于在我们的行业中,关注工具而不是技术似乎是常见的做法,因此引起人们注意的是工具/功能(StackOverflow上对此处问题的随意调查似乎很容易说明)。我的评论和这个问题本身反映了这种做法。

    然而,有时似乎特别有理由这样做,例如在本例中。有些工具似乎会“引导”用户使用特定的技术来应用它们,甚至有些人认为 tools shape thought (稍作修改)。我建议主要是出于这种精神 外部的 是反模式。

    为了更严格地说明这个问题,反模式是设计一个构建解决方案,其中包括在源代码级别将项目绑定在一起,或者隐式地版本化项目之间的依赖关系,或者允许这种依赖关系隐式地更改,因为每种依赖都会引发非常消极的后果。的性质 外部的 -类似的特性使得避免这些负面后果非常困难。

    正确地处理项目之间的依赖关系涉及到解决这些动态和基本问题,并且工具和技术将引领一条不同的道路。应该考虑的一个例子是 Ivy 这在某种程度上有助于马文,但没有许多不利因素。我正在研究IVY,再加上Ant,作为Java构建问题的短期解决方案。从长远来看,我希望将核心概念和特性合并到一个开源工具中,以促进多平台解决方案的实现。

        2
  •  65
  •   Jason Coco superfell    16 年前

    我认为这根本不是反模式。我在谷歌上做了几次快速搜索,基本上什么都没有找到。没有人抱怨使用SVN:外部环境是坏的或有害的。当然,你必须注意一些注意事项……你不应该把它大量地洒在你所有的仓库里…但对于原文,这只是他的个人(和主观)意见。他从来没有真正讨论过SVN:外部性,只是谴责它们是一种反模式。这种没有任何支持或至少没有关于此人如何来发表声明的理由的笼统的声明总是令人怀疑的。

    也就是说,使用外部系统存在一些问题。就像Mike所回答的,它们对于指出已发布软件的稳定分支非常有帮助…尤其是你已经控制的软件。我们在多个实用程序库等项目中内部使用它们。我们有一个小组,它可以增强实用程序库的基础并在上面工作,但是这个基础代码在许多项目中是共享的。我们不希望不同的团队只检查实用程序项目代码,也不希望处理一百万个分支,所以对于我们来说,SVN:Externals工作得很好。对一些人来说,他们可能不是答案。但是,我强烈反对“请不要使用…”的说法,这些工具代表反模式。

        3
  •  19
  •   Mike    16 年前

    使用svn:externals的主要风险是,引用的存储库将以破坏代码或引入安全漏洞的方式进行更改。如果外部存储库也在您的控制之下,那么这可能是可以接受的。

    就个人而言,我只使用svn:externals来指向我拥有的存储库的“稳定”分支。

        4
  •  18
  •   ulty4life    14 年前

    一个旧的线程,但我想解决的问题是,一个变化的外部可能会破坏您的代码。如前所述,这通常是由于外部属性的错误使用造成的。在几乎所有情况下,外部引用都应该指向外部存储库URI中的特定修订号。这样可以确保外部版本永远不会更改,除非您将其更改为指向不同的修订号。

    对于我们的一些内部库(在最终用户项目中用作外部库),我发现在major.minor版本中创建库的标记非常有用,在这个版本中我们不强制进行破坏性的更改。使用四点版本控制方案(major.minor.bugfix.build),我们允许标记与bugfix.build保持最新(同样,不强制中断更改)。这允许我们使用对标签的外部引用,而不使用修订号。在主要或其他中断更改的情况下,将创建一个新标记。

    外部性本身并不坏,但这并不能阻止人们创建它们的糟糕实现。学习如何安全有效地使用它们并不需要太多的研究,只需要阅读一些文档。

        5
  •  9
  •   smoothdeveloper    16 年前

    如果plain external是一个反模式,因为它可能会破坏您的存储库,那么一个有明确修改的应该不会。

    摘录 svn book :

    外部定义是本地目录到URL的映射,可能是版本化资源的特定修订版。

    我认为这一切都取决于你使用这个特性的目的,它本身并不是一个反模式。

        6
  •  8
  •   luapyad    16 年前

    颠覆外部存在明显的缺陷,但我们似乎可以合理地成功地使用它们来包含当前项目所依赖的库(包括我们自己的库和供应商的库)。所以我不认为它们是“反模式”。对我来说,重要的用法是:

    • 它们指向另一个项目的特定修订或标记(而不是标题)。
    • 它们被插入到当前项目中,远离其自身的源代码等(例如,在名为“支持文件”的子目录中)。
    • 它们只引用其他项目的“接口”文件(例如,include文件夹)和二进制库(即,我们无法获得其他项目的完整源代码)。

    我也会对这种安排的任何主要风险和更好的方法感兴趣。

        7
  •  2
  •   Lasse V. Karlsen    16 年前

    A是B 不做 除非你说 为什么? 就是这样。

    我在Subversion中看到的主要缺陷是,在更新工作副本时,不能保证存储库存在。

    可以使用和滥用颠覆外部引用,并且 特征本身 只是那样, 一个特征 . 不能说是 一种模式 也不 反模式 .

    我读过你引述的人的回答,我必须说我不同意。如果您的项目需要存储库中的文件版本XYZ,则外部Subversion引用可以很容易地为您提供该版本。

    是的,您可以通过不具体指定所需引用的版本来错误地使用它。这会给你带来问题吗?很可能!

    它是反模式的吗?嗯,要看情况。如果你遵循你引用的文本作者给出的链接,即。 here 不,那是什么 可以 被用来提供坏的解决方案并不能使整个方法这样做 反模式 . 如果这是规则,那么我会说编程语言大体上是反模式的,因为在每种编程语言中 可能会产生坏的解决方案 .