360高級前端架構師Hax(賀師俊):前端開發編程語言的過去、現在和未來

在日前的 GMTC 全球大前端技術大會上,360高級前端架構師賀師俊發表了《前端開發編程語言的過去、現在和未來》的演講,本文整理內容如下。

對待編程語言的態度

關於編程語言我首先想講一個事情,就是討論編程語言時,我們經常會看到兩種非常極端的態度:

  • 一種就是“XXX語言最好!”XXX可以是任何一個語言,比如PHP🤪。如果討論的時候你不附和他的觀點,就可能給你一個鄙視臉。

  • 另外一種,就是“所有語言都一樣!”當我們討論不同語言的特性優劣,他也會給你鄙視臉。

雖然這兩種態度看似截然相反,但這兩種態度的結果是一樣的,就是討論繼續不下去了,所以你看各種技術羣裏涉及編程語言的討論往往要麼曲高和寡,要麼迅速以“PHP是最好的語言”或者“語言都一樣”這樣毫無意義的廢話(按照復讀機隊形)收場。排除調侃和灌水的成分,本質上,這兩種極端態度背後的原因是類似的——人們總是高估短期,低估長期。

編程語言,以我的看法,不太可能是項目成敗的決定性的因素。但是長期來看,編程語言,作爲程序員創造軟件的核心工具,會影響團隊長期的生產力。這是我們爲什麼應該摒棄那些極端態度,投入一定的精力去研究和發展編程語言。

前端語言的特點

GMTC是大前端技術大會,所以我們這次討論前端和移動端開發中的編程語言。以下簡稱前端語言。

前端語言有自己的特點,也就是和一般非前端領域的編程語言有區別。如果我們觀察前端語言,會發現有兩個特點:

前端語言與平臺高度相關

什麼叫平臺高度相關呢?比如說今天我們要在iOS平臺上開發新應用,那基本上就得用Swift語言。反過來說,你要在其他平臺上開發新應用,就不太可能選擇Swift。

相比較而言,後端開發就沒有這麼強的約束,因爲後端服務並不是說非用哪個平臺,比如Java、.NET不可,完全可以用PHP、Go、Python、Ruby等各種語言寫,百花齊放。就算用Java或.NET平臺,也有多種語言可選。而前端開發中,語言和平臺具有強相關性,整個技術棧的選型中,選平臺和選語言是一而二二而一之事。

這會造成一些困擾。比如說因爲你看到了Flutter這個平臺非常好,所以你就用它,可你也一併選擇了Dart語言,但是很有可能你其實不是特別喜歡Dart語言——尤其如果我們已經很依賴Kotlin/Swift語言所提供的某些高級語言特性時。

也有另外一種情況,比如,假設你的團隊一直使用JavaScript/TypeScript,並對整個JS/TS生態裏已經有很大的投資(如積累了大量庫,自行研發了許多工具等),所以不想放棄這樣一個技術棧,那在這樣的情況下,很遺憾你現在就沒有辦法選擇Flutter平臺。所以我們會發現,在前端開發過程當中就有這個技術棧選型上的約束:編程語言跟平臺高度相關。

前端語言與領域高度重合

如果我們講前端語言,不管哪一個語言,它其實都是以前端應用某特定領域爲首要目標,所以問題領域是高度重合的,面臨的挑戰也是共通的。

比如都要處理界面和交互。許多其他編程語言就不一樣,它們各自有一些獨特的特點,擅長不同的領域。比如說Erlang就很適合用來開發分佈式系統,它本來的設計目標就是針對這種場景,並且有針對性的、獨特的併發模型和容錯機制等。

再比如說像大數據、人工智能領域就首選Python。而Go就常見於網絡服務層、雲設施。甚至像Coq這樣偏學術的語言,因爲其具有形式證明能力,被運用於金融、區塊鏈等領域。所以雖然都是通用編程語言,但不同語言可能有非常鮮明的特點,主攻領域有很大不同。而前端語言,雖然各平臺有各自的語言,但其主攻領域其實是高度重合的。

前端語言的過去

從這兩個特點伸發開去,我們來看看前端語言的過去、現在和未來。其實這個標題有點大,這裏只能把個人在這方面的觀察和思考跟大家分享一下,希望能引發大家的思考。

先看一下過去。這裏講的“過去”,是比較近的過去,更早的就不講了,比如最早移動開發是用J2ME,這個就太古早了。這裏我們還是以智能手機爲起點,也就是Android、iOS時代。

過去三個主要平臺的語言,在Web就是JavaScript(下簡稱JS),Android就是Java,iOS就是Objective-C(下簡稱OC)。

爲什麼前端很少用其他編程語言

那麼是不是可以用其他編程語言呢?

在Web平臺確實還有不少其他語言,各種altJS(可編譯到JS的其他替代性語言),以前一度CoffeeScript也挺流行。但是從整個發展來看,雖然我們總是可以用其他語言編譯到JS,然而隨着ES6的興起,總體趨勢還是重新迴歸了JavaScript。

Android用Java,理論上Java平臺上的其他語言也可以用,比如Groovy、Scala、Clojure等,但是這樣一種實踐,也不是特別流行。

爲什麼呢?原因可能各種各樣。比方說工具鏈不匹配。像構建,Scala用sbt而Android用Gradle。不是說不能解決,但需要花費開發者額外的精力。還有些問題可能就是無解的。比如,當你用另外一個語言,它通常有自己的標準庫。對於前端和移動端來講,你發佈的應用,用戶要通過網絡下載,就有一個大小的問題。如果你使用其他語言,雖然可以編譯過去,但是還要帶上他的庫,就使整個包變大。額外的runtime庫造成發佈包變大,對後端來說倒是無所謂,前端就很敏感。尤其是一些大公司的app非常複雜,由多個團隊共同開發,其包的大小限額也是要在多個團隊裏分配的,即使其中一個團隊認爲引入新語言有極大的好處,但你怎麼能說服所有團隊爲業務代碼以外的代價買單?非常困難。

爲什麼CoffeeScript能一度流行,很大原因是它選擇了聚焦於語法改進,不需要任何額外runtime庫的路線。然而這也限制了它的發展,當ES6也很大地提升了語法便利性之後,CoffeeScript的價值就大大下降,走向衰落。

實際上Swift也有需要打入runtime庫導致應用變大的問題,但是它是Apple的親兒子,所以大家確信這只是暫時的問題,我們看到最新的Swift 5就解決了這個問題,新版的iOS操作系統已經內置了庫。但是想象一下,如果是其他語言呢?

所以總體來講,雖然存在使用其他編程語言的這個可能,但是在實踐上,無論Web、Android還是iOS平臺,整個前端來說,我們在真正production裏還是比較少採用其他的語言。
但是呢,這些上一代的前端語言確實是存在一些問題的。

JS的問題

什麼問題呢?我們先講JS的問題。主要就是:不適合PITL。

PITL就是programming in the large,大型編程。所謂大型編程,時間和組織兩個維度,一個是這個軟件或服務有比較長的生命週期,另一個就是這個產品或項目有比較大的團隊需要多人協作,滿足任何一條,就可以算大型編程。

JS這個語言當年設計的時候,不是爲大型編程這個目標設計的,它的初衷,就是爲滿足在頁面上做一點動態效果的需求,所以JavaScript名副其實是一個script(腳本)語言。所謂腳本,很多時候就是一次性書寫甚至一次性運行,用後即拋。傳統上,腳本語言的設計目標就是方便使用,怎麼易用怎麼來,所以在很多方面並不適合大型編程,甚至背道而馳。比如說大家都知道JS的弱類型隱式轉換問題,像臭名昭著的“三位一體”,雖說是吐槽,但實踐上也確實會造成隱患,所以當團隊要進行“大型編程”,就必須用linter等工具去給語言的設計缺陷擦屁股。

Java的問題

Java又是什麼問題呢?其實Java本身是非常好的語言,到目前爲止仍然是我們整個行業最重要的編程語言。

Java的問題就是Oracle。Oracle的各種槽點就不說了,在Android平臺來說,最主要的就是和Google的官司。這個是非技術的因素。

技術的因素也有。Java雖好,但有一個問題:儘管Java最初也是“前端語言”(早期設計目標是用於嵌入式設備和Web),但Java最成功的領域是在服務器端。那麼這個語言的演化就要考慮服務器端,不能僅僅因爲前端和移動端有一些新的需求,就把一個語言特性加進去,而是要考慮更廣泛的場景來衡量這樣一個特性是不是值得加進去。

而我們知道,服務器端跟前端、移動端還是有一些差別,比如說平臺更新迭代的速率和普遍性,對backward compatibility的要求,對性能如內存佔用、啓動時間的需求,等等。這種不同會不會對社區心態產生不同的影響從而對語言的演化也產生影響?這或許是一個可以思考的問題。

OC的問題

Objective-C是非常獨特和有趣的語言,它有一個問題是和其他主流工業語言存在一定的gap。最簡單的例子,我們看OC代碼的命名風格,都是非常的長,比其他語言長得多。爲什麼那麼長呢?一個原因是其代碼風格就鼓勵自說明的、接近英文自然語言表達的、完整到有時覺得冗長的名字。另外一個是,OC中,參數名也是命名的一部分,方法名字和後續參數名合在一起構成整個的命名。最終效果就是在其他語言中字符串替換方法名就是一個簡單的“replace”,而在OC中則是“stringByReplacingOccurrencesOfString:withString:”。加之OC的詞法比如括號運用也和其他語言不太一樣,完整一個語句大概長這樣:

newString = [oldstring stringByReplacingOccurrencesOfString:@"oc" withString:@"swift"];

雖然說,坊間流行“Java和JavaScript的關係是雷鋒和雷峯塔的關係”,但Java和JS的切換其實並沒有那麼難,至少語法是很接近的。但是從Java、JS這樣的主流工業語言切換到Objective-C就障礙比較大,光語法和命名這些比較表面性的東西就已經沒那麼容易適應了。

當然OC還有其他的問題,像性能、內存安全性等。但我個人認爲OC和其他主流語言的過大差異或許是最大的問題。

前端語言的現在

我們看一下現在前端編程語言的狀況,可以看到很明顯的變革。在Web平臺,大量新的應用全線轉用TypeScript,還在維護的老項目遷移到TypeScript的案例也不在少數,尤其是在大廠,這個趨勢更加明顯。在Android平臺,則是Kotlin,最近的統計是超過50%的Android程序員已經切換到了Kotlin。而在iOS,當然就是Swift。除此之外,我們還有了一個新的平臺,就是Flutter,它引入了一個“新”語言:Dart。

我們發現,所有的端,這些平臺,都在比較短的一段時間內,從老的語言進化到新一代的語言。這不知道是不是巧合(實際上巧合背後往往是有原因的)。

前端語言平臺欽定

這些新語言,與一般的編程語言有什麼特別的不同呢?首先,我們之前已經提到過平臺和語言的關係。你會感覺到前端的編程語言似乎都被平臺所“欽定”。

比如Kotlin就是Google宣佈作爲首要支持的語言。Swift是Apple主推的。TypeScript雖然說微軟沒法“欽定”它,但TypeScript本身是JS和類型系統的結合,而JS是Web平臺唯一語言,讓TypeScript也附帶獲得了“欽定”。TypeScript在享受JS的紅利的同時,也通過更好的工具支持反哺JS生態。整個JS生態正逐步進化爲“JS/TS”生態。

最後還有Dart,這個語言其實已經誕生好幾年了,在Web和Android平臺上尋求發展接連受挫之後,終於獲得了Flutter平臺“欽定”從而起死回生。總之,前端各平臺上所有這些新語言和上一代語言一樣,我們感覺都是“欽定”。

編程語言的跨端和全棧

雖然是平臺“欽定”,但是我們可以發現,所有這些語言他們都不滿足於被“欽定”的那一畝三分地,它們都在走向跨端和全棧,突破單一平臺。

像JS/TS,Node.js在全棧開發上已經很多年,很成熟了。跨端方面,則有Cordova、React Native、Weex、NativeScript等各種跨端方案。再說Dart,其實Flutter“欽定”了它必須能跨端。Dart既有standalone VM,又可編譯到JS和Native。基於native,可以跑在Android和iOS上,基於dart2js則有Flutter for Web,standalone VM則給予其全棧的潛力。

Kotlin語言在語言設計之初也設定了多target的目標,可以編譯到JVM、JS和Native,所以無論跨端還是全棧也都沒有問題。相對來講,Swift在跨端方面較弱,儘管技術上說Swift經過LLVM編譯到native,你當然也是可以用Swift寫Android應用的,社區也有這樣的嘗試,但Apple對此缺乏動力,不太可能像Dart和Kotlin那樣有官方支持。但是全棧道路是沒有障礙的,Apple還建立了SSWG(Swift Server Work Group)來推進。此外Swift也可能會官方支持編譯到WASM來支持Web平臺。總之,各語言都在不斷髮展其跨端和全棧的能力。

JS/TS仍然是跨端和全棧能力最強的語言

這些語言當中,總體來看,JS/TS仍然是跨端和全棧能力最強的語言。Web自不必說,Android、iOS系統也都是帶有完整的JS引擎的,至少語言本身的標準庫是無需額外成本的。也因此JS本身就是一個編譯target。基本上現在所有的新語言都把能夠編譯到JS作爲必須達成的目標。

如果一定要說JS的弱點的話,可能是缺乏編譯到Native的能力。雖然JS引擎高度優化,但在極致性能上仍然沒法跟Native比。但我們現在有WebAssembly!JS引擎同時也是WASM引擎。當我們發現有性能瓶頸,就可以使用其他語言如C、C++、Rust等編譯到WebAssembly從而獲得基本接近Native的性能。這樣在基於JS的解決方案上就補上了這一環。

從前到後易,從後到前難

談到跨端和全棧,前面講的都是出身前端或移動端的編程語言。當然我們也有其他的新的老的語言。那些語言不是說不想做前端,我們發現很多其他語言都嘗試過往前端發展,但是都不是很成功。我們可以看到一門編程語言要擴張領域,從前到後比較容易,從後到前就比較難。
這個可能有很多原因了,像之前講到的非平臺欽定語言可能需要額外的runtime庫就是一個問題。還有比方說架構思想的差異。語言的發展還是首先來自於開發者的需求。“從前到後”的開發者,通常傾向於把前端和後端視作對等,因而採用前後端分離的架構。而對於“從後到前”的開發者來說,出發點可能反而是希望消除前後端分立,把前端作爲一個位於整個系統邊緣的表現層來解決。從歷史上看,這種架構實施起來難度較大,很難平衡用戶體驗需求和抽象複雜度。雖然這其實並不是語言的鍋,但會影響大家對語言適用領域的看法。當然可能還有很多其他原因,我這裏不具體展開了,大家可以考慮後面有一些什麼樣的因素。

新一代前端編程語言趨同

我們前面看到了不同的新的前端和移動端的編程語言,當然它們像它們的前輩一樣,仍然會有許多不同,因爲在整個發展過程當中,一定要考慮之前的、建立在上一代編程語言上的技術資產。但是總體來說,我們可以發現,這些新一代前端語言是趨同的。

語法

我們發現,新一代前端語言的語法比原來更加接近。很多較新的特性幾個語言都有,而且語法是基本一樣的。

比如說“?.”運算符,提供了更簡潔的null-safe的屬性訪問語法,Kotlin、Swift和Dart都支持。JavaScript也早就有提案,但是語法上有一點爭議,所以一直沒有進展,這也導致TypeScript團隊拒絕實現該特性。不過本月(2019年6月)月初時終於達成一致意見,維持了和其他語言一樣的“?.”符號,提案也進入到了Stage 2。我們也可以期待儘快能在TypeScript中使用該特性。

語法的趨同上,最明顯的當然是OC到Swift的轉變。Swift現在跟其他語言是非常像的。包括命名風格,比如前面提到的那個OC的“stringByReplacingOccurrencesOfString:withString:”,在Swift裏就簡化了,現在是“replacingOccurrences(of: …, with: …)”,並且藉助extensions特性, 程序員可以自行加入和其他語言完全一致的“replace()”,這樣寫出來的代碼和其他語言就幾乎完全一樣了。

類型安全

另外所有新的語言都進一步加強類型安全。

首先就是靜態類型支持,像TS就給JS把靜態類型加上了。OC本來有很多地方也是動態類型的,現在Swift則是完全的靜態類型。靜態類型的引入,對大型編程是非常有幫助的,比方說讓IDE能具有準確的代碼提示和自動完成的能力。

儘管是靜態類型,但我們並不需要在每個地方都顯式聲明類型,因爲這些新語言都大量使用自動類型推導,既獲得了靜態類型的好處,也沒有劣化開發者體驗。很多時候我們甚至覺得,如果你的代碼大部分是膠水代碼或應用邏輯,尤其是編寫UI的時候,好像和用動態類型的語言寫出來的代碼沒有什麼區別。

這些新一代語言也都支持泛型。不是所有靜態類型的語言都支持泛型,比如Go(當然Go 2.0也要加入泛型)。泛型對於網絡服務開發來說或許不一定那麼重要,但對於應用開發我認爲還是相當重要的。

我們日常開發中經常使用容器類,泛型對於容器類的類型安全來說必不可少。
還有non-null和null-safe,前面提到所有編程語言都在加入這方面的特性,底下可能各有不同,比如Swift是基於Optional type而沒有傳統的null,JS/TS則有兩個null值(null和undefined)🤪,但面上的語法基本一樣,編程體驗也很接近,可以說,都比較好的解決了空指針這個“價值億萬美元的錯誤”。

語言設施

除了語法、類型安全之外,我們還可以看到語言設施也有一個趨同的傾向。舉個例子,異步編程設施對於前端開發非常重要,因爲不管什麼平臺,爲了保證用戶體驗,共同的準則都是不能在UI線程裏做非常heavy的操作導致用戶操作無響應,這種情況下,異步編程,處理很多異步的操作變成必然要做的事情了,而且面臨的挑戰其實在各個語言裏面也非常類似,比方說callback hell。所以整個異步編程方面,可以發現新語言也越來越接近。比如很多都是基於Promise或者叫Future模式。JS/TS和Dart裏是作爲標準庫,Swift下有PromiseKit。進一步的,語言可能加入async/await語法,JS/TS、Dart都支持,Swift也已經有提案,未來也會加入async/await特性。Kotlin的機制雖然可能略有不同,是基於coroutine的,但從編程體驗上看,也是大同小異。

開發體驗

此外,前端語言在開發體驗上也互相借鑑。上一個演講裏董博士(Flutter團隊高級研究員:董韜博士)提到了Hot Reload,這個過去只有Web前端開發者可以享受到的便利性。但是現在其他端也都引入了。比如在Android上Instant Run,Flutter也提供了Hot Reload,Swift可能沒有官方的,但是有社區方案。總體來講,整個體驗是往這方面靠攏的。因爲這個對於我們開發效率會有提高的。

爲什麼會趨同

爲什麼我們在語法、類型安全、語言設施和開發體驗等方面會出現趨同?

  • 第一,這幾個前端語言的生態位是類似的。我們也有一些很有特色的語言,比如Elm、Clojure、ReasonML那樣一些語言,都很有特色,但是生態位跟我們前面講的官方“欽定”的前端語言不一樣,它們在源流上本來就基於相對小衆的語言(Haskell、Lisp、OCaml),轉到前端領域,就算有大廠加持(如ReasonML是facebook推出的),也只能是所謂niche,侷限在特定人羣(各流派函數式編程語言的愛好者,能力很強的小團隊等)。我們前面講的新一代平臺“欽定”的前端語言,儘管現在可能只是在一個平臺上,但都是希望佔據更大的市場的。它們都要搶佔“主流工業語言”的生態位,所以他們是以主流工業語言爲標的來設計和推廣的。在這樣相同的生態位上,所有的東西就會有一個相似性。要成爲主流工業語言,你要吸引已有的主流工業語言的使用者,儘量靠近傳統的Java、C#,無論是語法、語言特性、編程範式(對OOP的支持)之類的,就比較重要。

  • 第二,整個前端開發者的流動,本來原來是Web前端開發者,現在做iOS或者Android的開發,或者反過來。這個趨勢非常非常明顯。我舉一個例子來講,以前我們覺得React只是一個Web前端領域的框架,但是React Native推出之後,有一次我去聽React Native的技術分享,會場裏有一半以上是iOS和Android開發者。因爲這個流動的趨勢,我們希望阻礙流動的因素越少越好。作爲新一代“主流工業語言”的競逐者,互相參考借鑑,就響應了這樣一種開發者流動的需求。

  • 第三,本質因爲都是前端開發,問題領域非常相似,比如前面已經講過了異步編程的共性。既然它的問題領域是相似的,最後的結果可能也會殊途同歸。因爲好東西大家都想用嘛。在這一點上我想特別講一下UI DSL。

UI DSL

JS/TS下的JSX/TSX,Kotlin的Anko,Swift剛剛發佈的SwiftUI,最後Flutter,這四個東西,其實在很多地方是非常相似的,即所謂UI-as-code。當然我們直覺上會認爲它們有一些不同,比如我們覺得JSX是類XML/HTML,而後面幾個纔是真的語言本身的代碼。確實表面上是有這個差別。

爲什麼在JS/TS出現JSX,主要原因是JS/TS受到很多既往的限制,不太適合在語言內部做出一個好用好看的DSL,所以乾脆把大家熟悉的XML/HTML語法引入作爲語法糖,用轉譯器去轉換成等效代碼。(當然這個方式其實是有一些後遺症的,比如很難進入語言標準。)相反,Kotlin在設計之初就把DSL作爲設計目標,所以可以做出很好的DSL。Swift也具有類似的能力。

Flutter就比較有意思了,Dart在很多方面很保守,對內部DSL設計不是特別友好,所以跟JS/TS有相似問題(當然還是比JS/TS好多了),它做出的DSL不是很好看。不過董韜博士(Flutter團隊高級研究員)已經講了,已經做了很多改進,包括有一些語言層面的改進,使得DSL能看起來更清晰,另外通過IDE的改進,也能夠彌補在語言層面沒有辦法完全解決的問題。
無論如何,UI-as-code這個趨勢是共通的。

怎麼達到UI-as-code?

有兩個方向:

  • 一個是專用DSL代碼化,或者說是外部DSL內部化。Web端就是這樣,原來的HTML變成了JSX/TSX,原本聲明式的外部DSL變成可以用代碼操縱的對象。包括我們傳統CSS,在這個體系裏就傾向於CSS in JS。方案各種各樣,但是都是要把本來單獨分離的CSS或內嵌於HTML的CSS轉爲內嵌到JS/TS代碼裏,由JS/TS代碼引用和管理。這方式好不好我們另說,但思路就是這樣。

  • 另一個,就是JS/TS以外的語言,它們是命令式代碼的聲明化,這個就不多解釋了。
    這兩個方向,它們在本質上是殊途同歸的。最後達到的就是一個聲明性DSL和命令式程序的結合,或者叫統一。

React

前一段,React推出了React Hooks,可以理解爲新一代的UI DSL。像我前面講趨同,在React Hooks上也馬上可以看出來,React Hooks推出之後,我們整個Android社區、Swift社區,包括Flutter社區都可以看到馬上有開源項目跟進,嘗試把React Hooks的模式搬運到各個平臺上。所以也印證我前面講的爲什麼會趨同的那三點,各個平臺和語言互相影響和借鑑。React Hooks作爲現在還是一個新的、我認爲也比較先進,確實有很多優點的解決方案,我們期待它會不會在不久的將來被吸收到各個平臺的官方方案裏面去。

Vue

說到React,我也要提一下Vue。在不久之前在VueConf上面,Vue作者尤雨溪介紹了Vue 3未來的設計。比如Vue 3的function-based component也借鑑了React Hooks的方式,但是跟React Hooks還是有一些區別的,比如很“巧合”的避免了React Hooks設計上的一些代價。還有一個比較重要的,我們前面講UI-as-code,似乎大家都不用模板了,但是這裏有一個誤解,template和UI-as-code就一定是矛盾的嗎?

在Vue 3當中做的一個事情就是template和render做了完美結合。template是真正聲明式的東西,可以做徹底的靜態分析。前面講的現在的那些UI-as-code雖然是聲明式的,但是本質仍然是code,很多地方沒法靜態分析,比如確定到底哪個局部發生了變更,依賴關係是什麼,這可能是未來要去解決的問題。

Vue已經先一步拿出瞭解決方案。Vue的設計還是引導開發者儘量使用template,這樣可以充分利用靜態信息,同時局部可以自定義render實現,獲得完全的可控性和靈活性。這樣Vue可以精確計算出UI的變更,使得所需的底層更新操作最小化,獲得驚人的性能提升。具體這裏不展開了,大家可以去自行了解,這是目前我看到最先進的方案。

所以說單獨的UI-as-code本身是不是一定是最好的、最終的答案?可能不是。但我們也不用擔心,如果是真的好東西,那麼按照我前面講的,一定會流傳到各個語言和平臺。只不過,我在這裏提出來,這也許是一個機會,我們把握到這個趨勢,也可以去參與和推動這個趨勢,也就是參與創造未來。

未來

預測未來是很危險的事情,90%的概率是錯誤的。但是我還是願意冒險談一談。

首先有一點是未來這些前端語言會越來越相似。因爲前面講了看到這樣的趨勢,我覺得從很多方面,一方面確實看到確實是這樣,不同特性如果被證明好的語言特性,或者被證明對開發者是有價值的,那麼它會在不同前端語言和平臺當中普及開來。

但是另外一方面也要注意,畢竟語言還是有差異的。以下是一些個人的感受。

激進、中庸和保守

我們感覺Swift是相對比較激進的語言,被人詬病每年都要學一門新語言。當然Swift發展到現在這個版本,基本之前很多東西已經相對穩定下來了,可以認爲從狂飆的階段進入相對穩定的階段。但是總體上我們還是會感覺,Swift這個語言和這個社區是不怕做一些激進的改變的。比方說SwiftUI也許未來也會有很多的改動。

Kotlin就是一個相對比較中庸的語言。可能很多人不同意我的看法,覺得Kotlin也加入了非常多先進的語言特性,完全不亞於Swift。確實是這樣。但是這個中庸是和Java整個平臺下其他一些語言比較,Kotlin非常注重可以複用Java現有的東西。所以我覺得它的秉性其實是比較中庸的,中庸在這裏不是貶義詞,是一個很好的特性。

Dart這個語言,就是一個相對比較保守的語言,比如引入所有語言新特性的方面有點慢,甚至有時候是遲緩。有一些Kotlin、Swift早就有的特性,Dart就欠奉,一直到確信開發者非常需要這特性,纔會提上議事日程。不過保守不一定是壞的,保守有保守的好處。Dart語言的最初作者本身就是搞VM的,要確保某個語言特性在VM可以高效運行,對於語言設計來說就有比較高的約束。這也許是Dart保守秉性的源頭。

TS/JS未來面臨的挑戰

最後是JS/TS,它和前面三個語言有一個重要區別。前面三個語言雖然都是open source的,但都是有主導者的。Swift主導者是Apple,Dart主導者是Google,Kotlin則是JetBrains。

TypeScript雖然是Microsoft開發的,但TS的未來很大程度上並不取決於Microsoft,除了類型系統之外,其他都是JS帶過去的。

JS這個語言現在是一個比較典型的委員會語言了。這裏面其實沒有一個非常強勢主導方,而是委員會的一羣人一起去合作改進的。那麼這羣人很多方面就會非常不同,我們看JS新特性的提案討論,既有非常激進的動議,也有非常保守的,有一些特性不願意加。人多嘴雜,事情就難辦。而且TS/JS其實本質上是從前一代語言(傳統JS)發展而來,它不像其他幾個語言是全新的,它還是要揹負着不少歷史包袱。

JS社區又非常複雜,差異性很大,我們怎麼知道怎麼判斷社區在總體上的需求和好惡?尤其是當一些設計導致利害衝突時,誰能代表真正社區的心聲?所以在這裏我就打了一個問號,可能也是出於JS/TS需要面臨的長期挑戰。因爲整個語言在發展上,缺乏主心骨,可能面臨委員會語言的弊病。

未來的變數

技術上的一個變數是WebAssembly。前面說過WASM可以補齊JS/TS的短板。但另一方面,各個其他語言也可以由此進入JS/WASM引擎可以運行的所有的端。所以這是一個你中有我我中有你的情況。

會不會有新老語言藉此改變前端語言的戰局呢?好像也很難說一定沒有可能。

這裏還想講的未來當中一個變數,就是我們前面沒有提到的小程序。前面提到了Web端、Android、iOS端,但對中國開發者來講,還有另外一個端是小程序,而且準確講他還不是一個端,它是有很多很多不同家的“小程序”、“快應用”等,它們雖然非常相似,但是又有一些不同,所以在這個地方其實也是一個非常大的挑戰,同時我也覺得這也是一個很大的機遇。

多端的方案,對中國開發者來講,大家希望把小程序一併解決。前面董博士介紹了Flutter for Web,可能對於中國開發者來講還期待有Flutter for 小程序。如果小程序不能解決,在很多的選型場景下就沒有辦法選擇Flutter。

選型

所以我們前端的技術棧選型,最大的約束點,第一,平臺需求到底跨多少端,這是非常重要的因素。前面講的就是Flutter在這上面有小程序這個缺門。第二,就是團隊的技術背景,這個團隊本身熟悉一個怎麼樣的開發工具和開發語言的生態。我們基本還是從這兩點進行出發。

中國的公司和產業是否會誕生新語言

最後講一點想法。我們前面看到的新語言,像Dart是Google做的,像Swift是Apple做的,TypeScript是Microsoft。這都是大公司。Kotlin的JetBrains不是大公司,但也得到了Google的大力支持。Google和Microsoft其實還搞其他語言,Go啊、C#、F#等。還有像Facebook,首創了JSX,搞了flowtype(很類似於TS),還搞了ReasonML、Hack(PHP版的TypeScript)等。

其實我覺得中國現在頭部的科技公司,從規模來講,可以認爲已經不亞於他們了,但是我們到現在來講都沒有看到任何一箇中國的頭部公司設計和開發編程語言。當然研究性質的語言可能是有的,比如華爲應該是有的,但性質和我們這裏討論的不太一樣,不是面向一般程序員的。我們各個公司確實已經做一些自己的平臺,比如小程序、快應用等,但是沒有搞過編程語言,至少好像沒有大張旗鼓的搞,可能內部有偷偷的搞,我們沒怎麼看到。

爲什麼一定要做語言

大家可能會有一個疑問,說爲什麼一定要做語言呢?確實,很多時候我們用即有的語言就可以了,但是我們反過來思考一下,Google、Apple、Microsoft、Facebook等公司爲什麼搞新編程語言呢?注意,大家不要想當然覺得人家有強勢平臺所以可以做這個事情,也不要以爲他們總是能搞成功的。實際上有成功的例子,背後一定有更多失敗的。

比如Facebook的Skip,就是內部放棄之後纔開源出來的,ReasonML其實也不見得很成功,說不定未來哪天也就放棄了。像Dart我前面也提到過,要不是Flutter,恐怕也沒有什麼前途。於是有些人會說,連他們都失敗了,我們幹嘛要做呢?所以好像過去這些年對於搞編程語言這件事情,我們一直是抱持極大懷疑態度的。但是顯而易見,你如果永遠不去嘗試,那麼你永遠不可能有成功的可能。

當然,我們總可以選擇不做這個事情,我們就使用別人做的編程語言,我們搭便車,一樣可以享受語言發展的紅利。但是這裏有一個問題就是,如果我們永遠是搭便車的方式,我們就比較會缺乏在編程語言維度解決問題的能力。咱們中國整個頭部公司的工程師其實已經都非常厲害了,經過這麼多年的鍛鍊,在我們整個工具箱裏面我們有很多的解決的方法,比如庫、比如框架,都沒有問題,還有很強的hack能力,但是編程語言這個維度我們可能是相對比較缺失的一個維度,整個工具箱裏缺了一個重要的工具。

從編程語言維度解決問題

什麼叫編程語言維度解決問題?舉兩個例子。

  • 第一個例子就是前面圓心(阿里前端委員會主席)提到了,曾經有一段時間經常做各種JS Module的方案。我們可能覺得,用CommonJS方案解決就可以了。這個方案不是不好,實際上是一段時間裏整個生態的選擇。但是CommonJS還是有一些問題,它是通過類似庫和框架的方式解決的,是一個runtime的模塊機制,而我們知道今天的ES6的模塊機制,以及大部分其他語言裏的模塊機制,是靜態的,不是runtime的。靜態機制有好處,具體這裏不展開講。這裏只是用來說明一點,像模塊機制,本質上要在語言層面才能得到很好的解決。其實,我們曾經一度很接近這個語言層面的機制,比如玉伯(螞蟻金服研究員)當年做的Sea.js的方案,雖然長得和CommonJS一樣,實際上Sea.js是一個靜態模塊機制,本質上和CommonJS是不同的。Sea.js已經接觸到了語言層級。

  • 另外一個例子就是async/await,好多年之前有一箇中國程序員趙劼,就是著名的百萬年薪程序員組合“溫趙輪”裏的老趙,他其實是一個C#程序員,他不是JS程序員,但是他把C#/F#中的async/await引入了JS,開發了Wind.js。

所以呢,我覺得整個中國程序員,就像圓心講的,我們的思考,我們的能力其實沒有問題的,但是似乎有些事情,比如編程語言維度解決問題這一點,沒能進入到我們公司的、產業的主線上。老趙做的這個東西非常好,但是一直沒有流行起來,我們還是等了3、4年,等到外國人做的JS編譯器加入了這個東西,我們才說,哦,這是個好東西。Sea.js的情況可能好一點。

當然,這些局部的成果離開發一個完整的新編程語言也還離得比較遠,但是我們可以慢慢來,比如DSL和IDE,我們的產業界已經在這方面有實踐。前面我們講到小程序,其實裏面就有很多DSL,每個公司都做了一遍。

這個地方我們已經積累了一些經驗,或許從一個小的DSL逐漸將來可以走向更加完整或者通用的編程語言。另外IDE,前面也提到了,現在整個編程語言其實不是單單語言本身,而是包含了整個工具鏈。微信開發者工具就是個例子。如果我們深入各個公司瞭解一下,我們發現各個公司各個團隊很多都是在做IDE上的投資,包括前面圓心提到這事阿里未來的重點方向。

還有,我們不一定現在馬上做一個新編程語言,但是我們可以開始貢獻現有的編程語言社區,比如董韜博士提到中國程序員對於Flutter的貢獻,已經非常顯著了。

最後是參與編程語言標準制定。比如ECMA的TC39是JS語言的標準委員會,阿里已經在考慮加入,走這樣一個流程。我在這邊也同步一下我們360的情況,上週我們已經向ECMA提交了會員申請,並準備加入TC39工作組。希望無論是阿里還是360,或者是其他中國公司,能夠代表中國的產業界和開發者去參與這樣一個事情。

總結

工欲善其事,必先利其器。對於我們程序員來講,編程語言就是我們一個最重要的器。所以,我希望今天演講的內容,包括一些可能比較零碎、鬆散的想法,能夠給大家在整個前端開發和編程語言方面帶來更多的理解與思考。謝謝大家!

嘉賓介紹

賀師俊(網名Hax),360高級前端架構師,十多年來一直活躍在前端和JavaScript社區。對多項Web標準有微小貢獻,對Groovy語言並間接對Swift語言有微小貢獻,近年來參與了諸多ECMAScript新草案的討論。曾設計和實現Jedi語言並用於生產環境,對自研編程語言略有一點實踐經驗。三次擔任QCon出品人並獲得「優秀出品人」榮譽,也經常在其他衆多技術活動中擔任講師、嘉賓和主持人。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章