强化遗留Rails应用程序的第一步是什么



有一个生产系统已经运行了很多年,最初是作为PHP应用程序,后来是与Rails的混合,现在完全在Rails中。目前尚不清楚它已经存在了多久。最古老的git提交来自5年前。

目标是不惜一切代价保持系统运行。只要没有任何中断,我们使用什么代码都无关紧要。目前它是Rails版本3.2.33

如果我们不升级任何宝石,我们就有可能变得过时和无法部署。如果我们升级,我们将需要对代码进行更改,从而导致潜在的错误悄悄出现。我们不仅会面临代码腐烂,还会因AWS停机而停机。

确保没有损坏的第一步是什么?我花了几个月的时间编写黄瓜(集成)测试,但很难涵盖每一个边缘案例。该应用程序运行了很长时间,大多数错误都已修复,几乎没有新的异常。测试从一开始就不是一个优先事项,所以大多数代码都没有文档记录。

老实说,我发现RubyonRails不适合这种应用程序。Ruby和Rails都有一个非常激进的发布时间表,Rails尤其不怕放弃向后兼容性。Rails非常适合敏捷开发,在敏捷开发中,事情总是在变化,但要以长期稳定性为代价。

我假设你的应用程序足够大,你不想切换到其他任何东西。例如,Sinatra不会有太大的变化,它将是一个更加稳定的选择。

如果你坚持使用Rails,我建议你尽可能多地去掉gem依赖项。总有一种危险,即它们将不再被开发,或者它们可能会引入错误或漏洞。

此外,尽可能多地支持PORO(普通的旧Ruby对象)而不是依赖Rails的代码也是一个好主意。它通常需要更多的工作,但最终会得到更稳定和可重用的代码。

我意识到这可能比你想在这样的应用程序中投入更多的工作,但这是我最好的建议。

第一步是为gem文件中使用的所有gem设置特定的gem版本。

对于exmaple

 gem 'rspec-rails'

可能成为

 gem 'rspec-rails', '2.14.1'

您可以通过查看Gemfile.lock来了解当前使用的版本,例如,Gemfile.lock中的这一行显示了为rspec:选择的版本

rspec (2.14.1)

即使Gemfile没有版本,例如

gem chronic

Gemfile使用的版本,例如

chronic (0.10.2)

如果我们不升级任何宝石,我们就有可能变得过时和无法部署。如果我们升级,我们将需要对代码进行更改,从而导致潜在的错误潜入。

是的,这就是你的困境。没有任何魔法,你必须从这两个优先事项中选择哪一个。正如aNoble所指出的,RoR不是一个可以"原地踏步"的框架。组成大多数应用程序的gem的不断变化意味着RoR应用程序不会很好地老化。

你应该向项目所有者解释并重复,重复,重复。通常情况下,这是一种"被接受"的原则,但并非真正被接受,因为同样的问题仍在继续,"尽管如此,我如何升级它,我如何确保没有任何变化或中断,等等。"

如果该应用程序将在几个月后退役,那没问题。如果没有真正的计划来终止应用程序,并且它将继续是业务的重要组成部分,那么你只需要使用资源来维护它。在RoR土地上没有免费午餐。

编写许多测试是关键的第一步,很高兴看到这一点。检查您的语句覆盖范围,看看您是否遗漏了对重要代码区域的测试,并确保您有覆盖关键序列的集成测试。其想法是修改测试,以降低更改导致用户可见失败的风险。

现在在一些系统上设置连续测试。

设置你的Gemfile和.rube版本,这样你就可以具体控制加载的所有版本。这不会自动更新,但它确保您可以控制更新内容。登录Gemfile和Gemfile.lock.

此时,您可以缓慢增加版本号。不要跳过很多版本号——通常最好缓慢升级,这样你就可以看到弃用警告。修复这些,冲洗,重复。

将你的(输入)验证器修改为挑剔的白名单("它必须是这种形式,否则我不会接受")。如果您可以防止坏数据进入您的系统,它更有可能正常工作,通常更难受到攻击。

为了安全起见,可以考虑添加安全阅读器,并将CSP设置为尽可能强大。

开始添加一些静态分析器。Rubocop和Brakeman非常有用。您可能需要将Rubocop配置为只抱怨一些事情,然后慢慢增加他们报告的内容。将所有检查添加到默认的"rake"命令中,这样您就可以键入"rake)"来运行静态分析器和测试套件。

无论你使用什么框架,都没有魔法。人们会犯错误,假装不犯错误是没有帮助的。

CII最佳实践徽章项目可能是一个有用的例子。它使用RoR,我负责。特别是,请参见:*贡献*安全信息(保证案例)

来自捐款:"总的来说,我们尽量积极主动,尽快检测和消除错误和漏洞,并在错误和漏洞发生时减少其影响。我们使用防御设计和编码风格来降低错误的可能性,使用各种工具来尽早检测错误,并使用覆盖率高的自动测试套件。"

最新更新