極客時間專欄陳皓《左耳聽風》筆記二
你聽別人講,或是自己看書,或是讓別人演示給你,這些都不能讓你真正獲得學習能力,因為你是在被別人灌輸,在聽別人說。
只有你開始自己思考,開始自己總結和歸納,開始找人交流討論,開始踐行,並開始對外輸出,你才會掌握到真正的學習能力。
學習不是努力讀更多的書,盲目追求閱讀的速度和數量,這會讓人產生低層次的勤奮和成長的感覺,這只是在使蠻力。要思辨,要踐行,要總結和歸納,否則,你只是在機械地重複某件事,而不會有質的成長的。
深度學習十分重要
應該怎樣進行深度學習呢?下面幾點是關鍵。
- 高質量的資訊源和第一手的知識。
- 把知識連成地圖,將自己的理解反述出來。
- 不斷地反思和思辨,與不同年齡段的人討論。
- 舉一反三,並踐行之,把知識轉換成技能。
換言之,學習有三個步驟
- 知識採集 。資訊源是非常重要的,獲取資訊源頭、破解表面資訊的內在本質、多方資料印證,是這個步驟的關鍵。
- 知識縫合。 所謂縫合就是把資訊組織起來,成為結構體的知識。這裡,連線記憶,邏輯推理,知識梳理是很重要的三部分。
- 技能轉換。 通過舉一反三、實踐和練習,以及傳授教導,把知識轉化成自己的技能。這種技能可以讓你進入更高的階層。
我覺得這是任何人都是可以做到的,就是看你想不想做了。
學習是為了找到方法和原理
學習不僅僅是為了找到答案,而更是為了找到方法。只有掌握解題的思路和方法,你才算得上擁有解決問題的能力。
學習不僅僅是為了知道,而更是為了思考和理解。在學習的過程中,我們不是為了知道某個事的表面是什麼,而是要通過表象去探索其內在的本質和原理。
在學習的過程中,我們要不斷地問自己,這個技術出現的初衷是什麼?是要解決什麼樣的問題?為什麼那個問題要用這種方法解?為什麼不能用別的方法解?為什麼不能簡單一些?……
擁有正確的學習觀念:學習不僅僅是為了找到答案,而更是為了找到方法;學習不僅僅是為了知道,而更是為了思考和理解;學習不僅僅是為了開拓眼界,而更是為了找到自己的未知,為了瞭解自己;學習不僅僅是為了成長,而更是為了改變自己,改變自己的思考方式,改變自己的思維方式,改變自己與生俱來的那些垃圾和低效的演算法。
端正的學習態度和正確的學習觀念,是高效學習的第一步,擁有這兩者一定可以讓你事半功倍。
挑選知識和資訊源
如果你覺得用百度搜中文關鍵詞就可以找到自己想要的知識,那麼你一定遠遠落後於這個時代了。如果你用 Google 英文關鍵詞可以找到自己想要的知識,那麼你算是能跟得上這個時代。如果你能在社群裡跟社群裡的大牛交流得到答案,那麼你算是領先於這個時代了。
你的資訊源要有下面幾個特質。
- 應該是第一手資料,不是被別人理解過、消化過的二手資料。尤其對於知識性的東西來說,更是這樣。應該是原汁原味的,不應該是被添油加醋的。
- 應該是有佐證、有資料、有引用的,或是有權威人士或大公司生產系統背書的資料。應該是被時間和實踐檢驗過的,或是小心求證過的,不是拍腦袋野路子或是道聽途說出來的資料。
- 應該是加入了一些自己的經驗和思考,可以引發人深思的,是所謂資訊的密集很大的文章。
注重基礎和原理
我說過,很多人並不是學得不夠快,而他們的基礎真的不行。基礎不行,會影響你對事物的理解,甚至會讓你不能理解為什麼是這樣。當你對事物的出現有不理解的東西時,通常來說,是因為你的基礎知識沒有跟上。
使用知識圖
畫知識圖的方式可以讓你從一個技術最重要最主幹的地方出發開始遍歷所有的技術細節,也就是畫地圖的方式。如果你不想在知識的海洋中迷路,你需要有一份地圖,所以,學習並不是為了要記憶那些知識點,而是為了要找到一個知識的地圖,你在這個地圖上能通過關鍵路徑找到你想要的答案。
系統地學習
在學習某個技術的時候,可以使用一個學習模板。只有把這個學習模板中的內容都填實了,我才罷休。這個模板如下。
-
這個技術出現的背景、初衷和要達到什麼樣的目標或是要解決什麼樣的問題。這個問題非常關鍵,也就是說,你在學習一個技術的時候,需要知道這個技術的成因和目標,也就是這個技術的靈魂。如果不知道這些的話,那麼你會看不懂這個技術的一些設計理念。
-
這個技術的優勢和劣勢分別是什麼,或者說,這個技術的 trade-off 是什麼。任何技術都有其好壞,在解決一個問題的時候,也會帶來新的問題。另外,一般來說,任何設計都有 trade-off(要什麼和不要什麼),所以,你要清楚這個技術的優勢和劣勢,以及帶來的挑戰。
-
這個技術適用的場景。任何技術都有其適用的場景,離開了這個場景,這個技術可能會有很多槽點,所以學習技術不但要知道這個技術是什麼,還要知道其適用的場景。沒有任何一個技術是普適的。注意,所謂場景一般分別兩個,一個是業務場景,一個是技術場景。
-
技術的組成部分和關鍵點。這是技術的核心思想和核心元件了,也是這個技術的靈魂所在了。學習技術的核心部分是快速掌握的關鍵。
-
技術的底層原理和關鍵實現。任何一個技術都有其底層的關鍵基礎技術,這些關鍵技術很有可能也是其它技術的關鍵基礎技術。所以,學習這些關鍵的基礎底層技術,可以讓你未來很快地掌握其它技術。可以參看我在 CoolShell 上寫的 Docker 底層技術那一系列文章。
-
已有的實現和它之間的對比。一般來說,任何一個技術都會有不同的實現,不同的實現都會有不同的側重。學習不同的實現,可以讓你得到不同的想法和思路,對於開闊思維,深入細節是非常重要的。
基本上來說,如果你按照我上面所提的這 6 大點來學習一門技術,你一定會學習到技術的精髓,而且學習的高度在一開始就超過很多人了。如果你能這樣堅持 2-3 年,我相信你一定會在某個領域成為炙手可熱的佼佼者。
舉一反三
我認為,人與人最大的差別就是舉一反三的能力。那些聰明的或者是有經驗的人舉一反三起來真是太令人驚歎。
我覺得一個人的舉一反三能力,可以分解成如下三種基本能力。
-
聯想能力。這種能力的鍛鍊需要你平時就在不停地思考同一個事物的不同的用法,或是聯想與之有關的別的事物。對於軟體開發和技術學習也一樣。
-
抽象能力。抽象能力是舉一反三的基本技能。平時你解決問題的時候,如果你能對這個問題進行抽象,你就可以獲得更多的表現形式。抽象能力需要找到解決問題的通用模型,比如數學就是對現實世界的一種抽象。只要我們能把現實世界的各種問題建立成資料模型(如,建立各種維度的向量),我們就可以用數學來求解,這也是機器學習的本質。
-
自省能力。所謂自省能力就是自己找自己的難看。當你得到一個解的時候,要站在自己的對立面來找這個解的漏洞。有點像左右手互博。這種自己和自己辯論的能力又叫思辨能力。將自己分裂成正反方,左右方,甚至多方,站在不同的立場上來和自己辯論,從而做到不漏過一個 case,從而獲得完整全面的問題分析能力。
在這方面,我對自己的訓練如下。
- 對於一個場景,製造出各種不同的問題或難題。
- 對於一個問題,努力尋找儘可能多的解,並比較這些解的優劣。
- 對於一個解,努力尋找各種不同的測試案例,以圖讓其健壯。
老實說,要獲得這三種能力,除了你要很喜歡思考和找其它人來辯論或討論以外,還要看你自己是否真的善於思考,是否有好奇心,是否喜歡打破沙鍋問到底,是否喜歡關注細節,做事是否認真,是否嚴謹……
歸納和總結
對自己的知識進行總結和歸納是提高學習能力的一個非常重要的手段。這是把一個複雜問題用簡單的語言來描述的能力。
我們把學到的東西用自己的語言和理解重新組織並表達出來,本質上是對資訊進行消化和再加工的過程,這個過程可能會有信息損失,但也可能會有新資訊加入,本質上是資訊重構的過程 。我們積累的知識越多,在知識間進行聯絡和區辨的能力就越強,對知識進行總結和歸納也就越輕鬆。而想要提高總結歸納的能力,首先要多閱讀,多積累素材,擴大自己的知識面,多和別人討論,多思辨,從而見多識廣。
我們需要注意的是,如果只學了部分知識或者還沒有學透,就開始對知識進行總結歸納,那麼總結歸納出來的知識結構也只能是混亂和幼稚的。因此,學習的開始階段,可以不急於總結歸納,不急於下判斷,做結論,而應該保留部分知識的不確定性,保持對知識的開放狀態。當對整個知識的理解更深入,自己站的位置更高以後,總結和歸納才會更有條理。總結歸納更多是在複習中對知識的回顧和重組,而不是一邊學習一邊就總結歸納。
做總結歸納的方法:把你看到和學習到的資訊,歸整好,排列好,關聯好,總之把資訊碎片給結構化掉,然後在結構化的資訊中,找到規律,找到相通之處,找到共同之處,進行簡化、歸納和總結,最終形成一種套路,一種模式,一種通用方法。
要訓練自己這方面的能力,你需要多看一些經典的方法論圖書,看看別人是怎樣總結和歸納知識的。你可以在一開始模仿並把自己的理解的知識給寫出來,寫部落格會是一種很好的方式。另外一種更好的方式是講一遍給別人聽。總之,你需要把你總結歸納的知識公開出來,給別人看,接受別人的批評和反饋,這樣你才能成長得更快。其實,我也在鍛鍊這樣的能力。
讀文件還是讀程式碼
書和文件是人對人說的話,程式碼是人對機器說的話(注:程式碼中有一部份邏輯是控制流程的邏輯,不是業務邏輯)。所以,
- 如果你想知道人為什麼要這麼搞,那麼應該去看書(像 Effective C++、Code Complete、Design Pattern、Thinking in Java 等),看文件。
- 如果你要知道讓機器幹了什麼?那你應該看程式碼!(就像 Linus 去看 zlib 的程式碼來找效能問題。)
因此,我認為都比較重要,關鍵看你的目的是什麼了。
如果你想了解一種思想,一種方法,一種原理,一種思路,一種經驗,恐怕,讀書和讀文件會更有效率一些,因為其中會有作者的思路描述。像 Effective C++ 之類的書,裡面有很多對不同用法和設計的推敲,TCP/IP 詳解裡面也會有對 TCP 演算法好壞的比較……這些思維方式能讓你對技術的把握力更強,而光看程式碼很難達到這種級別。(現在你知道什麼樣的書是好書了吧 ;-))
如果你想了解的就是具體細節,比如某協程的實現,某個模組的效能,某個演算法的實現,那麼你還是要去讀程式碼的,因為程式碼中會有更具體的處理(尤其是對於一些 edge case 或是程式碼技巧方面的內容)。
從學習的過程中,我們來分析一下看程式碼和看書這兩個活動。人對新事物的學習過程基本都是從“感性認識”到“理性認識”的。
如果你是個新手,那應該多讀程式碼,多動手寫程式碼,因為你需要的是“感性認識”,這個時候“理性認識”你體會不到。一是因為,你沒有切身的感受,即便告訴你 Why 你也體會不到。另一方面,這個階段,你要的不是做漂亮,而是做出來。所以,在新手階段,你會喜歡 GitHub 這樣的東西。
如果你是個老手,你有多年的“感性認識”了,那麼你的成長需要更多的“理性認識”。因為這個階段,一方面,你會不滿足於做出來,你會想去做更牛更漂亮的東西;另一方面,你知道的越多,你的問題也越多,你迫切地需要知道 Why!這時,你需要大量地找牛人交流(讀牛人的書,是一種特殊的人與人的交流),所以,這個階段,你會喜歡讀好的書和文章。
然而,對於計算機行業這個技術創新能力超強、技術種類繁多的行業來說,我們每個人都既是新手,也是老手。
如何閱讀原始碼
在閱讀程式碼之前,我建議你需要有下面的這些前提再去閱讀程式碼,這樣你讀起程式碼來會很順暢。
-
基礎知識。相關的語言和基礎技術的知識。
-
軟體功能。你先要知道這個軟體完成的是什麼樣的功能,有哪些特性,哪些配置項。你先要讀一遍使用者手冊,然後讓軟體跑起來,自己先用一下感受一下。
-
相關文件。讀一下相關的內部文件,Readme 也好,Release Notes 也好,Design 也好,Wiki 也好,這些文件可以讓你明白整個軟體的方方面面。如果你的軟體沒有文件,那麼,你只能指望這個軟體的原作者還在,而且他還樂於交流。
-
程式碼的組織結構。也就是程式碼目錄中每個目錄是什麼樣的功能,每個文件是幹什麼的。如果你要讀的程式是在某種標準的框架下組織的,比如:Java 的 Spring 框架,那麼恭喜你,這些程式碼不難讀了。
閱讀程式碼的方法如下。
- 一般採用自頂向下,從總體到細節的“剝洋蔥皮”的讀法。
- 畫圖是必要的,程式流程圖,呼叫時序圖,模組組織圖……
- 程式碼邏輯歸一下類,排除雜音,主要邏輯才會更清楚。
- debug 跟蹤一下程式碼是瞭解程式碼在執行中發生了什麼的最好方式。
對了,閱讀程式碼你需要一個很好的 IDE。我記得以前讀 C 和 C++ 程式碼時,有一個叫 source insight 的工具就大大提高了我的程式碼閱讀效率。說白了就是可以檢視程式碼間相互的呼叫 reference 的工具,這方面 Visual Studio 做得是非常好的。
如何面對枯燥的知識
如果你發現有些知識太過於枯燥,那麼可以通過下面的方法解決。
- 這個知識對於你來說來太高階了,你可能不知道能用在什麼地方。
- 人的認知是從感性認識向理性認識轉化的,所以,你可能要先去找一下應用場景,學點更實用的,再回來學理論。
- 學習需要有反饋,有成就感,帶著相關問題去學習會更好。
- 當然,找到牛人來給你講解,也是一個很不錯的手段。
如何面對大量知識
我給你的建議是,一點一點學,一口一口吃。你可以使用我前面說過的那些方法,注重基礎,畫知識圖,多問為什麼,多動手,然後堅持住,哪怕你每週就學一個知識點,你一年也可以學到 50 個知識點。只要你在進步,總有一天可以把這些知識學到手的。
當然,你的目的不是學完這些知識,因為學無止境,你永遠也學不完,所以你在學習時,一定不要學在表面上,一定要學到本質,學到原理上,那些東西是不容易變的,也是經得住時間考驗的。把學習當成投資,這是這個世界上回報最好的投資。
帶著問題去學習,帶著要解決的東西去學習,帶著挑戰去學習,於是每當你解決了一個問題,做了一個功能,完成了一個挑戰,你就會感到興奮和有成就感。這樣,你也就找到了源源不斷的學習驅動力。
把你學習的心得、過程、筆記、程式碼分享出來,找到和你一同學習的人,因為一個人長跑很辛苦,有人同行就會好很多,就算沒有人同行,你的讀者,你的觀眾也會為你鼓勵叫好,這些也是讓你持續前行的動力。
其它幾個實用的技巧:
- 用不同的方式來學習同一個東西。 比如:通過看書,聽課,建立腦圖,寫部落格,講課,解決實際問題,等等。
- 不要被打斷。 被打斷簡直就是學習的天敵,所以,你在學習的時候,最好把手機設定成勿擾模式放在一邊,然後把電腦上的所有通知也關掉,最好到一個別人找不到你的地方。
- 總結壓縮資訊。 當你獲得太多的資訊時,你需要有一個“壓縮演算法”。我常用的壓縮演算法是隻關心關鍵點,所以,你需要使用表格、圖示、筆記或者腦圖來幫助你壓縮資訊。
- 把未知關聯到已知。 把你新學的知識點關聯到已知的事物上來。比如,你在學習 Go 語言,你就把一些知識關聯到自己已經學過的語言上比如 C 和 Java。通過類比,你會學得更紮實,也會思考得更多。
- 用教的方式來學習。 你想想,如果你過幾天要在公開場合對很多人講一個技術,那麼這個壓力會讓你學得更好。因為要教給別人,所以,這麼高的標準需要你不但要把自己已掌握的東西學好,還要把周邊的也一併學了,才可能做到百問不倒。你才敢去教別人,不是麼?(試試教 6 歲的孩子程式設計,如果你掌握了這種技能,那麼你一定是把知識吃得非常透徹了。)
- 學以致用。 把學到的東西用起來,沒有什麼比用起來能讓你的知識更鞏固的了。在實踐中,你才會有更為真實的體會,你才會遇到非常細節和非常具體的問題,這些都會讓你重新思考,或深化學習。
- 不要記憶。 聰明的人不會記憶知識的,他們會找方法,那些可以推匯出知識或答案的方法。這也是為什麼外國人特別喜歡方法論。
- 多犯錯誤。 犯錯會讓你學得到更多,通過錯誤總結教訓,你會比沒有犯過錯的人體會得更深。但是千萬不要犯低階錯誤,也不要同一個錯誤犯兩次。