当前位置: 首页 > 科技观察

第三方库在项目中不是必须的

时间:2023-03-19 13:03:38 科技观察

前言我在Lyft的八年时间里,很多产品经理和工程师经常想在我们的app中加入第三方库。有时需要集成特定的库(如PayPal),有时需要避免开发一些非常复杂的功能,有时只是为了避免重新发明轮子。虽然这些都是合理的考虑,但使用第三方库的风险和相关成本经常被忽视或误解。在某些情况下,风险是值得的,但在决定承担风险之前,首先要能够清楚地定义风险。为了使风险评估更加透明和一致,我们开发了一个流程来衡量我们将其集成到应用程序中的风险有多大。风险包括我们在内的大多数大型组织都将某种形式的代码审查作为其开发实践的一部分。对于这些团队来说,添加一个第三方库就相当于添加了一堆由不属于该团队的成员开发的未经审查的代码。这破坏了团队一直坚持的代码审查原则,交付质量未知的代码。这对应用程序的运行方式、长期开发以及大型团队的整体业务构成风险。运行时风险库代码通常与应用程序具有相同级别的系统资源访问权限,但它们不一定应用团队为管理这些资源而开发的最佳实践。这意味着他们可以访问磁盘、网络、内存、CPU等。线程延迟、下载(和上传!)大量数据等等。更糟糕的是,它们会导致崩溃甚至崩溃循环。两次。其中许多案例直到应用程序已经上线后才被发现,在这种情况下,修复它需要创建一个新版本并通过审查,这通常既费时又费钱。通过一个变量控制是否调用可以在一定程度上控制这种风险,但这种方法并不是万无一失的(见下文)。开发风险引用一位同事的话:“每一行代码都是一种负担”,当涉及到不是您自己编写的代码时更是如此。库适应新技术或API的速度可能很慢,这会阻碍代码开发,或者速度太快,导致版本过度开发。库在采用新技术或API方面可能会很慢,从而阻碍代码库,或者速度太快,导致部署目标过高。每当Apple和Google每年发布新的操作系统版本时,他们通常会要求开发人员使用SDK更改来更新他们的代码,而库开发人员也必须这样做。这需要齐心协力、协调优先事项以及及时完成工作的能力。这将是一个持续的风险,因为移动平台不断变化,团队(成员)也不是一成不变的。当集成库不复存在并且需要更新库时,可能需要花费大量时间来决定由谁来做。事实证明,一旦存货存在,就很少而且很难去除,因此我们将其视为长期维护成本。业务风险正如我上面所说,现代操作系统不区分应用程序代码和库代码,因此除了系统资源之外,它们还可以访问用户信息。作为应用程序开发人员,我们有责任正确使用这些信息,并负责任何第三方库。如果用户授予Lyft应用程序地理定位授权,任何第三方图书馆也将自动获得授权。他们可以将该(地理定位)数据上传到他们自己的服务器、竞争服务器,或者谁知道还有什么地方。当图书馆需要我们没有的权限时,问题就更大了。同样,一个系统的安全取决于它最薄弱的环节,但如果它包含未经审计的代码,那么你就不知道它到底有多安全。行为不当的库可能会破坏您精心设计的安全编码实践。这同样适用于Apple和Google执行的任何政策,例如“您不得跟踪用户”。降低风险在评估库的使用情况(无论是否)时,我们首先会问几个问题以了解对库的需求。我们可以在内部做吗?有时我们只需要简单地粘贴和复制真正需要的东西。在更复杂的情况下,库与自定义后端通信,我们对API进行逆向工程并自己构建一个迷你SDK(同样,只构建我们需要的)。在90%的情况下这是首选,但在与非常特定的供应商或需求集成时并不总是可行。有多少用户从该库中受益?在一个案例中,我们正在考虑添加一个非常危险的库(根据以下标准),旨在为一小部分用户提供服务,同时将我们的所有用户都暴露给该库。对于我们认为会从中受益的一小部分客户,我们冒着给所有用户带来问题的风险。这个库有什么传递依赖?我们还需要为库的所有依赖项评估以下标准。退出标准是什么?如果整合成功,是否有办法将其内部迁移?如果不成功,有没有办法去除它?评估标准如果此时团队仍想集成库,我们会要求他们根据一组标准对库“评分”。下面的列表并不全面,但应该可以很好地说明我们希望看到的内容。阻塞标准这些标准将阻止我们在技术上或公司政策上集成这个库。在进行下一步之前,我们必须解决:deploymenttarget/targetSDKs太高。我们支持过去4年的主流操作系统(版本),所以第三方库至少要支持那么多。许可证不正确/丢失。我们将许可证文件与应用程序捆绑在一起,以确保我们可以合法使用代码并将其归于许可证持有者。没有冲突的传递依赖。库不能具有我们已经包含但具有不同版本的传递依赖项。不显示自己的UI。我们非常注意让我们的产品看起来尽可能统一,定制UI并不能做到公正。它不使用私有API。我们不想冒因使用私有API而拒绝应用程序的风险。主要重点是闭源。访问源代码意味着我们可以选择要包含库的哪些部分,以及源代码如何与应用程序的其余部分捆绑在一起。封闭源代码的二进制发行版对我们来说更难集成。编译时有警告。我们启用了“Warningstreatedaserrors”,带有编译警告的库是库整体(下降)质量的良好指标。糟糕的文档。我们需要高质量的内联文档、外部“操作方法”文档和有意义的变更日志。二进制体积。这个图书馆有多大?有些库提供了很多功能,而我们只需要其中的一小部分。尤其是在无法访问源代码的情况下,往往是全有或全无的情况。外部网络流量。与我们无法控制的上游服务器/端点通信的库可能会在服务器出现故障、错误数据被发回等时导致整个应用程序崩溃。这也是我上面提到的隐私问题。技术支援。当事情无法正常工作时,我们需要能够报告/上报问题,并在合理的时间内解决问题。开源项目通常由志愿者维护,很难有时间表,但至少我们可以自己做出改变。这在闭源项目中是不可能的。无法禁用。虽然大多数库特别要求我们对其进行初始化,但有些库在实例化时更加“活跃”,并且可以在我们不调用它的情况下自行执行工作。这意味着当库出现问题时,我们无法通过函数变量或其他机制将其关闭。我们为所有这些(以及其他一些)标准分配了分数,并要求工程师为他们想要集成的库汇总这些分数。虽然默认情况下不难拒绝低分,但我们经常会要求更多理由继续前进。最后,虽然这个过程看起来非常严格,而且在许多情况下潜在的风险都是假设的,但我们在这篇博文中描述的每个场景都有实际的例子。记录评估并将其公开还有助于将相关风险传达给那些不熟悉移动平台如何工作的人,并证明我们没有随意评估风险。另外,我不想说每个第三方库都天生不好。事实上,我们在Lyft使用了很多:RxSwift和RxJava、Bugsnag的SDK、谷歌地图、Tensorflow,以及一些用于非常具体用例的较小的。但所有这些要么已经过全面审查,要么我们已经确定风险是值得的,并且清楚地了解这些风险和收益的真正含义。最后,作为专业开发人员的提示:始终在库的API之上创建您自己的抽象,永远不要直接调用它们的API。这使得将来更容易替换(或删除)底层库,再次减轻与长期开发相关的一些风险。