【问题标题】:How to version-control different features within one web application?如何对一个 Web 应用程序中的不同功能进行版本控制?
【发布时间】:2015-07-24 17:36:25
【问题描述】:

我们有一些网络应用程序,现在这些网站正在升级,不是第一次,但是对于用户和开发者来说,控制版本变得非常困难。

我们有很多客户,其中一些正在运行相同的应用程序,但他们需要支付升级费用。但是,并非所有客户端都为升级付费,因此我们有一些客户端运行一个版本,而另一个客户端运行另一个版本。

我们有两种方法,我们正在研究第三种方法:

  1. 将版本放在路径中,像这样:www\project\version\system-files

但这种方式让一些用户感到困惑,因为对于他们来说,URL变成了:www.website.com/app-version,而当系统升级时,URL会发生变化。

  1. 将版本放入函数中,像这样:function V1_functionX()

当函数需要升级时,我们创建一个新函数,名为V2_functionX。但是,这样创建了一个“胖”的网站,团队在开发过程中犯了一些错误,因为我们没有“一个开发版本”,而是“开发多个版本”,而且有些功能在多个网站中使用。

第一种方式很久以前就被放弃了。我们开发了 Web 应用程序,并“关闭了版本”,所有请求都包含在升级版本中,完成后的版本也被“关闭”。但这太慢了,也进行了更正并部署了“小升级”

我们谈到了另一家公司的方式:他们“关闭”网站以升级系统。这可能是我们的方式。

但是,如果有人有其他想法不关闭网站以升级应用程序,我们很乐意倾听。

注意:这与 SVN 无关。

【问题讨论】:

  • 您是否希望同时维护多个实时版本(可能针对不同的客户)?或者这只是在你的 VCS 中创建不同的功能分支?
  • 在我看来,名为V1_functionX() 的函数是一个重要的警告指标,表明开发方法出现了问题。您能否详细说明为什么要“开发多个版本”?
  • 您还有一个关于在升级网站时不关闭网站的问题 - 这是否相关?有可能,是的 - 广泛地说,您在服务器上的其他地方“构建”网站并运行脚本来修改符号链接。或者您可以在构建过程中修改虚拟主机定义,然后优雅地重启网络服务器。但这可能值得提出自己的问题,因为这是一个很大的话题。
  • 您应该使用诸如 GIT 之类的 VCS ... 每个站点都可以有自己的存储库,并且可以从主存储库“拉”:分支 .. 您现在所做的事情存在严重缺陷,并且会造成几乎不可能的管理和头痛。
  • 感谢您的 cmets。我们的团队有一些担忧,这个问题变得非常有问题。我们有很多客户,运行着不同版本的应用程序。

标签: php architecture system upgrade web-site-project


【解决方案1】:

您说您必须为不同的客户维护不同版本的应用程序。我希望您不需要我告诉您这会显着增加整个系统的复杂性,因此您的首要任务是减少并行维护的版本数量。

API 服务也有同样的问题:提供了具有更多功能的新版本,但需要维护旧版本以给新版本时间来稳定并给用户足够的时间来升级他们的代码。你的困难是相似的。因此,我要问的第一个问题是是否可以只维护两个版本。

如果无法做到这一点,请尝试至少减少并发版本的数量:在必须创建新版本的情况下,您需要鼓励用户从一个版本迁移到另一个版本。 (您说过您不能将您的用户统一到一个版本上,但是如果没有关于您的确切用例的更多信息,就不可能对此提供独立的看法)。因此,也许一种方法是永远不要维护超过五个版本。

您可以采取多种策略来减轻您现有系统的复杂性。首先,考虑将您的代码分成所有版本绝对必须具有的功能“核心”。这对所有版本都是通用的,因此如果您在此处修复错误,所有客户端都会从修复中受益。这可能是可见功能(例如产品编辑屏幕)或框架功能(例如在结帐期间强制使用 SSL)。

然后,您的核心库和特定于客户端的函数可以驻留在一组库中,如下所示:

/project/core
/project/versions/1/Class.php
/project/versions/1.1/Class.php
/project/versions/2/Class.php
/project/versions/2.1.1/Class.php
/project/versions/...

Class.php 当然是一个例子——实际上这里会有很多类文件,每个类文件都正确命名。)

通过这种方式,您不需要调用带有V1_ 前缀的函数,因为这将需要在很多地方复制您的版本选择代码。最好只加载与正确版本相关的库,只要所有版本的函数名称相同,您就可以使用函数名称,而您的库加载器将负责其余的工作。

另一种方法是使用插件,就像 WordPress 一样。在添加插件的地方,它通过添加新的或不同的行为来修改一些核心功能。 “中间件”设计模式在这里可能很有用——Slim 框架(当然还有其他框架)使用这种方法向现有路由处理程序添加调用前或调用后挂钩,从而提供了一种干净的机制来编辑各种现有功能组合。

总而言之,您目前的情况不仅仅是一个管理问题,而且会花费您缓慢的开发时间和额外的调试。虽然上述方法仍然需要降低一些复杂性,但也要考虑:

  • 强制落后的客户升级到您当前支持的版本之一
  • 免费将落后的客户升级到最旧的受支持版本

基于新信息的一些额外想法。我曾考虑将代码拆分到单独的存储库中是否会有所帮助,每个客户一个。但是我想知道是否不能保证他们会这样做;即使您在使用 Composer 或 Git 子模块时提取核心功能,您的最新核心和最早的客户端代码之间仍然存在分歧的可能性。在某些时候,您最糟糕的落后客户会阻碍核心的开发。

您始终可以将此客户端保留在废弃版本上,但如果他们发现了错误,则不值得从您的最新内核向后移植修复程序,因为这会导致您一直在尝试解决所有兼容性问题避免。他们要么升级到适用于最新内核的最低客户端版本(并在必要时付费),要么无限期地容忍这个错误。

您提到每个客户都有自己的数据库。这在一定程度上是有帮助的,因为这意味着客户端版本并不完全受核心强制执行的数据库模式决策的限制。但是,这仍然会对您可以将多少代码移至核心产生连锁反应。

例如,假设您有 7 个客户,其中 6 个客户有一个带有电子邮件地址的用户实体来处理密码更改请求(一个客户有一个没有此字段的用户实体)。这意味着,如果笨拙的模式可能不会改变,核心就不能假设电子邮件地址可用。 (在这种微不足道的情况下,免费升级奇一输出可能会更便宜,以便更多代码可以进入核心,而不是维护诸如版本增强之类的标准东西。

考虑到复杂程度,而且听起来您要长期维护它,我认为您应该设置一些单元和功能测试。您还需要将它们拆分为“核心”和“每个版本”。如果你发现了一个错误,不管它是否是由功能版本控制引起的,写一个失败的测试,然后修复它。然后,您将拥有 - 至少在理论上 - 一种方法来检查更改是否会以您没有想到的方式影响特定客户端的版本。

【讨论】:

  • 对于 OP,我可能会在回答中回答的其他问题:我认为您的代码都在一个存储库中?您是为每个客户端或每个版本维护单独的数据库,还是每个人都在一个数据库上?
  • 感谢您的回答。明天我会再读一遍(巴西是 22 小时 30 分),但我喜欢你所说的“考虑将你的代码分成功能的‘核心’”。
  • 代码在一个存储库中,本地服务器。每个客户都有自己的数据库。
  • 没问题@Ricardo。我又添加了一些想法。
【解决方案2】:

我的工作中有这个:

  1. 本地开发网站(SVN)
  2. 所有开发者测试的开发服务器
  3. 一切正常的预生产
  4. Prod(来自 preprod 的 rsync)

两台服务器之间的 rsync 速度非常快,当我们在不到 5 秒内进行重大更新时

【讨论】:

  • 谢谢,但问题不是“如何更新服务器”,而是“如何给应用程序和项目命名以避免冲突”
  • 还有一个问题,如何处理运行同一应用程序的不同版本的不同客户。
  • 好的,所以我认为它们不是一个好的答案,您所描述的 v1_function,v2_function 更多的是您的应用程序中的权利或选项问题,但您不是另一个版本的您'是应用程序,它就像一个包,当我添加一个新包时,我不会重新安装我的 Debian
猜你喜欢
  • 1970-01-01
  • 2013-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 1970-01-01
  • 2017-06-16
  • 2019-06-14
相关资源
最近更新 更多