這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
golang 和 Node.js 身為當今語言兩大新貴,在使用這兩者的時候常常會互相對比一下。對文法上來講,個人還是最喜歡 golang 的簡單和創新。而 Node.js 最讓我滿意的則是 npm 。但是在此主要說說兩者包管理對依賴處理的解決方案差異。
先說說 golang 的。golang 對依賴的處理宗旨是讓你 察覺不到依賴是遠端還是本地的倉庫 。一切都是通過 go get
來實現。只要在源碼裡面是
import "github.com/username/projectname"
在 go get
的時候工具自動幫你下載該依賴的源碼包。這樣看上去非常簡單,操作簡單,但是卻給我帶來了不少困擾。
比如當我們今天需要依賴項目 pA 所以在源碼裡面寫上
import "code.google.com/uA/pA"
但是有天你發現 code.google.com
被牆且翻牆不易,你想使用 github.com
上的鏡像倉庫。你就需要修改含有這句 import
的源碼。也就是,對於 golang 來說,倉庫依賴和源碼耦合在一起 。又或者,你在 github 上面 Fork 了該項目,
從 github.com/uA/pA
Fork 成 github.com/uB/pA
。
而該項目的源碼裡面存在 import "github.com/uA/pA/sub1/"
之類的依賴本項目子目錄包的語句。而你 Fork 之後,go build
就會報錯說找不到 github.com/uA/pA/sub1
這個包裡。這個問題說白了不是什麼新問題,比如在 C/C++
中,#include "xxx"
時,xxx 的路徑應該是寫相對路徑。而不能寫絕對路徑,因為當你寫上絕對路徑的時候,比如 #include "/home/yanyiwu/code/xxx"
,這樣的話,源碼就喪失可移植性了。當然對付這個問題的話也是有現成的解決方案的,只是這個解決方案不是完美解決方案。
具體請看 using-forked-package-import-in-go 。
而對於 npm 的話,這個事情就簡單很多。因為 npm 的包管理原則是 集中式管理 ,當你使用 npm publish
發布一個新包的時候,你的代碼是被上傳到 npmjs.org
上集中管理。所以當你使用 npm install
安裝一個新包的時候,你的代碼是從 npmjs.org
下載得到。當然這樣集中式管理有單點故障,比如 npmjs.org
掛掉了或者被牆了就要悲劇? 回答是否定的。因為 npm 也支援指定倉庫下載,比如在天朝內,勤勞自強的程式員們就搭建了一個國內的鏡像 cnpm ,而且速度非常不錯。使用鏡像也非常簡單,比如這樣:
npm --registry=http://r.cnpmjs.org install koa
具體用法可以參考 faster-npm。
說到這裡,就可以注意到差別是在哪裡。就是對於依賴管理。Node.js
的包管理解決方案是和源碼無關的。在 Node 源碼裡面是不需要管這個包在哪個倉庫下面。就拿 koa 這個項目來說,在 koa 的 package.json
裡可以看到:
"dependencies": { "accepts": "^1.1.0", "co": "^3.1.0", …},
裡面依賴了 accepts
這個包,在 koa 的源碼裡面直接 var acceps = require(‘accepts’);
即可,源碼並不需要知道 accepts
源碼的倉庫是在 github.com
上面還是 gitcafe.com
上面。而且,由 npm 通過 package.json
檔案來統一管理的另一個好處是依賴非常清晰,可以看到所有的依賴和對應的版本。一目瞭然。npm 這種集中式包管理的好處也能避免 golang 裡面 包管理和源碼 耦合在一起導致的問題。所以個人看來,npm 的包管理解決方案確實是比較好。 希望 golang 的之後的改進裡面能參考一下這種解決方案。
其實現在國內的技術論壇有個風氣不太好,就是當發表一些不同語言的分析對比時,總是會不可避免引起各種語言粉的敵意。就比說我說 golang 的包管理解決方案確實不如 Node 的 npm 。就會 golang 粉們覺得我是專門來挑刺踢館的。其實我也是 golang 粉,所以真心對於這種敵意很無語。