代码依赖是魔鬼。

您的依赖关系每次都会烧死您。
“变化是唯一不变的……” –赫拉克利特(哲学家)

我们今天用来构建Web应用程序的工具,库和框架与短短几年前所使用的工具,库和框架完全不同。

从现在开始的短短几年中,大多数这些技术将再次发生巨大变化。 但是,我们许多人将这些作为我们应用程序中不可或缺的核心部分。

我们导入,使用和继承月度风格的框架,好像它们将永远存在并且永远不变。 好吧……他们不是。 那是个问题。

经过20多年的开发,设计和架构Web应用程序,我逐渐意识到两个重要的事实:

  1. 外部依赖关系对任何应用程序的长期稳定性和可行性都构成了巨大威胁。
  2. 在没有利用外部依赖的情况下,构建任何类型的非平凡应用程序变得越来越困难,甚至不是不可能。

本文旨在调和这两个真理,以便我们的应用具有最大的长期生存机会。

兔子洞确实很深。

如果我们开始考虑我们的Web应用程序所依赖的所有事物,那么在进入代码之前,很容易想到十几个或更多:

  • 功率
  • 连接性
  • 防火墙功能
  • 域名解析
  • 服务器硬件(CPU,磁盘,Ram等)
  • 冷却
  • 虚拟化平台
  • 集装箱平台
  • 操作系统
  • Web服务器平台
  • 应用服务器平台
  • 网页浏览器

作为开发人员,意识到这些事情是件好事,但是我们对此通常无能为力。 因此,让我们暂时忽略它们,仅谈论代码。

在代码中,存在三种依赖关系:

1.我们控制的依赖性

这是我们或我们的组织编写和拥有的代码。

2.我们无法控制的依赖性

这是由第三方供应商或开源软件社区编写的代码。

3.依赖关系一旦删除

这些是我们的第三方代码依赖关系所依赖的代码依赖关系。 (快说三遍!)

我们将主要讨论我们无法控制的依赖项。

我们控制的依赖项以及一旦删除的依赖项仍然会引起头痛,但是在我们控制的依赖项的情况下,我们应该能够直接进行干预并减轻任何问题。

在删除依赖项的情况下,我们通常可以依靠第三方来为我们处理它,因为它们也依赖于这些依赖项。

为什么第三方代码依赖关系很好

您的Web应用程序中有很大一部分用于解决常见问题:身份验证,授权,数据访问,错误处理,导航,日志记录,加密,显示项目列表,验证表单输入,等等。

无论您使用哪种技术堆栈,都有很大的机会存在针对这些问题的通用解决方案,并且可以作为可以轻松获取并插入到代码库中的库的形式获得。 完全从头开始编写所有这些东西通常是浪费时间。

您想专注于解决不常见问题或以不常见方式解决常见问题的代码。 这就是使您的应用程序变得有价值的原因:仅实现您的应用程序所独有的业务规则的代码-“秘密秘诀”。

Google的搜索和页面排名算法,Facebook的时间线过滤,Netflix的“为您推荐”部分以及数据压缩算法-所有这些功能背后的代码都是“秘密调味料”。

第三方代码(以库的形式)使您可以快速实现应用程序的那些商品化功能,因此您可以专注于“秘密调味料”。

为什么第三方代码依赖性不好

看看过去几年中构建的任何非平凡的Web应用程序,您都会对来自第三方库的实际代码量感到惊讶。 如果这些第三方库中的一个或多个第三方库发生急剧变化,消失或中断怎么办?

如果它是开源的,也许您可​​以自己修复。 但是,您对自己不拥有的该库中的所有代码的理解程度如何? 首先使用库的一个重要原因是无需担心所有细节即可获得代码的好处。 但是现在你被困住了。 您已将自己的命运完全与这些不属于您并且无法控制的依赖项联系在一起。

不用担心,到本文结尾,您将找到新的希望。

也许您认为我是在夸张,或者纯粹从学术角度来说。 让我向您保证-我有数十个示例,这些示例将第三方代码过于紧密地嵌入到他们的应用程序中,从而完全欺骗了自己。 这只是最近的一个例子……

我的一位前客户使用Facebook拥有的后端即服务提供商(称为Parse)构建了他们的应用程序。 他们使用了Parse提供的JavaScript客户端库来使用Parse服务。 在此过程中,他们将所有代码(包括“秘密调味料”代码)紧密耦合到该库。

在我的客户首次推出产品三个月后(正当他们开始吸引真正的付费客户获得良好的吸引力时),Parse宣布将关闭。

现在,我的客户不必专注于迭代他们的产品并扩大他们的客户群,而是不得不弄清楚如何迁移到自托管的开源Parse版本,或者完全替换Parse。

这对于一个刚起步的新应用程序造成的破坏是如此巨大,以至于我的客户最终完全放弃了该应用程序。

平衡好与坏

几年前,我在克服风险的同时保留第三方库好处的首选解决方案是使用适配器模式包装它们。

本质上,您将第三方代码包装在您编写的适配器类或模块中。 然后,这将以您控制的方式公开第三方库的功能。

使用此模式,如果第三方库或框架发生更改或消失,则只需要修复一些适配器代码即可。 应用程序的其余部分保持不变。

来自Dofactory.com的适配器模式图

在纸上听起来不错。 当您具有仅提供一些功能的独立依赖项时,这将可以解决问题。 但是事情很快就会变得丑陋。

您能想象使用任何一个库之前都要包装整个React库(包括JSX)吗? 如何用Java包装jQuery,Angular或Spring框架? 这很快成为一场噩梦。

这些天,我推荐一种更细微的方法……

对于要添加到代码库中的每个依赖项,请通过将两个因素相乘来评估它将引入的风险级别:

  1. 依赖关系将以实质性方式改变的可能性。
  2. 对依赖项进行实质性更改将对您的应用程序造成损害。

当满足以下某些或全部要求时,第三方库或框架就不太可能更改:

  • 它已经存在了几年,并且已经发布了多个主要版本。
  • 它被许多商业应用广泛使用。
  • 它得到了大型组织(最好是家喻户晓的公司或机构)的积极支持。

如果满足以下某些或全部要求,则第三方库或框架对应用程序的损害较小:

  • 它仅在应用程序的一小部分中使用,而不是在整个过程中使用。
  • 依赖于此的代码不属于我之前提到的“秘密调味料”。
  • 删除它只需要对代码库进行最少的更改。
  • 您的整个应用程序很小,可以快速重写。 (请注意这一点-长期以来很少如此。)

风险越大,您越有可能将其包装或完全避免使用。

当涉及真正对应用程序的价值主张至关重要的代码时,您的“秘密武器”就需要对其进行高度保护。 使该代码尽可能独立。 如果您绝对需要使用依赖项,请考虑注入它而不是直接引用它。 即使那样,也要小心。

有时,这意味着对您认为真的很酷的第三方库或由于某种原因而真正要使用的第三方库说“不”。 坚强。 相信我,它将得到回报。 只需问问那些在Angular的第一个发行版中投入大量资金的人,或者我曾在各处使用Parse的前客户。 没意思 相信我。

说到乐趣,看看这个…

TinyTag资源管理器的依赖图

上图是名为TinyTag Explorer的应用程序的依赖图。

为现有应用程序生成依赖关系图是了解依赖关系引入的风险级别的一种好方法。 我整理了一系列免费工具,用于以多种语言(包括JavaScript,C#,Java,PHP和Python)生成类似于上述图形的图形。 你可以在这里得到它。

帮我帮别人

我想通过与他们分享我的知识和经验来为尽可能多的开发人员提供帮助。 请单击下面的❤推荐按钮(绿色的心)为我提供帮助。

最后,不要忘了在这里获取免费的依赖图生成器列表。