今年以來,一直在自學一些新的技術——準確地說——是本身之前沒怎麼深刻接觸過的技術。對於具體的技術,我愈來愈強烈的感覺是,若是不能系統性地講解出來,只是分享一些零散的知識點,那麼它的價值將是大打折扣的。所以,一些具體的知識,等時機成熟了咱們再來討論。然而,有一些知識和方法,它們每每比具體知識有着更廣泛的意義,並且對每一個人來講都是值得探討的課題,這就是有關「學習」自己的知識,以及對認知過程自己的分析。因此,最近我打算從新談談學習的方法,以及認知過程當中涉及到的一些基本問題。程序員
咱們的認知是創建在「概念」的基礎上的,在此基礎上「概念」之間造成「關係」,就構成了一個知識體系——一個知識的大網。而對於「概念」和它們之間的「關係」的把握,咱們靠的是什麼呢?沒錯,靠的是「邏輯」。算法
若是咱們從認知的角度出發,重點來關注概念之間的「依賴」關係,那麼能夠看到概念之間會呈現出清晰的分層結構。爲了理解一個系統或者新的知識領域,咱們必需要找到這樣一個概念的層次,而後把咱們全部的認知構建在這個層次之上。爲了把這個觀點說得更清楚,接下來我舉幾個例子。編程
分層的概念舉例
- 客戶端的UI編程。通常狀況下,咱們對於UI編程的認知是創建在與「View」相關的各個概念之上的。View是什麼呢?能夠認爲它是一塊矩形的區域,具備位置和大小,可以渲染出內容,能夠和用戶交互。只要理解了View這一層次,咱們就知道如何用它來組裝出各類頁面,咱們日常大部分的客戶端編程工做便能勝任了。單以渲染繪製方面來講,咱們能夠自定義繪製的內容,能夠繪製出矩形、圓形,也能夠繪製出任意圖片。但若是再往下深刻到「OpenGL ES」的概念層次,那麼就能理解全部形狀其實都由三角形組成的(包括圓形也是三角形拼成的),一個形狀和紋理是怎麼繪製出來的,少數的幾個頂點是怎麼對應到那麼多個像素點上去的,這中間是怎樣的一種插值的過程。若是咱們想實現一些稍微複雜的功能,好比濾鏡(須要執行像素級的操做),就頗有可能須要在「OpenGL ES」這個層面上去理解各個概念。
- 網絡通訊。以HTTP通訊爲例,若是咱們的認識只是侷限在一些具體的API層次,無論它是系統自己提供的(好比Java的HttpURLConnection,或者iOS的NSURLConnection),仍是第三方庫提供的(好比HttpClient, OkHttp, Android-Volley等),那麼咱們雖然也有可能在某些狀況下寫出能運行的代碼,可是使用不一樣編程環境的人之間(好比先後端之間)就基本無法交流,由於具體的API都有所差別。爲了能互相聽懂對方的話,咱們必需要到HTTP協議的層次去交談,這樣,咱們才能分清什麼是Method,什麼是參數,什麼是Header,什麼是Body,各部分的格式是怎樣的,緩存策略以及Cookie這些概念和HTTP Header有什麼關係,等等。更進一步,若是咱們涉及到要作一些更底層的工做,好比網絡性能優化,或者協議處理,咱們就必須理解到TCP這一層,理解HTTP和TCP是怎樣的關係,一個HTTP請求或響應怎樣被封裝進TCP包,多個HTTP請求如何共用一條TCP鏈接,等等這些問題。
- Web框架。後端在實現一個Web Server的時候,常常基於一些成熟的MVC框架,就相似Spring這樣的。這種MVC框架所提供的功能,就組成了一個概念層次。咱們知道,在這個層次上,咱們只須要寫一個小小的Java Annotation,就可以按照咱們精肯定義的規則來實現Request Mapping;咱們在處理方法最後返回的Java對象,也會被轉成正確的格式(通常是JSON)輸出到網絡上去;配置一個攔截器就可以進行某種通用的處理。可是,有時候咱們也須要深刻到下一個層次,Servlet規範的層次,去了解框架的全部這些功能是怎樣在Servlet的基礎上構建出來的。只有這樣,當咱們碰到一些難解的疑難雜症,或者想對框架進行擴展的時候,才知道從哪裏下手。
- 響應式編程。當咱們使用Rx系列的架構來構建咱們的代碼時,在這一層次上,咱們能夠執行各類變換,靈活地切換線程,流式地處理事件和邏輯。但若是要理解這背後到底發生了什麼,咱們必需要深刻一層,把這些抽象的東西構建在咱們已經熟知的基本概念之上,這些基本概念包括:多線程、同步原語、事件隊列,以及一些基本的異步邏輯。
- 機器學習。利用機器學習,咱們至少能解決兩個大類的問題:分類(Classification)和迴歸(Regression)。爲了解決這些問題,機器學習就像一個工具箱,爲咱們提供了不少現成的的算法框架,好比:LR, 決策樹,隨機森林,Gradient boosting等等,還有近兩年大熱的深度學習的各類算法,但要想作到深刻的話呢,只是會使用這些現成的算法庫還不夠,還須要在底層的數學原理上有所把握。好比,研究優化理論,纔可以有更好的思路去設計和優化目標函數;研究統計學,纔可以理解機器學習本質的由來,理解爲何機器學習的方法可以使得模型一步步地逼近真實的數據分佈;研究線性代數,纔可以更靈活地使用矩陣這一數學工具,提升了性能且表達簡潔,纔可以更好地理解機器學習中涉及到的維數災難及降維問題;研究信息論,纔可以準確地度量不一樣機率分佈之間的差別。
- 計算機圖形學。若是要作2D的圖像處理,基本上能理解OpenGL的規範和Shader程序的語法就差很少能進行開發工做了。但若是要作3D的圖像處理,則須要理解3D的座標變換(model, view, projection),尤爲是投影變換。這個層次的知識超出了OpenGL的範疇,本質上是線性代數中的線性變換。
例子就先到此打住,由於具體的例子永遠也舉不完。爲何在認知的過程當中,咱們要把概念清晰地分層呢?c#
- 必要性。有些時候,當咱們接觸一個新的知識領域時,有大量的概念須要理解。若是咱們想理解上層的概念,那麼必須先理解下層的概念,一層層推下去,直到咱們到達了一層咱們已經熟知的概念爲止。這時候,咱們才能理解整個體系。
- 更深入的理解。幾乎全部狀況下,理解了下層的概念,上層的概念也變得更加清晰。試想一下,分別站在四個不一樣的層面來看系統:JDK,JVM,POSIX規範,Kernel,看到的東西天然相差甚遠。不少狀況下,受限於時間和精力,咱們沒有機會去一窺各個層次的究竟,但咱們也不該該忘了在研究方法中這種層層深刻的可能性。
- 更清晰的知識結構。若是咱們頭腦中對於某個知識領域的認識,只有一系列雜亂的概念,且它們來自各個不一樣的層次,那麼咱們的知識就是支離破碎的。在這樣一個支離破碎的基礎上,咱們是無法進行正常的邏輯思考的。
概念的層次與Spec的關係
若是你不是第一天讀我寫的東西,那麼極可能你已經知道了Spec這個概念表明的是啥。這個概念是我在《技術的正宗與野路子》中提出來的,它是對於某項技術或知識的一份完備的、系統性的描述,咱們學習的目的,能夠說就是能讀懂它,理解它。後端
從咱們今天所討論的話題來說,一個Spec其實定義了某個層次的全部概念,並且這份定義是比較完備的。之因此說是完備的,是由於只要咱們理解了一份Spec,那麼對應的那個層次的認知過程就基本結束了,咱們能夠在這個層次上構建起必需的邏輯,並有能力解決從屬於那個層次的一切問題。因此說,從新概括Spec的定義,咱們能夠加上一個定語:它是對於某項技術或知識的某個層次的一份完備的、系統性的描述。緩存
通俗地說,某個特定層次的概念,就至關於那個層次的一門交流的語言。就比如說,程序員對設計師或產品經理應該使用產品語言來交流,但若是咱們非要使用「數據存儲的表結構」、「接口返回的數據格式」之類的詞彙,交流就變得沒法進行。由於這不是雙方都能理解的語言。而咱們在思考的時候,在頭腦中也是須要一種「邏輯語言」來進行描述的,這門「邏輯語言」就是某個概念層次,也或者是一份完備的Spec。性能優化
自底向上仍是自頂向下
像計算機科學中的不少問題同樣,認知的過程也能夠分爲自底向上(bottom-up)或自頂向下(top-down)的。網絡
就好比要理解前面提到的降維問題,咱們須要去學習一些降維的技術,好比頗有名的PCA。若是按照自頂向下的方法去理解這個概念,那麼,要理解PCA,就須要先理解特徵值和特徵向量;要理解特徵值和特徵向量,就須要先理解線性變換;要理解線性變換,就須要先理解線性映射;要理解線性映射,就須要先理解線性空間;要理解理解線性空間,就須要先理解向量、向量組、線性相關和線性無關等諸多的基礎概念。多線程
上述自頂向下的理解過程,與咱們學校裏傳統的教學過程正好相反。兩種方法各有優缺點。架構
- 自底向上,知識的根基會打得更深。但缺點是費時費力,目的性不明確。
- 自頂向下,優勢是目的性強。缺點是得到的知識可能不夠系統。
在實際中,兩種方法應該互爲補充。當時間相對緊迫,而所面臨的新領域又相對龐大的時候,這時候能夠選用自頂向下的方法,來迅速地自上而下地穿透各個概念層次,把遭遇到的陌生的概念變成能夠理解的概念。而當時間充裕以後,對於重要的知識領域,就能夠採用自底向上的方式,從新把各個概念層次自下而上地梳理一遍,以達到一個更系統性的理解。
對於具體知識的逐層深刻地認知,是永遠沒有止境的。而學習和認知的方法自己也是一種技術,它們就蘊藏在那些具體問題之間。只要你終日和它們打交道,你就必定會摸索出其中的一些門道,並逐漸變得精於此道。
(完)
其它精選文章: