從開源軟體和論文中提升自己

越來越多的軟件開源以及搜索引擎帶來的便利,大大提高了工程開發效率。但是相對於程序員來說,這種效率的提高卻給自身成長帶來了很多困惑:

  • 對於大部分普通工程師來說,每天的工作內容只不過是在原有代碼基礎之上修修改改,用著框架做著重複單調的CURD工作,寫著不痛不癢的業務代碼,反過頭來看自己所掌握的技能,覺的什麼都會一點,可是都不精通,開始變的焦慮不自信;
  • 目前需獨立開發一個全新系統,卻毫無頭緒,不知道怎麼做架構設計;
  • 有些同學想通過學習開源代碼來提高自己,可是一看到代碼量這麼龐大,卻無從下手或者望而卻步。

那麼在平常的工作中如何提高自己的代碼和架構能力呢?本文以相關代碼為例子,具體說明如何讀源代碼和論文,並且掌握其中的思想來為我所用,最終可以做到寫代碼有理可尋,有據可依。

文章的大致結構:第一部分,開源代碼,具體從熟悉、閱讀、應用實踐源代碼三個階段敘述;第二部分,論文,具體從論文閱讀和論文應用實踐兩個方面論述;最後一部分總結。

開源代碼

源代碼被看做是學習的寶藏,從中可以學到很多先進思想和技術。很多同學都曾想通過讀源碼提高自己,可是面對這龐然大物,有的同學選擇一頭扎進去開始從頭開始學,最後收穫甚微,只能放棄,而有些同學則心生畏懼,望而卻步,最終一無所獲。

其實學習任何一新技能和知識,都需要經過一個過程,從熟悉,到深入,最後到實踐為我所用,然後再繼續熟悉,以此循環往復,整個過程需要付出很大的耐心和精力。同樣,閱讀開源代碼亦是如此,在開始這項工作前,一定要克服心理魔障,從戰略上藐視對方,“哼,讀源代碼並沒什麼了不起的“,戰術上一定要重視。

做好充分的心理準備後,開始關於源代碼的戰術分析。

熟悉

學習任何新東西都有一個熟悉的過程,切忌一開始直接下載源代碼從頭開始啃,這種方法只會事倍功半,而且很容易產生挫敗感直至放棄。學習需要有一個循序漸進的過程。

在開始正式閱讀源代碼之前,首先要經歷熟悉的三個階段。

閱讀文檔,熟悉基本概念

在遇到一個新的軟件,一定要先閱讀文檔瞭解其解決什麼問題,涉及到的核心概念,每個模塊的具體職責。如果不看文檔直接打開源碼,會發生什麼事呢?打開源碼的瞬間,各種類的定義迎面而來,spout,tuple,stream,nimbus,一看是不是想死的心都有了。所以,事情說三遍,

基本概念一定要弄清楚,概念越清楚,系統瞭解的越透徹

常用文檔 Read List:

  • 官方文檔:常用的開源代碼都有其公開的網站。
  • wiki:對應github倉庫的wiki文檔。
  • 系統對應的發表論文:比如Bigtable、Zookeeper、Kafka等都有論文發表。

這裡以 storm 為例子:

從開源軟件和論文中提升自己

文檔中,storm提出了一些新的概念,spouts,bolts,詳細閱讀這些名詞背後所表述的含義以及在系統中擔任的職責。

文檔內容需要反覆的讀,每次讀都會有不同的新的認識

實踐使用

具體實踐活動:

  • 按官方文檔部署相關軟件,準備運行環境。
  • 寫一個hello world的demo運行起來:開發包中一般存在文件夾名包含starter 和example字眼的文件夾,該文件夾下會有許多官方使用例子。
  • 修改demo實現自己的業務邏輯。

這個階段主要是模仿官方的例子實現自己的業務邏輯以及熟悉常用的API。在實踐的過程中,會遇到各種問題,同時也會看一些相關技術文章,難點一點點攻破,系統的瞭解也會更深入。

構建數據流圖

看到自己的代碼可以正確的運行,成就感油然而生。但是,請收起你的放縱,這還遠遠不夠,請繼續下一階段:構建數據流運行圖。程序的運行其實就是數據的流動運轉,即數據是在模塊之間流動交互的,數據從輸入到輸出,經歷了哪些模塊,以及模塊之間如何協作。

剛開始構建數據流圖不需要很詳細,只要把文檔中涉及到的核心概念聯繫起來即可,隨著對系統的深入,回頭反過來繼續充實更多的細節內容。

例如,在學習使用storm時,會試著構建這麼一個數據流圖:

從開源軟件和論文中提升自己

為什麼要花時間構建這樣一個圖呢?

  • 理解概念,瞭解系統的運行機制。
  • 逼迫自己去思考,比如模塊之間如何交互,數據流怎麼流動。腦海裡有越多的問題,看源碼的動力就越足。
  • 隨著對系統的逐漸瞭解,可以一步步完善,添加一些具體的實現細節,比如task如何知道輸出結果應該發往那個task呢,其地址是多少呢?
  • 遇到問題時,可以依照該圖猜測問題可能出在哪個模塊,迅速找到切入點。

Tips:在分析系統時,可以從數據流動的角度來思考這個問題。

閱讀

通過熟悉階段,腦海裡積累了很多疑惑,已經迫不及待的開始要閱讀代碼解惑了。切記,閱讀代碼一定要化整為零,從小模塊開始。具體過程則是提出問題,大膽猜想

,小心驗證。

閱讀代碼不是簡單的讀,而是一個思維碰撞的過程:大膽猜想非常重要,當遇到一個技術問題時,首先一定要先獨立思考,想一下:如果換作自己該如何解決以及實現這個功能,當有了自己的解決思路後,然後再對照源代碼驗證。當發現自己的思路跟作者是一樣的,那種快感,哈哈,慢慢體會。

準備階段

在開始具體的代碼閱讀時,還要做些技術儲備。首先我會先看下該軟件所依賴的外部庫,從瞭解這些外部庫開始。為什麼要從這兒開始看呢?其實軟件開發就像搭積木一樣,由一個個小的模塊拼裝而成,只有瞭解了每個小模塊的正確使用方式,才能更流暢的剖析如何搭積木的。

這裡以JAVA項目為例子,打開pom或者gradle 文件查看,該項目依賴了哪些外部庫。

從開源軟件和論文中提升自己

這裡是storm依賴的外部庫,裡面用到了curator(zookeeper使用)、kryo(序列化)、disruptor(生產者消費者模式庫)、netty(網絡)。這裡需要額外花些時間研究下該庫的解決的問題、使用方法和常用API。同時,這也是知識儲備的過程,以後遇到類似的問題,可以聯想到對應的庫,為解決問題提供更多的思路。

切入階段

有了一定的知識儲備,就可以尋找切入點開始在代碼的汪洋中盡情遨遊。關於切入點的選擇,自己有幾點體會:

(1)從熟悉的基礎依賴庫入手,查看它在代碼中是如何使用的。比如基礎庫中對netty使用比較熟悉,就直接找代碼裡對應的handler具體實現,pipline的構成以及netty的設置管理等。從自己熟悉的東西入手,一方面可以克服恐懼,同時通過閱讀代碼可以知道更多的api和api使用方法,看完之後經常會有'原來還可以這樣使用'的感嘆。

(2)從使用過程中遇到的bug入手,依賴錯誤日誌的上下文來查看代碼。

(3)從概念模型中提到的概念模塊入手,比如storm中提到了tuple,spout,nimbus,worker等,直接找到對應的實現類(一般類名和概念名是一樣的,可以直接按名字來搜索),依照其在系統中的職責查看具體實現。

(4)從問題出發,查看相應的技術文章,進一步縮小範圍,查看相關代碼。問題可以是開發中遇到的異常,構建數據流圖的困惑,或者一些很普遍的疑問,比如數據的存儲格式,通信協議,數據處理異常的解決方案等,問題越詳細越好。

(5)從demo代碼開始一步步debug。

深入階段

在深入代碼的閱讀過程中,沒有必要一行一行的閱讀,有些方法可以當作黑盒子,有些if-else分支可以直接略過(忽略一些異常條件情形)。最後模仿代碼自己動手寫一些簡單實現。

整理階段

通過一定時間的學習,看了一部分代碼,即使做總結,一方面可以反過來豐富前文提到過的數據流圖,完善一些細節,同時也可以寫一些技術文章條理一下思路。

應用實踐

俗話說,讀書千萬卷,不會吟詩也會騶。同樣的,源代碼看多了,東拼西湊也可以實現所需的功能(

會抄並且抄的好也是一種能力)。

那麼源代碼會在開發中的哪些方面會有幫助呢?這裡我總結了幾點可操作的具體實踐:

概念模型和命名

在開發初期,需要根據業務需求抽象出概念模型以及系統設計文檔。這一階段也是最難的部分,剛開始根本無從下手。那現在有沒有想起熟悉階段我們閱讀過的文檔和平時積累的素材呢?其實每個優秀的開源軟件都有很好的概念模型和清晰的系統架構,比如在數據處理中任務執行的系統中經常會聽到這些詞,比如topology,task, job,manager,service dispatcher,DAGscheduler,context等。現在要開發設計一個任務提交管理系統,那這個任務和storm的拓撲提交以及hadoop的任務提交及其生命週期管理是不是同一個領域問題呢?很多概念是不是就用上了(job,task,JobManager,JobScheduler,worker,executor,cordinator 等)只要看代碼命名,是不是瞬間覺得高大上了。

從開源軟件和論文中提升自己

關於系統架構圖,有沒有想到前面思考過的系統數據流圖,只要稍微調整一下即可,是不是很容易。

開源基礎庫的使用

在準備階段會了解到很多新的開源應用基礎庫。

比如在看 presto 分佈式 SQL 執行引擎的時候,瞭解到其中一個組件presto-parser,可以解析SQL語句。正好,現需要開發一個SQL語法解析的功能,引用該基礎庫,幾行代碼直接搞定。如果需要重新造輪子,可以參考其實現。

 SqlParser SQL_PARSER = new SqlParser(); Query query = (Query)SQL_PARSER.createStatement("select * from tableName"); QueryBody queryBody = (QuerySpecification) query.getQueryBody();

部分代碼的copy

看代碼的過程中,經常發現這一段代碼實現很巧妙,可以記錄下來,當實現類似的需求,可以直接copy過來,稍微改一下。比如看到flink的限流代碼,構造netty通信協議代碼。在自己設計SPE底層通信協議的時候,直接copy過來做些調整,開發就是這麼easy。

論文

平時的工作中,很少會接觸論文,閱讀論文的時間少之又少。但是論文真是個好東西,內容包含了作者的一些思考和問題闡述,從技術的起源說到目前的狀況等,而這些內容正好幫助構建和豐富自己的知識體系。

閱讀

論文的選擇

(1)在閱讀開源代碼的時候,有些代碼註釋會標註其涉及到的論文:

從開源軟件和論文中提升自己

想要理解具體算法和實現,就需要下載下來仔細閱讀。

(2)比較出名的開源系統(kafka,zookeeper,disruptor等)都會有相對應的論文。對於想學習分佈式系統的同學,有網友已經總結了一些好的論文readlist,有興趣的可以看下。

閱讀方法

這裡簡單說下自己閱讀論文的心得,我會著重花時間在論文的introduction部分,並試著翻譯成中文記錄下來:

從開源軟件和論文中提升自己

好的論文有個特點,在introduction部分會詳細說明一些背景知識,包括:提出問題,目前已有解決方案及其缺點,所討論技術方案的優點

等,這些內容會敘述的相當透徹。閱讀這些內容可能對代碼能力的提升及其有限,但是會提高程序員的軟素質。比如在準備tech talk和寫文章時,需要敘述一些相關技術背景,論文就是很好的素材。

應用實踐

閱讀論文是為了更好的解決實際遇到的問題。有些論文描述瞭解決思路和方法,在遇到問題提出解決方案時會有一定的指導作用。有些論文則會具體論述其實現細節,比如一篇論文Implementing Linearizability at Large Scale and Low Latency :

從開源軟件和論文中提升自己

可以利用業餘時間,動手做個小項目,從論文到工程實現,提高自己的代碼能力。

總結

開發代碼就如搭積木,每個開源工具就好比每個積木快,論文和具體開源代碼的實現思路則是搭積木的粘合劑。只要有正確的指導思想,再配備正確高效的基礎工具,代碼開發真的可以做到如奶茶般潤滑。但是這個過程是極其漫長的,需要長期的積累,才會在工作中潛移默化的提高自己的能力,送大家一句,以共勉。

在成功的道路上都是艱辛而且孤獨的。

最後,每個人都有自己的學習方法體系,歡迎提出自己的意見積極討論,謝謝大家!!


分享到:


相關文章: