deno 如何償還 node.js 的十大技術債

前端先鋒發表於2019-03-21

根據網路資料整理

“Node現在太難用了!”。Node.js之父 Ryan Dahl 去年初要開發一款 JavaScript 互動式資料分析工具時,忍不住抱怨起自己十年前一手創造的技術。

Ryan Dahl 想要設計出一款類似 IPython 的互動式資料科學分析命令列工具,但改用 JavaScript 語言,要讓 JavaScript 也可以像 Python 那樣,進行各式各樣的資料分析、統計計算以及資料視覺化戰士。一度離開 Node.js 開發社群的 Rayn Dahl,再次拿起自己發明的 Node.js 來開發這個新的資料分析工具,但是越用越彆扭,他開始思考,有什麼方法可以改進 Node.js。

Node.js 是他在 2009 年 11 月 8 日時,在 JavaScript 社群歐洲 JSConf 大會上首度釋出的,它把瀏覽器端的 JavaScript 技術,帶入了伺服器端應用領域。前端網頁工程師從來都沒想過,自己也可以成為後端工程師,但 Node.js 讓前端技術走出了瀏覽器,前端工程師甚至可以成為全端工程師,Node.js 改變了前端工程師的世界。

從2009年 Ryan Dahl 設計出這個伺服器端的 JavaScript 框架,至今已經發展到了第 10 版。而隨 Node.js 而生,另一位開發者 Isaac 設計出的 JavaScript 包管理工具 npm,更成了網頁開發者必懂得技術,在 npm 的儲存庫上,註冊了超過 60 萬個 Node.js 模組,這更讓 Node.js 的應用遍及各類開發或軟體需求。

JavaScript是最普及的語言,而Node.js是最受歡迎的框架

根據 Stack OverFlow 在 2018年度的開發者大調查(全球超過 10 萬開發者參與),JavaScript 是開發者中最普及的技術,近 7 成開發者都會用,比 HTML 或 CSS 的普及率還要要高,而最多人懂的開發框架排名中,第一名就是 Node.js ,將近5成開發者(49.6%)經常使用,比 2017 年還小幅上升了 2 個百分點,同時使用者還在持續增加,遠高於排名第二的 Angular(36.9%),這正是因為 Node.js 是前端和後端工程師都能用的技術。

Node.js 不只是當前的主流技術,也是下一代網頁應用架構 Serverless(無伺服器)架構的關鍵技術。負責 Azure Functions 專案的微軟資深首席軟體工程師 Christopher Anderson 就曾直言,主流無伺服器服務商紛紛把寶押在 Node.js,因為看上了 JavaScript 工具的豐富生態,再加上 Node.js 的輕量化、容易分散與水平擴充、各種作業系統都容易執行的特性,將 Node.js 作為無伺服器服務優先支援的框架,這也讓 Node.js 更適合用於超大規模部署的應用。

Ryan Dahl 自己坦言,從沒想到 Node.js 日後會帶來這麼大的影響。他也將此歸功於開發社群的持續改善,才讓它越來越成熟。截止到2018年8月,參與 Node.js 的開發者已經超過2千人,十年來的更新發布次數超過 500 次,在 GitHub 上程式碼的下載次數更是累計超過了10億次,就連大型科技公司如 PayPal,或頂尖科研機構 NASA 都在使用。

但 Ryan Dahl 在 2012 年開始淡出 Node.js 社群,轉而進入 Go、Rust 語言社群,也重回他擅長的數學應用領域,2017 年還申請了 Google 大腦一年的進駐計劃,成為 Google 大腦研究團隊的一員,擔任深度學習工程師,並投入影象處理技術的研究。直到 2018 年 6 月初,就在 Node.js 準備邁入第 10 年之前,JSConf 歐洲大會再次邀請Ryan Dahl 來進行開場演講。

儘管大受歡迎,但 Node.js 仍有十大技術債

原本 Ryan Dahl 打算在 2018 年的 JSConf 演講中分享自己這款 JavaScript 版的 IPython 互動式資料分析工具,沒想到一直開發到 5 月份,這個工具都還不能用。本來要放棄這次演講的 Ryan Dahl 念頭一轉,乾脆把他重拾 Node.js 後發現的問題拿出來分享,這就是去年引發全球開發社群熱烈討論的那場演講,題目是 “我在 Node .js 最後悔的 10 件事”。Ryan Dahl 在演講中坦言,Node.js 有十大設計錯誤,甚至可說是他的 10 大悔恨(他刻意用Regret 這個詞來形容)!

這些讓 Ryan Dahl 懊悔不已的錯誤,包括了沒采用 JavaScript 非同步處理的 Promise 物件、低估了安全性的重要性、採用 gyp 來設計 Build 系統、沒有聽從社群建議改用 FFI 而繼續用 gyp,另外,他也覺得 Node.js 過度依賴 npm 功能(內建到 package.json 支援是個錯誤)、用 require("")來嵌入任意模組簡直太容易了、package.json 容易造成錯誤的模組觀念(讓開發者誤以為同一目錄下的檔案就是同一模組)、臃腫複雜的node_module設計以及開發社群抱怨已久的下載黑洞問題(下載npm得花上非常久的等待時間)、require("module")功能沒有強制要求註名.js副檔名,以及無用的 index.js 設計。

2012年,Ryan Dahl 離開了Node.js社群,他事後解釋,Node.js 的發展已經步入正軌,也達到他最初的目標,因而決定離開,但在2018年這場演講中,他坦言, Node.js 還有大把問題要修復,所以現在他回來了,要來償還當年的技術債,挽回 Node.js 的設計錯誤。

Ryan Dahl 的答案是打造一個全新的伺服器端 JavaScript 執行環境,也就是 Deno 專案。

deno 如何償還 node.js 的十大技術債
Deno從2018年5月在 Github 開源至今年3月,已有超過100名開發者參與,經常貢獻程式碼的核心開發者也有5名。

讓Ryan Dahl懊悔不已的 Node.js 十大技術債

  1. 沒用 JavaScript 非同步處理的 Promise 物件

  2. 低估了安全的重要性

  3. 使用了 gyp 來設計 Build 系統

  4. 沒有聽大家的建議提供 FFI 而繼續用 gyp

  5. 過度依賴 npm(內建 package.json支援)

  6. 太容易造成 require("任意模組")

  7. package.json 建立了錯誤的模組概念(在同一目錄下的檔案就是同一模組)

  8. 臃腫複雜的 node_module 設計和下載黑洞(往往下載 npm 得花上非常久的時間)

  9. require("module") 時沒有強制加上 .js 副檔名

  10. 無用的 index.js 設計。

Deno 如何挽回 Node.js 設計上遺留的問題

這是 Deno 專案的一個範例,是 Unix 系統基本命令 cat 的一個實現。cat 可以從標準輸入取得檔案, 再逐行把檔案內容送出到標準輸出上。這個範例反映出 Deno 要將 I/O 抽象化和精簡化的意圖。

這是 Deno 專案的一個範例,是 Unix 系統基本命令 cat 的一個實現。cat 可以從標準輸入取得檔案, 再逐行把檔案內容送出到標準輸出上。這個範例反映出 Deno 要將 I/O 抽象化和精簡化的意圖。

Ryan Dahl 希望通過打造 Deno 這個全新的伺服器端 JavaScript 執行環境,來解決 Node.js 的三大問題,包括準確的 I/O 介面、預設安全性(Secure by Default)以及引進一套去中心化的模組系統等,最後一項就是要解決下載過久過慢的老問題。

Ryan Dahl 進一步解釋,雖然他所有的時間都是用 C++、Go 或 Rust 這類編譯式語言來開發,但是他還是有一些經常要做的事,需要使用動態的指令碼程式。例如整理資料、協調測試任務、部署伺服器或使用者端環境、繪製統計圖表、設定構建系統(Build System)的引數或是設計應用雛形等。

可是,這些不同用途的任務,需要切換使用多種不同的指令碼語言或工具,如 Bash、Python 或是 Node.js 等才行,相當麻煩。而 2018 年上半年的這個互動式資料分析工具的開發挫折,更讓他有一股強烈地念頭,能不能有一個通用的指令碼工具。

Deno

Deno 架構

打造一款簡單、好用的通用指令碼工具

Ryan Dahl 在 2018 年 11 月參加臺灣年度 JavaScript 開發者大會(JSDC)時,特別提到:“我不喜歡用不同工具來處理不同的事情,我只想要有一個簡單,直接可執行,拿了就能用的順手工具,這正是打造Deno的初衷。”

簡單來說,Deno 跟 Node.js 一樣都採用了 Chrome 的 JavaScript 引擎 V8,但 Deno 採用了更嚴格的 JavaScript 語法規範 TypeScript,Deno 等於是一個 TypeScript runtime。第一個版本的 Deno runtime 是用 Go 語言實現的,但是 Ryan Dahl 又重新用 Rust 語言開發了一次 Deno 的 runtime,避免因為重複使用兩套垃圾回收器(Go語言一套、V8引擎也內建了一套)而影響效能。另外,Deno runtime 中也內建了 TypeScript 編譯器。

Deno的目標是安全、簡潔、單一可執行檔案

Deno的設計目標是安全、模組簡潔、單一可執行檔案(簡化封裝)等,目前已完成的特色之一,就是可以透過URL 來匯入各種模組,另外預設安全性,要存取實體資源或網路時都需要授權,使用者的程式碼只能在安全的沙箱中執行。為什麼他最熟悉的 Go 做不到?因為“動態語言仍有其必要。“他強調,尤其要建立一個適當好用的 I/O 處理流程(pipeline)時,動態指令碼語言是不可或缺的工具。

而 JavaScript 就是那個他心中的理想動態語言,但是,Node.js 是一項將近 10 年曆史的技術,受限於最初的設計架構,他認為,可以重新用 JavaScript 近幾年出現的特性,重新思考 Node. js 的根本設計,包括像是可存取原始記憶體的標準方法 ArrayBuffers、適合彈性組合的 TypeScript Interfaces,以及新興的非同步機制 Async 和 Await。Ryan Dahl 把這些新的 JavaScipt 功能,放入了 Deno 中,來設計一款新的伺服器端 JavaScript 框架。

但是,這一次,他不想重走 Node.js 的老路,將整個 Web 伺服器放進框架,Ryan Dahl 決定打造出一支自給自足功能完整的 runtime 程式,容易帶著走,而不是有著一套複雜目錄和結構的框架。

而且,打包成 runtime 形式,就可以部署到各種環境中,Ryan Dahl 舉例,如果在無伺服器服務上部署了Deno,就可指定一個網址,就能啟動這個無伺服器服務的呼叫,而不用上傳一段程式碼到無伺服器服務平臺上執行,也可以部署到邊緣運算裝置中,來完成小型的資料處理工作。

不信任使用者的程式碼,只能在沙箱執行

另外在安全機制上,Deno 設計了兩層許可權架構,一個是擁有特權的核心層,另一個是沒有特權的使用者空間,RyanDahl 解釋到,這就像是作業系統的設計一樣,不信任使用者的程式碼,區分出使用者的許可權和系統核心的許可權等級,使用者的程式,要向使用到關鍵的資源,必須透過系統呼叫,由系統核心程式來執行。Deno 也是一樣,“不信任使用者端的 JavaScript 程式,只能在安全的沙箱中執行。”

所有涉及到敏感資源的處理,如底層檔案系統,都需要授權執行,這就是預設安全性的設計,包括網路存取、檔案系統寫入、環境變數存取、執行等這些敏感的動作,都需要取得授權才能執行。

另外,Deno 的設計還將 I/O 處理抽象化,讓 JavaScript 程式不必處理各種不同的輸出或輸入端配置,改由 runtime 接手,從而無法直接接觸實體資源。一來簡化各種不同的 I/O 存取方式,不論是本地或遠 I/O,都是同樣的 read 和 write 指令就可以搞定,二來也可以強化安全性。

另外,Deno 還借鑑了不少 Go 語言的特性,例如 Deno 的 copy() 就參考了 Go 語言的 io.Copy()BufReader() 也參考了 Go 語言的 bufio.Reader 設計等,還有不少測試機制、檔案等,Ryan Dahl 也都參考了他熟悉的Go語言。

指定URL,就能嵌入第三方函式庫

Deno 第三項設計目標是要打造一個去中心化的模組系統,Ryan Dahl 的設計是,Deno 可以像 JavaScript 一樣,通過 URL 網址來嵌入外部的第三方函式庫。除此之外,Deno和Rust語言也有不少整合,甚至改用Rust來實作Deno之後,Ryan Dahl透露,將會建立一個橋接機制,讓Deno可以很容易地運用Rust中的函式庫。

不過他坦言,嵌入外部的第三方函式庫的機制,也是 Deno 專案釋出後,人們詢問最多、也最擔心的功能,擔心透過 URL 來引入外部函式庫後,容易引發安全問題或是中間人攻擊等問題。“這就是為什麼 Deno 要採取預設安全性的設計的原因,來隔絕來自外部第三方程式碼的威脅。”

另外,通過 URL 連結到第三方函式庫時,Deno 會通過快取,在本地環境生成一份第三方函式庫,第二次再呼叫到同樣的URL時就不需再次下載了,以此來加快執行速度。甚至這個通過外部 URL 來引用函式庫的功能,還可以指定版本,就算是改版了,還是可以指向舊版。當然 Ryan Dahl 強調,所有存取外部網路或下載寫入到本地檔案的動作,都需要取得授權才能執行。

未來會支援 WebGL,Deno 就能呼叫 GPU 資源

Deno 還有一個與 Node.js 最大的差異,就是未來會支援機器學習。Ryan Dahl 透露,他們正在開發一個數值計算類的外掛模組,最重要的就是要能支援 GPU,這也是機器學習模組最需要的功能。“Deno未來將會原生支援 WebGL,就可以讓 JavaScipt 程式呼叫 GPU 的資源。這是他打造 Deno 的目標之一。”甚至,Ryan Dahl 預告,未來說不定可以把 TensorFlow JS 放上 Deno 來執行,因為 TensorFlow JS 用的也是 WebGL。

Deno未來將瞄準小型機器學習的推理需求

不同於 Nvidia的CUDA 可以用來排程多顆 GPU 資源進行復雜的機器學習訓練工作,Ryan Dahl 解釋,Deno 想要提供的是簡單夠用的機器學習能力,可以用來滿足只有單顆 GPU,而且是小型或是隻需要推理的計算需求,支援WebGL 已經夠用了。

Deno 從 2018 年 5 月中放上 Github 網站開源至今年3月,已有超過80名開發者參與,經常貢獻程式碼的核心開發者也有 5 名。目前正把主要精力放在在預設安全性架構的設計功能上。

最後企業能不能用 Deno?Ryan Dahl 坦言 Deno 距離 1.0 還有很長一段路要走,仍舊是一個非常新的技術。不過,“再等我1年,若有企業想用,請Email給我,我會提供技術支援。” 他認真地說。

關於Ryan Dahl

deno 如何償還 node.js 的十大技術債
deno 如何償還 node.js 的十大技術債

2009年11月8日,Node. js之 父RyanDahl在歐洲 JSConf 大會,第一次釋出了 Node.js ,一鳴驚人,將瀏覽器端的 JavaScript 技術,帶入了伺服器端應用領域。不過他從 2012 年開始淡出 Node.js 社群,轉而進入Go、Rust語言社群,2017年加入 Google 大腦研究團隊,擔任深度學習工程師。現為自由開發者。

2018年6月初,Ryan Dahl 在 JSConf 歐洲大會發表了 Node.js 十大悔恨,並推出了新的伺服器端 JavaScript runtime 方案 Deno。

歡迎關注京程一燈公眾號:jingchengyideng,獲取更多前端乾貨。

相關文章