今年是舉辦 ECUG Con 的第 11 年,之前我談的基本都是服務端的開發實踐。從去年起我開始不談後端而是談前端。當然,去年我沒有說為什麼我會關注前端。今天再談 Go 語言在前端的應用之前,我先簡單聊一下思路脈絡,為什麼我今天會關注前端。
前端的演進
最早的 PC 時期,常見的裝置主要是桌上型電腦、筆記本。這兩類裝置是 PC 時代主流裝置,用的作業系統主流的是三個,分別是 Mac 、 Linux、Windows。前兩者市場佔有率非常少,基本是 Windows 一統天下。瀏覽器早期因為 Windows 的流行,主要是 IE,但在今天 Chrome 市場佔有率非常高。另外還有 Safari、Firefox,大家也都耳熟能詳。
從蘋果釋出 iPhone 為標誌,我們開始進入移動時期。這個時期的裝置主要是手機和平板,以手機為主。作業系統基本是安卓和 iOS,像 Windows Mobile 之類的佔比非常少。瀏覽器不是 Chrome 這類桌面瀏覽器,而是從微信小程式開始,有了移動時代的瀏覽器。在國內小程式的種類非常多,包括支付寶小程式、頭條小程式等等。我認為這才真正是移動瀏覽器戰爭的開始。
比較奇怪的是,為什麼移動瀏覽器之爭沒有在美國開始,而是在中國開始,這也是比較有意思的地方。小程式相關的技術,無論是谷歌還是其他公司,也都在琢磨,當然也可能是我孤陋寡聞,我沒有看到國外出現移動瀏覽器的跡象。為什麼我說 Chrome 這些不是移動下的瀏覽器,是因為操作手感差別非常大。微信小程式是第一次試圖讓 BS 結構的應用和 Native 應用手感無差別,這是非常重要的嘗試。
我也暢想了一下未來,移動時期裝置還比較少,筆記本、手機、平板是最主流的裝置。桌上型電腦今天不太見得到,但筆記本大家經常會用。ECUG 是在 2007 年,差不多蘋果釋出第一代蘋果手機時開始的。在那時候,我做了一個判斷,未來是一個強悍的服務端加上多元化的終端,其實就是前端。但今天在我看來,前端多元化還沒有真正意義上的出現。
在 ECUG 的第 11 年,可以看到這個多樣化的趨勢已經越來越趨向於現實,包括手機之後下一個前端戰場,在我看來是汽車。汽車非常火爆。當然,會有更多裝置,很多人都會認為下一個是所謂的物聯網時代,我們不必談這麼抽象的名詞,也能預測到未來前端的趨勢會非常多元化。這個多元化和 PC 時期、移動時期都非常不一樣,因為螢幕的尺寸在前端互動裡佔非常關鍵的因素。除了汽車,今天手錶也蠻多,但普及率可能還不如手機和平板。手錶是一個很特別的東西,它在這麼小的螢幕上,要把前端玩出花來,其實是非常難的事情。未來作業系統到底會是怎麼樣的?今天還是未知狀態。
前端的演進跟裝置演進非常有關聯。所以前端的演進是大起大落的,這和服務端非常不一樣。服務端的發展非常穩健。作業系統偏 Unix 係為主,到今天仍然如此,不太劇烈變動。但前端由於終端變化,導致作業系統的演進非常劇烈。
雲端計算的演進
雲端計算的演進,我分三個階段:第一階段,以亞馬遜的 EC2 為典型代表的,我叫做機器計算階段。虛擬機器(VM)為基礎構建了整個體系結構。虛擬機器和物理機沒什麼區別,現在大家摸不到虛擬機器,但從操作一臺虛擬機器手感來說和物理機區別不大。
今天看到很多不一樣的地方,因為容器興起了,從 2014 年開始興起到今天典型的標誌是 Kubernetes 一統了容器作業系統的天下。以這樣的基礎,能看到雲端計算演進到了第二階段。容器計算時期和機器計算時期的計算不太一樣,容器會越來越關注運維的自動化以及相關基礎支撐,它最終要達到的目標是讓服務端基本趨向於免運維。以後大家做業務時,基本不用太在意服務端的事情。
這也會帶來另外一個問題,再下一階段雲端計算會走向哪裡?在我看來是應用計算。因為雲已經隨著容器技術的發展越來越標準,雲端計算下一階段應該會偏向於業務,和業務做越來越強的融合,不再只是關注基礎架構,而是關注應用本身的業務架構。應用業務架構裡,端佔非常大的成份。雲端計算和端並不是割裂的。
雲+端的演進趨勢
今天我為什麼會談前端?當下我們仍然在很努力地推進後端技術的標準化,但在我看來,在可以預期的幾年內這個事情就會被解決,更遠的未來一定會把精力花在前端。
很多人都知道七牛雲跟 Go 語言非常有淵源,我自己大概在 2012 年也比較狂妄地做了一個預測,認為 Go 語言一定會進語言排行榜第一,我設的時間是 10 年左右。2012 年到現在差不多進入第 7 個年頭。Go 是很專注的語言,用 Go 的人基本都集中在後端的開發,而且是偏向於後端 API 層面的開發,Web 佔比相對少很多。Go 的專注使得它今天基本佔領整個雲端計算領域。很多雲端計算公司技術棧,Go 在裡面的佔比會越來越高。這樣的專注也讓 Go 語言在今年裡程碑式地進入前十的排名。
Go 語言的演進
為什麼 Go 語言適合做前端?
前端需求量最大
前端是開發人員最多,需求量最多的工種,對語言的要求一定是入門門檻比較低,心智負擔最小。而這個非常適合 Go。我 2011 年推 Go 時,大部分人不太瞭解 Go,但今天 Go 語言的受眾已經非常廣,大家有很大共識的一點是,Go 語言的入門門檻非常低,心智負擔比較少。基本程式寫出來編譯透過,大機率沒有問題。這樣的特性使得它非常適合前端。
前端需要工程化更強的語言
前端業務量非常大,所以前端程式碼量比後端多很多。前端是負責和使用者打交道的,和人打交道的東西是最複雜也最容易發生變化的。今天可能這個知識更好,明天可能換了一種新的知識,尤其是我前面提到了端的變化。從 PC、筆記本到手機,螢幕尺寸不一樣,以及過去以鍵盤為互動主體變成了觸控式螢幕,再到未來手錶或者汽車。為什麼很多公司都關注語音互動,就因為像汽車、手錶這樣的裝置,語音互動是一個比較好的手段。但這些都有很大的不確定性。前端的變化是很劇烈的,而互動的手感以及為了讓使用者舒服、爽,程式設計師要付出的努力也會是非常大的。前端的程式碼量一定是最多的。
前端非常需要有強工程化能力的語言。今天我們看到前端最大的程式碼量肯定是 JavaScript,但 JavaScript 幾乎是沒有工程化支援的。它之所以叫 Script,是因為小,類似於微信小程式。大家仔細想想,小程式一定不小。在這樣一個不小的東西上,或者程式碼量更多的應用裡,需要工程語言更強。JavaScript 為什麼流行,是因為它的「壟斷地位」。有個趨勢已經發生了,但今天還不是特別強烈,就是會有越來越多語言進軍前端,Go 只會是其中之一。這是由需求決定的,我也認為 Go 是最有希望的那幾個之一。
前面談為什麼我會在 ECUG Con 談前端,今天我講的東西,也許對大家影響不會太大,因為 Go 做前端畢竟還非常初級,但 ECUG Con 我希望它是一個前瞻趨勢探索的會議,我並不傾向於它一定是非常實用的,它不需要今天跟大家聊了,明天就把它用到工程上,我對它並不是這樣的定義。我希望 ECUG 本身是一種對未來有預見的社群。
Go 在前端的進展
回顧 Go 在前端的進展,GopherJS 是第一個真正產生了影響力的進展。在 GopherJS 之前有非常多人做前端相關的事情。谷歌也有人推出了一個框架叫做 GXUI,GXUI 今天已經不怎麼維護了。
很多人會試圖做跨平臺的框架,但實際上跨平臺的框架最有希望的一定是瀏覽器。因為瀏覽器就是跨平臺框架。在我看來,像 QT 包括谷歌做的 GXUI,都相對比較侷限。但 GopherJS,我認為它是在前端第一個真正能立得住腳的嘗試。他就是幹我剛才說的事情,讓 Go 語言的程式設計師能寫前端。怎麼寫?它做了一個編譯器,這個編譯器把 Go 程式碼翻譯成 JavaScript 程式碼,自然而然 Go 就能寫前端了。它是把 JavaScript 作為前端的一個機器語言,因為 JavaScript 的位置是繞不過去的。
但也不見得真的繞不過去。前端的機器語言在今天的標準肯定是 JavaScript,但我們也看到了另外一個東西,叫 WebAssembly,顧名思義它將自己看做是 Web 的組合語言。但其實這個 WebAssembly 是二進位制的,我覺得說它是 Web 的組合語言,不如說它是 Web 的機器語言。WebAssembly 的覆蓋面比大家想象得要廣,今天所有主流的瀏覽器都已經支援了。JavaScript 的「壟斷位置」已經有一些變化了,它並不會一直這樣壟斷下去。大家可能也聽過 Go 已經支援 WebAssembly,而且是語言內建支援,這對 Go 來說也是非常重要的。
Go 在前端的進展,第二個大里程碑事件是 Go 內建支援了 WebAssembly(https://github.com/golang/go/wiki/WebAssembly)。從 Go 的 1.11 版本開始。這是 Go 官方對 WebAssembly Go 支援的介紹,編譯過程是把 GOOS 環境變數定義成 js,架構選 wasm,這樣就可以編譯出 wasm 檔案,而不是本地的可執行程式。這裡有一些 DEMO,是一些社群的人用 Go 寫的 WebAssembly 樣例。
DEMO 樣例展示:
https://stdiopt.github.io/gowasm-experiments/
https://justinclift.github.io/wasmGraph1/
https://stdiopt.github.io/gowasm-experiments/splashy/
這展示的效果就是後面的原始碼實現的。看起來好像也沒有什麼,但這個支援是非常關鍵的。Go 開始在語言內建就支援 Web 前端的開發。儘管今天它還是一個經驗版的狀態,但也是非常重要的里程碑。做這件事情的人和前面幹 GopherJS 是同一波人。有那麼一堆人他們在努力把 Go 推向前端。
前面兩個如果大家關注 Go 語言應該比較多人知道,但接下來這件事情應該大部分人都不知道。有一個新東西叫做 TinyGo,它是在嵌入式裝置上跑 Go,它是一個剪裁版的 Go(https://github.com/aykevl/tinygo)。因為 Go 主要是針對服務端開發,所以大家對 Go 編譯出的可執行檔案有多大一點都不在意,但如果留意過就知道它非常大。TinyGo 試圖讓編譯出的檔案足夠小,因為在嵌入式裝置上磁碟空間非常珍貴,記憶體也很珍貴。它居然也支援 WebAssembly,能夠做 Web 開發,雖然裁掉了很多 Go 的特性。不知道它後面的演化怎麼樣,因為這個專案還非常新,不到一年。對於新出現的東西,我們只能關注,也沒有辦法真的用到什麼工程上。
Go 2D 遊戲開發引擎(https://github.com/hajimehoshi/ebiten),實際上 3D 已經出現了,今天沒有列出來。這個遊戲引擎是日本人做的,而且已經拿它做了多款的手遊開發。它是一個已經商業化的引擎。支援的平臺非常廣,用這個遊戲引擎做出的遊戲能夠支援 PC 作業系統如 Windows、Mac、Linux、FreeBSD,也支援手機作業系統 Android、iOS,還支援 Web 開發如 GopherJS、WebAssembly。它是一個生產級的引擎。我去年演示的 DEMO,用 Go 寫了一個少兒程式語言 Scratch 的解析器,這個解析器就是用這個 2D 遊戲開發引擎做的。
下一個有趣的東西是 Go 的前端程式碼託管(https://github.com/dave/jsgo)。JavaScript 有很多公開的前端程式碼託管,但這裡出現了 Go 前端程式碼託管。直接往這裡一扔就直接上雲了。這看起來很小眾,但有人幹這些事情。
這也有一些 DEMO:
這是一個拼數字的遊戲。
https://jsgo.io/hajimehoshi/ebiten/examples/2048
這是俄羅斯方塊。
https://jsgo.io/hajimehoshi/ebiten/examples/blocks
這是一個遊戲,大家之前見過的版本是小鳥,不是土撥鼠。
https://jsgo.io/hajimehoshi/ebiten/examples/flappy
這是一個 To do list 類的 Web 應用。加它只是為了展示 Go 也能做一個標準的前端開發。
https://jsgo.io/dave/todomvc
Jsgo.io 既支援 GopherJS 也支援 WebAssembly。我們剛才看到的遊戲,不是一個 js 檔案,是很多個。原始碼裡,Go 會 import 一些 Go 標準庫,比如字串轉換庫 strconv。字串轉換 Go 標準庫會直接被編譯成一個單獨的 js 檔案。這個做法的好處是第一遍慢一點,但後面的載入會非常快(因為基本不用改)。大的前端應用這樣被拆解之後,從長遠來說載入速度會比較快。它支援分模組載入,而且我們不用為分模組載入付出什麼努力,Go 的引用最後會變成一個模組引用,對應到 js 也是一個模組。這樣程式設計會非常爽。前端 JavaScript 語言裡,這種模組化程式設計並不是語言內建支援的。
Jsgo.io 對 WebAssembly 的支援目前還不體完善,跟剛才的 GopherJS 不一樣,它目前不能做到分 package 引用,編譯出來的是一個大的 wasm 檔案。但這只是臨時狀態,因為這塊的支援才剛開始做。
前面我也說過,Go 的通用卡平臺 gui 庫很多人在嘗試,但無一不是失敗告終。這並不是由於 Go 引起的,是因為像 QT 這類的跨平臺方案本身並不是符合趨勢的東西。最有希望的跨平臺方案還是瀏覽器技術,基於 HTML5 和小程式,它們是真正的生產級的跨平臺方案。尤其是小程式的出現,今天看到很多跨平臺庫,比如 React 做出的應用還是有生硬的地方,但微信小程式是第一個試圖讓 Web 跟 Native 體驗一致的。
Go 在前端的發展展望
Go 跨平臺的遊戲引擎,已經基本接近生產級,它是非常重要的突破口。
在我看來,Go 第一個在前端的突破,一定是從遊戲領域開始。它對 Go 的意義是 0 到 1 的歷史性突破。如果沒有商業公司用它,這個東西就是一個玩具。但 Go 的遊戲引擎不會是玩具,因為會有越來越多商業公司用它。未必是這個遊戲引擎,也許會有人做出更牛的,但這是個靠譜的方向。對於 Go 來說,就跟 Docker、Kubernetes 的流行代表 Go 佔領了雲一樣。Go 在前端也需要一個殺手鐧,它就是遊戲引擎。