第三方庫並不是必須的
我報名參加金石計劃1期挑戰——瓜分10萬獎池,這是我的第4篇文章,點選檢視活動詳情
前言
我在Lyft的八年間,很多產品經理以及工程師經常想往我們 app 裡新增第三方庫。有時候整合一個特定的庫(比如 PayPal)是必須的,有時候是避免去開發一些非常複雜的功能,有時候僅僅只是避免c重複造輪子。
雖然這些都是合理的考量,但使用第三方庫的風險和相關成本往往被忽視或誤解。在某些情況下,風險是值得的,但是在決定冒險之前,首先要能夠明確的定義風險。為了使風險評估更加的透明和一致,我們制定了一個流程來衡量我們將其整合到app有多大的風險。
風險
大多數大型組織,包括我們,都有某種形式的程式碼審查,作為開發實踐的一部分。對這些團隊來說,新增一個第三方庫就相當於添加了一堆由不屬於團隊成員開發,未經審查的程式碼。這破壞了團隊一直堅持的程式碼審查原則,交付了質量未知的程式碼。這給app的執行方式以及長期開發帶來了風險,對於大型團隊而言,更是對整體業務帶來了風險。
執行時風險
庫程式碼通常來說,對於系統資源,和app擁有相同級別的訪問許可權,但它們不一定應用團隊為管理這些資源而制定的最佳實踐。這意味著它們可以在沒有限制的情況下訪問磁碟,網路,記憶體,CPU等等,因此,它們可以(過度)將檔案寫入磁碟,使用未優化的程式碼佔用記憶體或CPU,導致死鎖或主執行緒延遲,下載(和上傳!)大量資料等等。更糟糕的是他們會導致崩潰,甚至崩潰迴圈
其中許多情況直到 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
。這使得將來替換(或刪除)底層庫更加容易,再次減輕了與長期開發相關的一些風險。
- 在 SwiftUI 中建立一個環形 Slider
- Swift 週報 第二十五期
- Swift 週報 第二十四期
- 在 iOS 16 中用 SwiftUI Charts 建立一個折線圖
- Swift 中的 async/await ——程式碼例項詳解
- Swift AsyncSequence — 程式碼例項詳解
- Swift 週報 第十期
- SwiftUI 之 HStack 和 VStack 的切換
- 第三方庫並不是必須的
- Swift 週報 第十二期
- LeetCode - #146 LRU 快取(Top 100)
- LeetCode - #145 二叉樹的後序遍歷
- 現今 Swift 包中的二進位制目標
- LeetCode - #125 驗證迴文串
- 解決 iOS 15 上 APP 莫名其妙地退出登入
- 用 SwiftLint 保持 Swift 風格一致
- TCA - SwiftUI 的救星?(一)
- Swift 中的熱過載
- 在 Swift 中編寫指令碼:Git Hooks
- LeetCode - #124 二叉樹中的最大路徑和(Top 100)