最近這段時(shí)間一直比較忙第献,相對(duì)于之前少了很多的學(xué)習(xí)時(shí)間破加。抽空看幾篇源碼分析的文章俱恶,大多數(shù)都是大同小異的思路,把英文翻譯為中文而已范舀。鑒于關(guān)于介紹如何閱讀開(kāi)源項(xiàng)目的文章比較稀少速那,常言道授人予魚(yú)不如授人予漁。希望這篇文章能夠給準(zhǔn)備閱讀三方源碼的同學(xué)一些啟示尿背。
目的
在閱讀源碼之前最好明確一下閱讀的目的,這樣有助于閱讀的深度和時(shí)間的控制捶惜。比如如果是為了解決項(xiàng)目中的bug田藐,則可以閱讀bug所涉及的部分;如果是為了提高自己的編碼能力吱七,學(xué)習(xí)設(shè)計(jì)技巧汽久,則就需要更為深入的閱讀。
因?yàn)殚喿x源碼其實(shí)是一件非常辛苦的事情踊餐,尤其是分析一些大型開(kāi)源項(xiàng)目的源碼景醇,如果毫無(wú)目的的閱讀會(huì)浪費(fèi)大量的時(shí)間。而且閱讀源碼也是一個(gè)長(zhǎng)期的過(guò)程吝岭,不可能一天分析完Spring源碼的分析三痰,所以在分析源碼之前一定要有一個(gè)明確的認(rèn)識(shí)吧寺,不僅僅只是翻譯英文注釋?zhuān)ù罅康臅r(shí)間是在所難免的。
對(duì)筆者而言閱讀源碼的目的基本上可以分為如下幾種:
- 提高自己的編碼能力散劫,學(xué)習(xí)設(shè)計(jì)思想。
- 解決工作中所用第三方庫(kù)遇到的bug获搏。
- 借鑒開(kāi)源代碼赖条,私有化別人的代碼,完成工作需求常熙。
當(dāng)然不排除某些大神纬乍,讀源碼純粹是了找開(kāi)源代碼漏洞或者想改進(jìn)該項(xiàng)目。畢竟這種牛逼的人是少數(shù)裸卫。當(dāng)我們明確了閱讀的目的就可以大致確定所需要花費(fèi)的時(shí)間及精力了仿贬。
源碼獲取
獲取源碼的地方太多了,最負(fù)有盛名的就是GitHub彼城。除此之外還有sourceforge诅蝶,Google和Apple也有其開(kāi)源項(xiàng)目下載地址,分別是Google OpenSource募壕、Apple OpenSource调炬。國(guó)內(nèi)有比較出名的有開(kāi)源中國(guó),碼云(開(kāi)源中國(guó)代碼托管平臺(tái)))舱馅,Coding缰泡。
整理一下:
- GitHub
- sourceforge
- Google OpenSource
- Apple OpenSource
- 開(kāi)源中國(guó)
- 碼云(開(kāi)源中國(guó)代碼托管平臺(tái)))
- Coding
在進(jìn)行搜索的開(kāi)源項(xiàng)目有很多搜索技巧,就拿GitHub舉個(gè)例子代嗤。想高效的使用GitHub棘钞,一定要把 advanced search、prefixes看一下干毅。
除了上面提到的開(kāi)源項(xiàng)目下載地址宜猜,還有很多其他的地方可以獲取到源碼,這里就不多提了硝逢。
分析方法
閱讀方法才是今天的重點(diǎn)姨拥,筆者一般是按照下面的步驟開(kāi)始。
- 基本思想就是先對(duì)項(xiàng)目有個(gè)大致的了解渠鸽。比如關(guān)鍵的類(lèi)有哪些叫乌,各個(gè)文件夾之間的關(guān)系。
- 然后從最核心的API開(kāi)始徽缚,先使用UML里的類(lèi)圖建立靜態(tài)結(jié)構(gòu)憨奸,分析出類(lèi)與類(lèi)之間的關(guān)系(繼承,組合凿试,實(shí)現(xiàn)排宰,依賴(lài)似芝,關(guān)聯(lián)等等)。這一步是精讀的必經(jīng)之路额各,如果想要徹底理解国觉,畫(huà)UML圖無(wú)意識(shí)最直接的方式。
- 配合IDE工具分析核心流程虾啦,理解項(xiàng)目是如何工作的麻诀。
- 著重看項(xiàng)目中添加的注釋?zhuān)驗(yàn)橐话汩_(kāi)源項(xiàng)目中的注釋都非常重要。
接下來(lái)分下面幾個(gè)部分詳細(xì)介紹傲醉。
- 看:靜態(tài)對(duì)代碼進(jìn)行分析蝇闭,看相關(guān)資料,代碼邏輯
- 跑:將項(xiàng)目在IDE里面跑起來(lái)硬毕,通過(guò)IDE調(diào)試參數(shù)呻引,加Log等。
- 查:閱讀過(guò)程中肯定會(huì)遇到不懂的吐咳,這時(shí)候需要通過(guò)搜索引擎來(lái)解決你的疑惑逻悠。
看
這個(gè)部分是非常基礎(chǔ)但是重要的部分韭脊,主要完成對(duì)代碼的基本感知童谒。從靜態(tài)的角度理解代碼。
現(xiàn)有資料
在我們準(zhǔn)備閱讀某個(gè)開(kāi)源項(xiàng)目之前沪羔,如果搜集了相關(guān)的資料的話饥伊,對(duì)我理解起來(lái)非常有幫助。也就是常說(shuō)的站在巨人的肩膀上蔫饰。
主要分為兩種:
- 項(xiàng)目官方文檔比如Wiki
- 使用者分析的文檔比如項(xiàng)目源碼分析琅豆。
GitHub上的開(kāi)源項(xiàng)目大部分都有文檔介紹,好一點(diǎn)的項(xiàng)目都會(huì)有對(duì)應(yīng)的Wiki篓吁。除此之外開(kāi)源項(xiàng)目的Issue也是我們需要關(guān)心的茫因。往往這些Isuue對(duì)應(yīng)到項(xiàng)目中都是核心部分,也就是我們非常值得關(guān)注的地方杖剪。如下圖所示节腐,一定要善用這些選項(xiàng)。因?yàn)檫@些都是前人踩過(guò)的坑摘盆,對(duì)于項(xiàng)目理解非常有用。
除了項(xiàng)目本身的文檔外饱苟,還有一種形式的文檔也需要我們注意孩擂。這類(lèi)文檔就是別人對(duì)這個(gè)項(xiàng)目寫(xiě)過(guò)的一些源碼分析文章。這類(lèi)文章已經(jīng)對(duì)項(xiàng)目分析過(guò)一次了箱熬,先閱讀完之后类垦,會(huì)對(duì)我們自己去閱讀源碼起到一個(gè)理清思路狈邑,引路的作用。
但是有些大型的開(kāi)源項(xiàng)目文檔太多了米苹,就官方說(shuō)明文檔就不可能一次看完砰琢,比如java中的Spring,看完文檔也是不現(xiàn)實(shí)的陪汽。這個(gè)時(shí)候就應(yīng)該把文檔與代碼調(diào)試結(jié)合在一起训唱。效率會(huì)高不少。而且這類(lèi)型的大型項(xiàng)目至少也得花一年半載才能弄清楚况增。
代碼內(nèi)注釋
對(duì)于開(kāi)源項(xiàng)目?jī)?nèi)注釋一定训挡,一定要仔細(xì)看看澳骤。在使用第三方庫(kù)的時(shí)候澜薄,往往因?yàn)闆](méi)有仔細(xì)閱讀代碼內(nèi)注釋而導(dǎo)致濫用方法。
如下圖是iOS開(kāi)源項(xiàng)目CocoaAsyncSocket一段代碼內(nèi)注釋
如果沒(méi)有仔細(xì)看代碼內(nèi)注釋?zhuān)瑳](méi)有注意到必須設(shè)置代理和代理隊(duì)列表悬,遇到報(bào)錯(cuò)了根本不知道怎么發(fā)生的。
代碼內(nèi)注釋是作者著重想傳達(dá)給使用者的信息籽暇,所以切記切記戒悠,一定要仔細(xì)看代碼內(nèi)注釋绸狐。但是好多人都誤以為把注釋看懂就是源碼分析了累盗,而且好多源碼分析文章也是這樣寫(xiě)的,把注釋翻譯一下符相,說(shuō)明一下用途。
跑
這個(gè)過(guò)程是對(duì)代碼的深入理解部分镜豹,通過(guò)改變函數(shù)參數(shù)蓝牲,運(yùn)行環(huán)境等。不同的語(yǔ)言用了不同的IDE例衍,大部分IDE的作用都相差不多肄渗,都可以追溯堆棧,查看變量信息等翎嫡。所以思路都是相同的。
IDE調(diào)試
項(xiàng)目編譯出來(lái)惑申,運(yùn)行加log,試著修改一些數(shù)據(jù)和代碼人芽,看看有什么變化绩脆。這是最為常用的方法。靈活使用IDE的debugger惕味,而debugger最重要的功能是獲取call stack玉锌。查看變量的變化情況,在你不知道有什么用的函數(shù)里加個(gè)斷點(diǎn)禀倔,顯示出來(lái)的call stack都能讓你對(duì)系統(tǒng)有更清晰的認(rèn)識(shí)参淫。
關(guān)于IDE的調(diào)試使用常用的斷點(diǎn)調(diào)試,變量跟中這些鞋既,這里就不多講了。
調(diào)試技巧
很多時(shí)候我們不知道某個(gè)變量或者某個(gè)變量具體的作用,那么這個(gè)時(shí)候就可以用到對(duì)CUD(Create,Update,Delete)思想检吆。
調(diào)試中的CUD具體來(lái)講就是對(duì)源代碼的類(lèi)程储、函數(shù)、變量進(jìn)行增加摊灭、修改败徊、刪除。如果一直停留在看
源碼的基礎(chǔ)上很有可能不能透徹的理解煤杀,當(dāng)我們掌握了代碼設(shè)計(jì)規(guī)則沪哺,使用CUD方式可以加深理解辜妓,以及驗(yàn)證我們的猜想是否正確。
特別注意籍滴,在實(shí)現(xiàn)項(xiàng)目中一定不要去修改第三方的源碼异逐,有時(shí)候可以通過(guò)修改第三方源碼來(lái)達(dá)到暫時(shí)的目的,但是往往在后期維護(hù)腥例,升級(jí)方面必將付出慘重的代價(jià)酝润。這里指的CUD只適合在分析源碼的時(shí)候。
查
在分析源碼的過(guò)程中构回,肯定會(huì)遇到自己不懂的地方纤掸,對(duì)于這種問(wèn)題,大部分靠自己現(xiàn)有的知識(shí)很有可能無(wú)法理解借跪,這個(gè)時(shí)候就需要實(shí)在不懂就問(wèn)了掏愁。Google、相關(guān)社區(qū)沦泌、GitHub Issue辛掠、Stackoverflow多搜多問(wèn)。
查這個(gè)步驟應(yīng)該是貫穿整個(gè)過(guò)程的他宛,但是也得注意不是一遇到問(wèn)題就上網(wǎng)查欠气,而是應(yīng)該在自己思考之后,得不到解答才去查队塘。很多同學(xué)養(yǎng)成了一遇到問(wèn)題就Google宜鸯,百度淋袖,其實(shí)從長(zhǎng)遠(yuǎn)來(lái)看不利于自己的提升。
分析總結(jié)
走完上面的步驟之后焰情,基本上對(duì)一個(gè)項(xiàng)目源碼掌握了剥懒。但是這個(gè)層次還是有點(diǎn)low。僅僅停留在理解的階段验游,如果想做得更好就需要對(duì)項(xiàng)目的設(shè)計(jì)進(jìn)行分析,看看有沒(méi)有可以改進(jìn)的地方崔梗,甚至完全試一試自己能不能針對(duì)某個(gè)模塊改進(jìn)一下垒在。
這個(gè)階段類(lèi)似于提升爪膊、創(chuàng)新
的程度砸王,建立在見(jiàn)多識(shí)廣的基礎(chǔ)之上,對(duì)于閱讀開(kāi)源項(xiàng)目不多的同學(xué)還是非常有難度的耘成。
整理成文
最后的階段就是把自己分析的內(nèi)容整理成為文檔驹闰,分享出來(lái)师妙。這也是提升自己能力的一個(gè)重要渠道默穴,在寫(xiě)文章的時(shí)候蓄诽,會(huì)強(qiáng)迫自己對(duì)那些不清楚的知識(shí)點(diǎn)加深理解。
文章內(nèi)容應(yīng)包括自己整理的UML圖闸英,核心類(lèi)的實(shí)現(xiàn)嚎莉,代碼設(shè)計(jì)技巧趋箩,以及告知讀者使用該第三方的時(shí)候需要注意的問(wèn)題叫确。
在寫(xiě)文章的時(shí)候需要注意竹勉,不要過(guò)多的延伸吓歇。畢竟一個(gè)點(diǎn)所涉及的知識(shí)網(wǎng)太大了,選擇其中比較核心的幾點(diǎn)闡述即可测柠。