forked from SwiftCommunityRes/article-ios
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4820e00
commit 4e3c8da
Showing
4 changed files
with
100 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
|
||
## 前言 | ||
|
||
我在Lyft的八年间,很多产品经理以及工程师经常想往我们 app 里添加第三方库。有时候集成一个特定的库(比如 **PayPal**)是必须的,有时候是避免去开发一些非常复杂的功能,有时候仅仅只是避免c重复造轮子。 | ||
|
||
虽然这些都是合理的考量,但使用第三方库的风险和相关成本往往被忽视或误解。在某些情况下,风险是值得的,但是在决定冒险之前,首先要能够明确的定义风险。为了使风险评估更加的透明和一致,我们制定了一个流程来衡量我们将其集成到app有多大的风险。 | ||
|
||
## 风险 | ||
|
||
大多数大型组织,包括我们,都有某种形式的代码审查,作为开发实践的一部分。对这些团队来说,添加一个第三方库就相当于添加了一堆由不属于团队成员开发,未经审查的代码。这破坏了团队一直坚持的代码审查原则,交付了质量未知的代码。这给app的运行方式以及长期开发带来了风险,对于大型团队而言,更是对整体业务带来了风险。 | ||
|
||
### 运行时风险 | ||
|
||
库代码通常来说,对于系统资源,和app拥有相同级别的访问权限,但它们不一定应用团队为管理这些资源而制定的最佳实践。这意味着它们可以在没有限制的情况下访问磁盘,网络,内存,CPU等等,因此,它们可以(过度)将文件写入磁盘,使用未优化的代码占用内存或CPU,导致死锁或主线程延迟,下载(和上传!)大量数据等等。更糟糕的是他们会导致崩溃,甚至[崩溃循环](https://www.theverge.com/2020/5/7/21250689/facebook-sdk-bug-ios-app-crash-apple-spotify-venmo-tiktok-tinder)。[两次](https://github.com/facebook/facebook-ios-sdk/issues/1427)。 | ||
|
||
其中许多情况直到 app 已经上架才被发现,在这种情况下,修复它需要创建一个新版本,并通过审核,这通常需要大量时间和成本。这种风险可以通过一个变量控制是否调用来进行一定程度的控制,但是这种方法也并非万无一失(看下文)。 | ||
|
||
### 开发风险 | ||
|
||
引用一个同事的话:“每一行代码都是一种负担”,对不是你自己写的代码而言,这句话更甚。库在适配新技术或API时可能很慢,这阻碍了代码开发,或者太快,导致开发的版本过高。 | ||
|
||
库在采用新技术或API时可能很慢,阻碍了代码库,或者太快,导致部署目标太高。每当 Apple 和 Google 每年发布一个新 OS 版本时,他们通常要求开发人员根据SDK的变化更新代码,库开发人员也必须这样做。这需要协调一致的努力、优先事项的一致性以及及时完成工作的能力。 | ||
|
||
随着移动平台的不断变化,以及团队(成员)也不是一成不变,这将会成为一个持续不断的风险。当被集成的库不存在了,而库又需要更新时,会花很多时间来决定谁来做。事实证明一旦一个库存在,就很少也很难被移除,因此我们将其视为长期维护成本。 | ||
|
||
### 商业风险 | ||
|
||
如同我上面所说,现代的操作系统并没有对 app 代码和库代码进行区分,因此除了系统资源之外,它们还可以访问用户信息。作为 app 的开发者,我们负责恰当的使用这部分信息,也需要为任何第三方库负责。 | ||
|
||
如果用户给了 Lyft app 地理位置授权,任何第三方库也将自动得获得授权。他们可以将那些(地理位置)数据上传到自己服务器,竞对服务器,或者谁知道还有什么地方。当一个库需要我们没有的权限时,那问题就更大了。 | ||
|
||
同样,一个系统的安全取决于其最薄弱的环节,但如果其中包含未经审核的代码,那么你就不知道它到底有多安全。你精心设计的安全编码实践可能会被一个行为不当的库所破坏。苹果和谷歌实施的任何政策都是如此,例如“你不得对用户追踪”。 | ||
|
||
## 减少风险 | ||
|
||
当对一个库(是否)进行使用评估时,我们首先要问几个问题,以了解对库的需求。 | ||
|
||
### 我们内部能做么? | ||
|
||
有时候我们只需要简单的粘贴复制真正需要的部分。在更复杂的场景中,库与自定义后端通信,我们对该API进行了逆向,并自己构建了一个迷你SDK(同样,只构建了我们需要的部分)。在90%的情况下,这是首选,但在与非常特定的供应商或需求集成时并不总是可行。 | ||
|
||
### 有多少用户从该库中受益? | ||
|
||
在一种情况下,我们正在考虑添加一个风险很大的库(根据下面的标准),旨在为一小部分用户提供服务,同时将我们的所有用户都暴露在该库中。 对于我们认为会从中受益的一小部分客户,我们冒了为我们所有用户带来问题的风险。 | ||
|
||
### 这个库有什么传递依赖? | ||
|
||
我们还需要评估库的所有依赖项的以下标准。 | ||
|
||
### 退出标准是什么? | ||
|
||
如果集成成功,是否有办法将其转移到内部? 如果不成功,是否有办法删除? | ||
|
||
## 评价标准 | ||
|
||
如果此时团队仍然希望集成库,我们要求他们根据一组标准对库进行“评分”。下面的列表并不全面,但应该能很好地说明我们希望看到的。 | ||
|
||
### 阻断标准 | ||
|
||
这些标准将阻止我们从技术上或者公司政策上集成此库,在进行下一步之前,我们必须解决: | ||
|
||
**过高的** **deployment target/target SDKs。** 我们支持过去4年主流的操作系统(版本),所以第三方库至少也需要支持一样多。 | ||
|
||
**许可证不正确/缺失。** 我们将许可文件与应用捆绑在一起,以确保我们可以合法使用代码并将其归属于许可持有人。 | ||
|
||
**没有冲突的传递依赖关系。** 一个库不能有一个我们已经包含但版本不同的传递依赖项。 | ||
|
||
**不显示它自己的 UI 。** 我们非常小心地使我们的产品看起来尽可能统一,定制用户界面对此不利。 | ||
|
||
**它不使用私有 API 。** 我们不愿意冒 app 因使用私有 API 而被拒绝的风险。 | ||
|
||
### 主要关注点 | ||
|
||
**闭源。** 访问源代码意味着我们可以选择我们想要包含的库的哪些部分,以及如何将该源代码与应用程序的其余部分捆绑在一起。 对于我们来说,一个封闭源代码的二进制发行版更难集成。 | ||
|
||
**编译时有警告。** 我们启用了“警告视为错误”,具有编译警告的库是库整体质量(下降)的良好指示。 | ||
|
||
**糟糕的文档。** 我们希望有高质量的内联文档,外部”如何使用“文档,以及有意义的更新日志。 | ||
|
||
**二进制体积。** 这个库有多大?一些库提供了很多功能,而我们只需要其中的一小部分。尤其是在没有访问源码权限的情况下,这通常是一个全有或全无的情况。 | ||
|
||
**外部的网络流量。** 与我们无法控制的上游服务器/端点通信的库可能会在服务器关闭、错误数据被发回等时关闭整个应用程序。这也与我上面提到的隐私问题相同。 | ||
|
||
**技术支持。** 当事情不能正常工作时,我们需要能够报告/上报问题,并在合理的时间内解决问题。开源项目通常由志愿者维护,也很难有一个时间线,但至少我们可以自己进行修改。这在闭源项目是不可能的。 | ||
|
||
**无法禁用。** 虽然大多数库特别要求我们初始化它,但有些库在实例化时更“主动”,并且在我们不调用它的情况下可以自己执行工作。这意味着当库导致问题时,我们无法通过功能变量或其他机制将其关闭。 | ||
|
||
我们为所有这些(和其他一些)标准分配了点数,并要求工程师为他们想要集成的库汇总这些点数。虽然默认情况下,低分数并不难被拒绝,但我们通常会要求更多的理由来继续前进。 | ||
|
||
## 最后 | ||
|
||
虽然这个过程看起来非常严格,在许多情况下,潜在风险是假设的,但我们有我在这篇博文中描述的每个场景的实际例子。将评估记录下来并公开,也有助于将相对风险传达给不熟悉移动平台工作方式的人,并证明我们没有随意评估风险。 | ||
|
||
此外,我不想声称每一个第三方库本质上都是坏的。事实上,我们在Lyft使用了很多:`RxSwift`和`RxJava`、`Bugsnag`的`SDK`、`Google Maps`、`Tensorflow`,以及一些较小的用于非常特定的用例。但所有这些要么都经过了充分审查,要么我们已经决定风险值得收益,同时对这些风险和收益的真正含义有了清晰的认识。 | ||
|
||
最后,作为一个专业开发人员提示:始终在库的`API`之上创建自己的抽象,不要直接调用它们的`API`。这使得将来替换(或删除)底层库更加容易,再次减轻了与长期开发相关的一些风险。 | ||
|
||
> [译自:Third-party libraries are no party at all](https://scottberrevoets.com/2022/07/15/third-party-libraries-are-no-party-at-all/?utm_source=swiftlee&utm_medium=swiftlee_weekly&utm_campaign=issue_124) |