對底層該有的探究能力與程度


iThome 網站首載:對底層該有的探究能力與程度

現在這個時代進行程式設計,有著越來越多高階工具,它們存在的目的是為了讓程式人免於各種繁瑣細節,藉以大幅提昇工作效率,因為有了更多的高階工具,應用程式規模越來越大,技術堆疊也越形複雜,程式人就得學習越多高階工具的抽象觀念,然而時不時地,細節會從這些高階工具中滲漏出來,為此不少人強調程式人必須有底層探究能力,高階工具帶給程式人的到底是麻煩還是效率?抽象觀念之下,程式人到底要深究到什麼程度呢?

新生代程式人的困境

高階工具是為了隱藏複雜,C語言隱藏了組合語言的複雜,C++簡化了C語言在實作物件導向時的繁複,Java簡化了物件配置與回收的概念,並以JVM抽象化了作業系統,Web容器(Container)抽象化HTTP伺服器,Session機制掩蓋了HTTP無狀態事實,各式Web框架簡化了MVC/Model2流程的實作,ORM試圖隱藏物件模型與關聯模型不匹配問題,jQuery簡化了JavaScript與DOM操作間的麻煩...各式的抽象或高階工具都試圖隱藏底層,某個時間點上,總會流行某些抽象或高階工具,不少應用程式基於這些工具建構,後續某個程式人要進入程式設計領域,似乎理所當然地就是學習與使用這些高階工具。

這些高階工具讓程式人愉快地用來解決它們所擅長的問題,直到問題超過工具能力可及範圍,然後程式人雙手一攤,什麼也繼續不下去了,資深程式人告訴他,要去瞭解工具的架構,要去瞭解工具的底層,於是使用ORM的必須去瞭解SQL,使用Web框架的必須去瞭解MVC/Model2,寫jQuery的必須去瞭解JavaScript,寫JSP的要回去瞭解Servlet與Web容器行為,寫Java的要理解JVM,為了瞭解物件配置與記憶體的關係,得學一下C/C++,為了當名程式設計師,搞到最後都得學一下組合語言或寫出個作業系統?

新生代程式人處於某個技術發展的時間點,得疲於學習越來越多的抽象觀念,才能夠使用基於這些抽象觀念的高階工具,往上層得應付日益龐多的技術堆疊,往下層得探究各種抽象觀念的底層細節,因為資深程式人都知道,只要在知道底層細節如何手動解決時,才知道高階工具如何節省時間,也才能知道高階工具的能與不能,在高階工具力有不逮之時,也能夠知道如何手動處理細節,或者知道如何擴充高階工具。

你的底層不是我的底層?

然而真要談到深究底層能力,寫組合語言的會覺得寫C/C++的喪失底層能力,寫C/C++認為寫Java的不懂底層,懂Web容器的批評用Web框架的不懂原理,操弄JavaScript得心應手的覺得用jQuery根本不是在寫JavaScript,瞭解SQL的覺得ORM根本就是個廢物。在本位主義下,每個人基於自己深諳的專業與浸淫之深度,都會認為自己懂的東西才算基本,當別人不瞭解時就搖頭看輕,這是否落入自古文人相輕,程式設計師亦然的心態?

如果存在這種「你的底層不是我的底層」的心態,那任何高階工具就都沒有存在的必要了,畢竟人的時間有限,各種抽象或高階工具,是希望程式人能避免將時間花費在過於繁瑣的細節,而可以將時間與腦力花費在更有價值的創造上。《人月神話》書中提到「程式人員一定時間內能產出的程式碼行數是一定的,不論用什麼語言」,這也是高階語言存在的價值,也是不斷有新語言出現追求更高抽象與表達能力的原因。

或許問題不在於程式人處於哪個底層,而是在使用某個抽象工具時,能瞭解它封裝了哪些細節,而不僅是使用其表面的功能性,重點在於必要之時,能探尋底層實作方式與原理的那份能力,因而能不被工具限制住,甚至擁有改善或創造新工具的可能性。舉個例子來說,在我初次探討Rails時,看到它提供的一個高階Session機制flash,作用週期僅止於兩次HTTP請求之間,此次請求設置的資訊可於下次請求取得,而後資訊就清除了,這在重新導向(redirect)時設置與取得資訊很方便,然而我會想知道它是利用什麼機制實現的,以瞭解它代勞了哪些細節,從而知道其他可能的運用場合,或甚至是安全上必須注意的事項。

抽象邊界與抽象滲漏法則

在使用抽象邊界外的便利功能性時,能夠思考一下抽象邊界內的可能細節,甚至是去探究原始碼以瞭解其實作原理,這種能力是我本身對程式人底層探究能力之定義,擁有這種能力,無論處於抽象的哪一樓,必要之時都可以步下一層樓來瞭解究竟,注意我說的是「必要之時」,工具創造出來就是要善用的,「必要之時」是指想更進一步瞭解如何善用它(或決定不使用它)的時候,如果深入至某個底層對於該工具的運用與否沒有助益,除非是單純個人興趣,否則再深入的意義就不大了,如果想瞭解的是超高大樓頂樓景觀餐廳如何360度旋轉,那麼去研究它的地下室應該是沒什麼幫助。

從另一角度來說,之所以要有這種探究抽象邊界內細節的能力,是因為有時跟細節相關的問題,會從這些高階工具中滲漏出來,這就是《約耳趣談軟體》書中的〈抽象滲漏法則〉中談到:「所有重大的抽象機制在某種程式上都是有漏洞的」,滲漏出來的東西可能會以各種形式呈現,像是錯誤訊息、效能負擔、安全漏洞、功能限制與複雜的生命週期等,一旦細節從高階工具中滲漏出來,就如約耳說的:「唯一能適當處理漏洞的方法,就是弄懂該抽象原理以及所隱藏的東西」。

瞭解抽象邊界內的細節,承認抽象滲漏是存在的,並不是意謂著程式人只能使用低階工具,只有在弄懂抽象原理以及所隱藏的東西,才能知道高階工具以何種方式抽象化了哪些東西,也才能知道為何細節為何會滲漏出來,也可能加以處理或避開,或是依所面對的問題情境,選擇最適當的抽象工具,甚至使用自己的抽象規則來建立工具以解決問題,而不是現有的工具架構下做受限的思考。

日前有篇〈Programmer’s dilemma〉文章談到了有些程式人理解底層能力正逐漸失去,甚至衍生出無法創新的問題,文中談到現有程式碼如此穩定(如此龐大/如此好用)的情況下,若程式人只一昧遵循既有路徑,不多做額外思考,那麼就會越陷越深,變成只會在現有架構下維護程式,漸漸地失去從無到有建立完整專案的能力,失去了創立新架構的能力。

抽絲剝繭、解決問題的能力

我有一個朋友,平常總愛說某些東西的底層細節他不懂,然而卻是那種會一邊抱怨,一邊認真地把問題解決的人,最近他為了解決問題,認真地研究了JAX-RS與Jersey,然而最後,他決定放棄直接使用Jersey,而是將它的RESTful概念帶到自己撰寫的程式上頭,因為根據他的需求,硬是套用Jersey的話,無法從中獲得益處,反而讓現有程式變得複雜。

因而程式人的底層探究能力,其實牽涉到的就是抽絲剝繭、解決問題的能力,而不是位於哪個底層的問題。如果沒有抽絲剝繭、解決問題的能力,為了解決一個複雜的問題,而直接使用了一個高階的工具,為了要能使用那套工具,得再去理解一套複雜的抽象規則,如此繼續下去的話,就會像約耳講的「擁有愈來愈高階的程式設計工具,抽象化也做得愈來愈好,要成為一個純熟的程式師卻是愈來愈難了」,在複雜的東西上建立更複雜的東西,最後問題發生在某個底層時,那就真的難以解決了。