成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

用戶數(shù)十億的iOS超級應(yīng)用,10年代碼變化,你發(fā)現(xiàn)了嗎?

原創(chuàng) 精選
移動開發(fā) iOS
FBiOS架構(gòu)演變到今天,并不是有意為之的。它反映了10年以來的發(fā)展,這是由越來越多的工程師開發(fā)該App所需的技術(shù)決策、穩(wěn)定性以及最重要的用戶體驗所推動的。

?作者 | Dustin Shahidehpour

策劃 | 言征 

iOS版Facebook(FBiOS)可以說是Meta最古老的移動代碼庫了。自2012年該應(yīng)用程序被重寫以來,數(shù)千名工程師對其進(jìn)行了研究,并將其交付給數(shù)十億用戶,它可以支持?jǐn)?shù)百名工程師一次對其進(jìn)行迭代。

FBiOS架構(gòu)演變到今天,并不是有意為之的。它反映了10年以來的發(fā)展,這是由越來越多的工程師開發(fā)該App所需的技術(shù)決策、穩(wěn)定性以及最重要的用戶體驗所推動的。

補(bǔ)充知識:

截止到2022年,該代碼庫已經(jīng)走過了十周年,筆者將對這一演變背后的技術(shù)決策以及它們的歷史背景進(jìn)行一些說明。

經(jīng)過多年的迭代,F(xiàn)acebook代碼庫與典型的iOS代碼庫不同:

(1)它包含了C++、Objective-C(++)和Swift。

(2)它有幾十個動態(tài)加載的庫(dylib),以及太多的類,無法一次將它們加載到Xcode中。

(3)蘋果SDK的原始使用幾乎為零——一切都被內(nèi)部抽象所包裝或替換。

(4)該應(yīng)用程序大量使用代碼生成,這是由我們的自定義構(gòu)建系統(tǒng) Buck 推動的。

(5)如果我們的構(gòu)建系統(tǒng)沒有大量緩存,工程師將不得不花一整天時間等待應(yīng)用程序的構(gòu)建。  

一、2014:建立我們自己的移動框架

2014年,對Facebook應(yīng)用程序進(jìn)行本地重寫已經(jīng)過去兩年,這時,News Feed的代碼庫開始出現(xiàn)可靠性問題。當(dāng)時,News Feed的數(shù)據(jù)模型得到了蘋果管理數(shù)據(jù)模型的默認(rèn)框架:核心數(shù)據(jù)的支持。核心數(shù)據(jù)中的對象是可變的,這并不適合新聞提要的多線程架構(gòu)。更糟糕的是,News Feed利用了雙向數(shù)據(jù)流,這源于它對Cocoa應(yīng)用程序使用了蘋果事實上的設(shè)計模式:模型視圖控制器。

最終,這種設(shè)計加劇了不確定性代碼的產(chǎn)生,這些代碼很難調(diào)試或再現(xiàn)錯誤。很明顯,這種架構(gòu)是不可持續(xù)的,是時候重新思考了。

在考慮新的設(shè)計時,一位工程師研究了React,F(xiàn)acebook的(開源)UI框架,該框架在Javascript社區(qū)中非常流行。React的聲明性設(shè)計抽象了導(dǎo)致Feed(在web上)出現(xiàn)問題的棘手命令式代碼,并利用了單向數(shù)據(jù)流,這使得代碼更易于推理。這些特征似乎很適合News Feed面臨的問題:蘋果的SDK中沒有聲明性UI。

Swift將在幾個月內(nèi)發(fā)布,SwiftUI(蘋果的聲明性UI框架)將在2019年之前發(fā)布。如果NewsFeed想要有一個聲明性UI,那么團(tuán)隊必須構(gòu)建一個新的UI框架。

最終,這就是他們所做的。

在花了幾個月時間構(gòu)建和遷移新聞提要以在新的聲明性UI和新的數(shù)據(jù)模型上運行后,F(xiàn)BiOS的性能提高了50%。

幾個月后,他們開源了基于React的移動UI框架ComponentKit。時至今日,ComponentKit仍然是在Facebook中構(gòu)建本機(jī)UI的事實上的選擇。它通過視圖重用池、視圖展平和背景布局計算為應(yīng)用程序提供了無數(shù)性能改進(jìn)。它也啟發(fā)了其Android對手Litho和SwiftUI。

最終,選擇用自定義infra替換UI和數(shù)據(jù)層是一種權(quán)衡。為了獲得可以可靠維護(hù)的令人愉快的用戶體驗,新員工必須擱置他們對Apple API的行業(yè)知識,學(xué)習(xí)定制的內(nèi)部基礎(chǔ)設(shè)施。

這將不是FBiOS最后一次做出平衡最終用戶體驗與開發(fā)者體驗和速度的決定。進(jìn)入2015年,該應(yīng)用的成功將引發(fā)我們所稱的功能爆炸。這也帶來了一系列獨特的挑戰(zhàn)。

二、2015:架構(gòu)拐點

到2015年,Meta在其“移動第一”的口號上翻了一番,F(xiàn)BiOS代碼庫的每日貢獻(xiàn)者數(shù)量急劇增加。隨著越來越多的產(chǎn)品被集成到應(yīng)用程序中,其發(fā)布時間開始縮短,人們開始注意到。到2015年底,啟動性能非常緩慢(接近30秒!),以至于有可能被手機(jī)的操作系統(tǒng)殺死。

經(jīng)過調(diào)查,很明顯有許多因素導(dǎo)致啟動性能下降。為了簡潔起見,我們將只關(guān)注那些對應(yīng)用程序架構(gòu)有長期影響的方面:

(1)隨著應(yīng)用程序的規(guī)模隨著每種產(chǎn)品的增長而增長,該應(yīng)用程序的“前置”時間正在以無限的速度增長。

(2)該應(yīng)用程序的“模塊”系統(tǒng)為每個產(chǎn)品提供了對該應(yīng)用程序所有資源的無管制訪問。這導(dǎo)致了一個公共問題的悲劇,因為每個產(chǎn)品都利用它的“鉤子”來啟動,以執(zhí)行計算上昂貴的操作,從而快速導(dǎo)航到該產(chǎn)品。

緩解和改善啟動所需的更改將從根本上改變產(chǎn)品工程師為FBiOS編寫代碼的方式。

三、2016年:Dylibs和模塊化

根據(jù)蘋果關(guān)于改進(jìn)發(fā)布時間的維基,在調(diào)用應(yīng)用程序的“主”功能之前,必須執(zhí)行許多操作。通常,一個應(yīng)用程序的代碼越多,所需時間就越長。

雖然“pre-main”在發(fā)布過程中僅貢獻(xiàn)了30秒的一小部分時間,但這是一個特別令人擔(dān)憂的問題,因為隨著FBiOS不斷積累新功能,它將繼續(xù)以無限的速度增長。

為了幫助緩解應(yīng)用程序發(fā)布時間的無限增長,我們的工程師開始將大量產(chǎn)品代碼移入一個稱為動態(tài)庫(dylib)的延遲加載容器中。當(dāng)代碼移動到動態(tài)加載的庫中時,不需要在應(yīng)用程序的main()函數(shù)之前加載。

最初,F(xiàn)BiOS dylib結(jié)構(gòu)如下:

圖片

創(chuàng)建了兩個產(chǎn)品dylib(FBCamera和NotOnStartup),第三個dylib(FBShared)用于在不同的dylib和主應(yīng)用程序的二進(jìn)制文件之間共享代碼。

dylib溶液效果很好。FBiOS能夠抑制應(yīng)用程序啟動時間的無限增長。隨著時間的推移,大多數(shù)代碼都會以dylib結(jié)尾,這樣啟動時的性能就會保持快速,并且不會受到應(yīng)用程序中添加或刪除產(chǎn)品的持續(xù)波動的影響。

dylibs的加入引發(fā)了Meta產(chǎn)品工程師編寫代碼方式的思想轉(zhuǎn)變。隨著dylib的添加,像NSClassFromString()這樣的運行時API冒著運行時失敗的風(fēng)險,因為所需的類存在于卸載的dylib中。由于FBiOS的許多核心抽象都是在遍歷內(nèi)存中的所有類的基礎(chǔ)上構(gòu)建的,因此FBiOS必須重新思考其核心系統(tǒng)的工作情況。

除了運行時失敗之外,dylibs還引入了一類新的鏈接器錯誤。如果Facebook(啟動集)中的代碼引用了dylib中的代碼,工程師將看到如下鏈接器錯誤:

Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_SomeClass", referenced from:
objc-class-ref in libFBSomeLibrary-9032370.a(FBSomeFile.mm.o)

為了解決這個問題,工程師們需要用一個特殊的函數(shù)來包裝他們的代碼,如果需要的話,可以加載dylib,比如:

int main() {
DoSomething(context);
}

看起來像這樣:
int main() {
FBCallFunctionInDylib(
NotOnStatupFramework,
DoSomething,
context
);
}

該解決方案有效,但有很多奇怪的地方:

(1)應(yīng)用程序特定的dylib枚舉被硬編碼到各種調(diào)用站點中。Meta的所有應(yīng)用程序都必須共享一個dylib枚舉,讀者有責(zé)任確定代碼運行的應(yīng)用程序是否使用了該dylib。

(2)如果使用了錯誤的dylib枚舉,代碼將失敗,但僅在運行時失敗。考慮到應(yīng)用程序中大量的代碼和功能,這個延遲的信號導(dǎo)致了開發(fā)過程中的許多挫折。

最重要的是,我們唯一能防止在啟動過程中引入這些調(diào)用的系統(tǒng)是基于運行時的,在應(yīng)用程序引入最后一分鐘的回歸時,許多發(fā)布都被延遲。

最終,dylib優(yōu)化抑制了應(yīng)用程序發(fā)布時間的無限增長,但這意味著應(yīng)用程序架構(gòu)的巨大轉(zhuǎn)折點。FBiOS工程師將在接下來的幾年里重新設(shè)計應(yīng)用程序,以消除dylib帶來的一些粗糙邊緣,我們(最終)推出了一個比以往任何時候都更強(qiáng)大的應(yīng)用程序架構(gòu)。

四、2017:重新思考FBiOS架構(gòu)

隨著dylibs的引入,F(xiàn)BiOS的幾個關(guān)鍵組件需要重新思考:

(1)“模塊注冊系統(tǒng)”不能再基于運行時。

(2)工程師們需要一種方法來了解啟動期間的任何代碼路徑是否會觸發(fā)dylib加載。

(3)為了解決這些問題,F(xiàn)BiOS轉(zhuǎn)向Meta的開源構(gòu)建系統(tǒng)Buck。

在Buck中,每個“目標(biāo)”(app、dylib、library等)都用一些配置聲明,如下所示:

apple_binary(
name = "Facebook",
...
deps = [
":NotOnStartup#shared",
":FBCamera#shared",
],
)

apple_library(
name = "NotOnStartup",
srcs = [
"SomeFile.mm",
],
labels = ["special_label"],
deps = [
":PokesModule",
...
],
)

每個“目標(biāo)”都列出了構(gòu)建它所需的所有信息(依賴項、編譯器標(biāo)志、源等),當(dāng)調(diào)用“buck build”時,它會將所有這些信息構(gòu)建成一個可以查詢的圖形。

$ buck query “deps(:Facebook)
> :NotOnStartup
> :FBCamera

$ buck query “attrfilter(labels, special_label, deps(:Facebook))
> :NotOnStartup

使用這個核心概念(以及一些特殊的醬汁),F(xiàn)BiOS開始生成一些buck查詢,這些查詢可以在構(gòu)建過程中生成應(yīng)用程序中的類和函數(shù)的整體視圖。這些信息將成為該應(yīng)用程序下一代架構(gòu)的基石。

五、2018:生成代碼的激增

既然FBiOS能夠利用Buck查詢依賴關(guān)系中的代碼信息,那么它就可以創(chuàng)建一個“function/classes->dylibs”的映射,可以在運行中生成。

{
"functions": {
"DoSomething": Dylib.NotOnStartup,
...
},
"classes": {
"FBSomeClass": Dylib.SomeOtherOne
}
}

使用該映射作為輸入,F(xiàn)BiOS使用它生成從調(diào)用站點抽象出dylib枚舉的代碼:

static std::unordered_map<const char *, Dylib> functionToDylib {{
{ "DoSomething", Dylib.NotOnStartup },
{ "FBSomeClass", Dylib.SomeOtherOne },
...
}};

左右滑動查看完整代碼

使用代碼生成之所以吸引人,有幾個原因:

(1)因為代碼是基于本地輸入重新生成的,所以沒有什么可簽入的,也沒有更多的合并沖突!考慮到FBiOS的工程規(guī)模每年都會翻倍,這是一個巨大的開發(fā)效率勝利。

(2)不再需要應(yīng)用程序特定的dylib(因此可以重命名為“FBCallFunction”)。相反,調(diào)用將從構(gòu)建期間為每個應(yīng)用程序生成的靜態(tài)映射中讀取。

事實證明,將Buck查詢與代碼生成相結(jié)合是如此成功,以至于FBiOS將其作為新插件系統(tǒng)的基礎(chǔ),最終取代了基于運行時的應(yīng)用程序模塊系統(tǒng)。

1.左移信號

使用Buck支持的插件系統(tǒng)。FBiOS能夠通過將infra遷移到基于插件的架構(gòu)中,以構(gòu)建時警告取代大多數(shù)運行時失敗。

構(gòu)建FBiOS時,Buck可以生成一個圖表,顯示應(yīng)用程序中所有插件的位置,如下所示:

圖片

從這個角度來看,插件系統(tǒng)可以顯示構(gòu)建時間錯誤,以便工程師發(fā)出警告:

(1)“插件D、E可能會觸發(fā)dylib加載。這是不允許的,因為這些插件的調(diào)用方位于應(yīng)用程序的啟動路徑中。”

(2)“應(yīng)用程序中沒有用于呈現(xiàn)配置文件的插件……這意味著導(dǎo)航到該屏幕將無法工作。”

(3)“有兩個插件用于呈現(xiàn)組(插件A、插件B)。其中一個應(yīng)該刪除。”

對于舊的應(yīng)用程序模塊系統(tǒng),這些錯誤將是“懶惰”的運行時斷言。現(xiàn)在,工程師們相信,當(dāng)FBiOS成功構(gòu)建時,它不會因為功能缺失、應(yīng)用程序啟動期間的dylib加載或模塊運行時系統(tǒng)中的不變量而失敗。

2.代碼生成的代價

雖然將FBiOS遷移到插件系統(tǒng)提高了應(yīng)用程序的可靠性,為工程師提供了更快的信號,并使應(yīng)用程序可以與其他移動應(yīng)用程序輕松共享代碼,但這是有代價的:

(1)插件錯誤在Stack Overflow上很難找到答案,調(diào)試時會感到有些吃力。

(2)基于代碼生成和Buck的插件系統(tǒng)與傳統(tǒng)的iOS開發(fā)有著天壤之別。

(3)插件為代碼庫引入了一層中間層。大多數(shù)應(yīng)用程序都會有一個包含所有功能的注冊表文件,這些都是在FBiOS中生成的,很難找到。

毫無疑問,插件使FBiOS遠(yuǎn)離了慣用的iOS開發(fā),但這種權(quán)衡似乎是值得的。我們的工程師可以更改Meta的許多應(yīng)用程序中使用的代碼,并確保如果插件系統(tǒng)運行良好,任何應(yīng)用程序都不會因缺少很少測試的代碼路徑中的功能而崩潰。像News Feed和Groups這樣的團(tuán)隊可以為插件構(gòu)建一個擴(kuò)展點,并確保產(chǎn)品團(tuán)隊可以在不觸及核心代碼的情況下集成到其表面。

六、2020:Swift與語言架構(gòu)

應(yīng)用程序規(guī)模問題導(dǎo)致的架構(gòu)變化上,但蘋果SDK的變化也迫使FBiOS重新考慮其一些架構(gòu)決策。

2020年,F(xiàn)BiOS開始看到來自蘋果的Swift專用API的數(shù)量增加,并且越來越多的人希望在代碼庫中使用更多的Swift。終于是時候接受這樣一個事實了:Swift是FB應(yīng)用程序中不可避免的租戶。

歷史上,F(xiàn)BiOS曾使用C++作為構(gòu)建抽象的杠桿,因為C++的“零開銷”原則,這節(jié)省了代碼大小。但C++尚未與Swift互操作。對于大多數(shù)FBiOS API(如ComponentKit),必須創(chuàng)建某種墊片以在Swift中使用,從而導(dǎo)致代碼膨脹。

下面是一個圖表,概述了代碼庫中的問題:

圖片

考慮到這一點,我們開始形成一種關(guān)于何時何地使用各種代碼的語言策略:

圖片

最終,F(xiàn)BiOS團(tuán)隊開始建議:面向產(chǎn)品的API/代碼不應(yīng)包含C++,這樣我們就可以自由使用蘋果公司的Swift和未來的Swift API。使用插件,F(xiàn)BiOS可以抽象出C++實現(xiàn),這樣它們?nèi)匀粸閼?yīng)用提供動力,但對大多數(shù)工程師來說是隱藏的。

這種類型的工作流意味著FBiOS工程師構(gòu)建抽象的方式發(fā)生了一些變化。自2014年以來,影響框架構(gòu)建中的最大因素是對應(yīng)用程序大小和表現(xiàn)力的貢獻(xiàn)度(這就是為什么ComponentKit選擇Objective-C++而不是Objective-C的原因)。

Swift的引入導(dǎo)致開發(fā)人員的效率降低,不急,未來還能看到更多。

七、2022年:旅程已完成1%

自2014年以來,F(xiàn)BiOS架構(gòu)發(fā)生了很大變化:

(1)它引入了大量內(nèi)部抽象,如ComponentKit和GraphQL。

(2)它使用dylibs將“pre-main”時間保持在最小,并有助于快速啟動應(yīng)用程序。

(3)它引入了一個插件系統(tǒng)(由Buck提供支持),這樣就可以從工程師那里抽象出dylib,因此代碼很容易在應(yīng)用程序之間共享。

(4)它引入了關(guān)于何時何地使用各種語言的語言指南,并開始改變代碼庫以反映這些語言指南。

與此同時,蘋果對其手機(jī)、操作系統(tǒng)和SDK進(jìn)行了令人興奮的改進(jìn):

(1) 他們的新手機(jī)速度很快。裝載成本比以前小得多。

(2) dyld3和鏈修復(fù)等操作系統(tǒng)改進(jìn)提供了軟件,使代碼加載更快。

(3) 他們引入了SwiftUI,這是一個用于UI的聲明性API,它與ComponentKit共享了很多概念。

(4) 他們提供了改進(jìn)的SDK,以及我們可以為其構(gòu)建自定義框架的API(如iOS8中的可中斷動畫)。

隨著Facebook、Messenger、Instagram和WhatsApp分享了更多的體驗,F(xiàn)BiOS正在重新審視所有這些優(yōu)化,以了解在哪些方面可以更接近平臺正統(tǒng)。最終,我們發(fā)現(xiàn),共享代碼的最簡單方法是使用應(yīng)用程序免費提供的東西,或者構(gòu)建一個幾乎無依賴性且可以在所有應(yīng)用程序之間集成的東西。

我們將于2032年在這里與您見面,回顧代碼庫的20周年紀(jì)念!?

責(zé)任編輯:武曉燕 來源: 51CTO技術(shù)棧
相關(guān)推薦

2010-11-04 10:06:27

GSMMTN華為

2024-05-20 08:25:55

2015-07-21 15:35:47

代碼總結(jié)源碼

2014-08-21 14:49:32

MIUI 6

2020-09-01 10:32:52

iOS微信新功能

2022-04-26 06:43:12

文檔TCPLinux

2016-10-24 15:44:15

2022-04-18 07:42:31

配置機(jī)制Spring

2020-08-17 09:30:34

代碼焦點程序員

2015-11-16 14:52:13

代碼程序員

2018-01-24 11:49:34

2018-08-22 09:01:08

2015-01-05 09:56:41

UDPLinux TCP

2020-04-14 15:30:00

微信群管理朋友圈

2012-02-23 13:34:28

2018-07-12 14:03:33

區(qū)塊鏈新零售電子商務(wù)

2011-03-25 15:21:43

2021-01-20 23:40:27

數(shù)據(jù)泄露OpenWRT攻擊

2011-12-18 21:27:29

Android
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产精品中文字幕在线 | 激情福利视频 | 天天综合操 | 国产精品综合色区在线观看 | 久久伊人影院 | 久久免费精品 | 欧美精品一区二区三区四区五区 | 成人一区二区三区在线观看 | 亚洲视频中文字幕 | 欧美中文字幕 | 国产97人人超碰caoprom | 91亚洲国产成人久久精品网站 | 免费看a| 色视频成人在线观看免 | 亚洲一区二区不卡在线观看 | 国产精品一区二区三区在线 | 国产精品美女久久久久久免费 | 韩国电影久久 | 一区二区三区四区毛片 | 9久9久9久女女女九九九一九 | 日韩在线资源 | 日韩av福利在线观看 | 天天操伊人 | 国产成人叼嘿视频在线观看 | 国产四虎| 亚洲精品一区中文字幕乱码 | 二区av| 成人国产一区二区三区精品麻豆 | 国产精品美女一区二区三区 | 国产国拍亚洲精品av | 香蕉久久a毛片 | 亚洲高清在线观看 | 国产精品亚洲综合 | 狠狠操狠狠操 | 国产精品免费一区二区三区四区 | 91最新视频| 黄色大片免费网站 | 97色在线观看免费视频 | 日本中文在线 | 亚洲精品久久久一区二区三区 | 欧美另类视频在线 |