1. 程式人生 > ># 程式碼約架?Vue.js和Binding.scala兩大框架作者的PK

# 程式碼約架?Vue.js和Binding.scala兩大框架作者的PK

作為一個知乎小透明,最近看了一場炸魚大片。兩天前,民工叔因為 Teambition 是 React 技術棧而離職 一文,引發了激烈的討論。其中民工叔偏向的技術選型Vue.js的作者出沒現場黑了一把Angular2,其它各吃瓜群眾表示還沒反應過來該如何站隊之時,Binding.scala的作者則跳了出來順帶把Vue.js、ReactJS、AngularJS、ELM、diode黑了個遍。各人語言犀利,毫不留情。

前端框架的開發,js在各大廠小店都是第一順位的選擇,然而在這樣的氣氛中,為啥突然出現了Scala這麼一股泥石流呢?

在這麼一個小小的角落裡,一場大戲在開演,吃瓜群眾表示看得很過癮,所以順了順過程,技術部落格處女作就這樣交出去了

這裡節錄一下其中幾個比較正面的交鋒,及參與者。

楊博,Binding.scala作者,簡稱楊
尤雨溪,Vue.js的作者,簡稱尤
賀師俊, 犀利的技術批評者,前端技術資深專家,簡稱賀

楊稱,用Binding.scala寫的程式所需程式碼行數不到ReactJS的三分之一,甚至比以簡潔著稱的Vue.js還要短。

尤還以顏色,用Vue.js重新寫了一個135行的TodoMVC新版本,比Binding.scala還短。

楊隨後貼出了122行的Binding.scala版TodoMVC。

尤沒有跟進更短的版本,但他指出122行的Binding.scala版TodoMVC,要比Vue.js字元數多30%。

楊認為Vue.js字元數少的代價是API更臃腫。Vue.js 90%的API,在Binding.scala用一個函式就可以全部代替。

在前端技術大爆炸的今天,大家怎麼看待這場程式碼PK呢?這一場炸魚,對各廠的前端選型有木有帶來一絲波動?

以下是部分的討論記錄,有點長。按時間順序,也可直接點選知乎連結參觀

已經用慣 react 的人不願意換棧可以理解,但是居然折衷到 ng2 去了,這我也是有點醉。。。這跨度比 react 到 vue 還大得多得多啊。

Vue.js, ReactJS, AngularJS各有各的坑,所以你們爭執不下也很正常。

如果你們試過Binding.scala大家就不用爭吵了嘛。

你看,世界人民紛紛棄用AngularJS、ReactJS、ELM、diode,改投Binding.scala:

賀 -> 楊

做比較得有成本的。你覺得你的東西好,可以寫一些對比然後給大家看。但是要求別人自己先去看就強人所難了。更不要暗示別人“不懂”,“信口開河”。這對推廣你的東西並沒有好處。

楊 -> 賀

賀 -> 楊

我先簡單給你講一下大的方面,bindings.scala因為整個技術棧是基於scala的,本身你就不能指望能說動react/vue/ng的人轉向它。你看這幾個技術棧都是基於js的,轉換都要爭論,何況遷移到非js生態?如果有人要選非js,他甚至優先選elm,也不見得是scala。因為elm之於js就類似scala之於java,也就是親緣更近。也正是因為更大的技術生態的區分,你講的sbt配置比webpack之類的更簡單,其實並沒有什麼卵用,因為沒有人會因為配置這點次要的問題就轉換整個技術棧。所以你在推廣的時候的訴求本身就有問題。bindings.scala能夠做到最好的成果就是成為scala社群的第一web框架,如果你能像elm一樣反哺js生態下的重要框架,就可以說逆天了。再其他的,只能是不切實際的奢求。沒辦法,這是歷史程序決定的,不是個人努力可以改變的。

賀 -> 楊

再給你說下這系列文章。第一個是,你講的react的一些缺點,是有,但是是不是那麼大?不見得。而且社群自己可能已經有其他方案,比如vdom的實現就數不清了。第二個是,“元件對複用性有害”這就是個標題黨,我不是說元件的方式就一定好,實際上我自己確實對元件(自定義標籤)是有一定保留的,但你根本沒講清楚到底有害在哪裡,而且react也完全可以按照不用元件的方式寫個大render。注意,react/vue/ng/polymer甚至webcomponents標準都引入元件(自定義標籤),難道他們都是傻叉?至少你現在的文章完全沒有說服力,最後大部分人只能反過來認為bindings.scala缺少元件特性,而不會認為這是你的優點。第三個,就算你的精確繫結啊,html語法支援都是優點,vue技術棧已經都具備了。總之,僅按照你這系列文章連我這個對react有所保留的人也說服不了。

楊 -> 賀

第一個,ReactJS的那些缺點大不大要看跟誰比,如果跟AngularJS1相比,確實缺點不大,畢竟Angular1更臃腫不是?但要跟Binding.scala比,這些缺點大概比Binding.scala難用3倍以上。我在More than React 系列文章中的各個例子,每個ReactJS實現都超過Binding.scala的3倍程式碼行數。

虛擬DOM這個演算法,過去,還是挺有用的。現在,有了精確資料繫結的演算法,無論是效能還是易用性都壓制了虛擬DOM,再談“虛擬DOM的實現數不清”這就有點井底之蛙的感覺了。

我覺得賀老師,您其實可以跳出井外看看,外面的世界很大的。

楊 -> 賀

第二個,具體在More than React(二)元件對複用性有害?中,ReactJS 例子中三分之二的程式碼都是多餘的,是 Component 帶來的語法噪音。

首先您得先看程式碼,承認一個客觀事實,Binding.scala要比ReactJS簡單得多。有了這個客觀事實之後你在去找原因,那麼您就會發現ReactJS複雜的原因之一是React.Component的語法噪音。

如果您認為我寫的文章是在“論證”React.Component不好,那就變成語言聖戰了,誰也說服不了誰。

賀老師您讀一下程式碼,先承認事實,然後再體會一下。

楊 -> 賀

第三個,我寫文章的目的可能不是為了說服賀老師。我也不指望賀老師看完文章,畢竟我連說服賀老師把Binding.scala的名字拼對都做不到。

賀 -> 楊

Component絕不可以用語法噪音來批評。因為它提供了額外的抽象機制。你如果要論證Component不好,你得論證這種抽象不好或者沒用。明白了沒?

賀 -> 楊

比較程式碼行數雖然很直接,但是其實沒什麼卵用。你要相信一點,在沒有特別巨大的抽象方式的改進時,做同樣的事情,程式碼是不會有非常大的差異的。這是資訊理論決定的。你最多去掉一些語法冗餘。但是,前面說了,Component不是語法冗餘(好不好是另外一回事情),通過去掉Component來節省行數毫無意義。除非你能先證明Component抽象是無用的。而我前面就說了,你目前的文章並沒有做到這個證明。

賀 -> 楊

知乎評論是無法編輯的。如果我前面把Binding.scala拼錯了,向你道歉。

尤 -> 楊

光比程式碼短沒有什麼意義,Vue 寫出來的程式碼也很短,但很少有人以這個作為難用不難用的標準。

說效能,沒有資料空口說有毛用啊… krausest/js-framework-benchmark 你也來跑一個,碾壓了所有實現再說別人井底之蛙也不遲。

賀老跟你說的意思是,你列舉的種種(所謂)優點,沒有一個重要到讓一個寫 js 的人有動力整個換一個生態,除非這人本來就熟悉 scala。另外就是,你推銷自己的東西時候預設了用 js 的人都在井裡,光這種居高臨下的心態和口吻就不可能推銷得出去。

楊 -> 尤

Vue.js 的 TodoMVC 例子中的 JavaScript 程式碼行數比 Binding.scala 的 Scala 程式碼長。vue/js、Binding.scala

當然這樣比較,對 Binding.scala 不太公平。因為 Vue.js 除了需要編寫 JavaScript 以外,還需要額外編寫 HTML 模板。而 Binding.scala 的 Scala 檔案中有一半左右的程式碼都是 HTML 模板。

不過沒關係,雖然對 Binding.scala 不公平,但 Binding.scala 還是能贏。

所以您說的“Vue 寫出來的程式碼也很短”就是井底之蛙。

尤 -> 楊

你那麼多東西擠一行裡面,空行那麼少,比行數有意義麼… 是來搞笑的吧?想要的話我分分鐘可以把 Vue 的 todomvc 行數壓得比你的短。行了,你這樣的態度我也沒興趣理你,連 Vue star 零頭的不到的專案繼續自娛自樂去吧。

楊 -> 尤

Binding.scala的TodoMVC最長的一行是68行,有139個字元,是個註釋行。

Vue的TodoMVC最長的一行是25行,有218個字元,塞滿了那麼多東西。

您要把程式碼行數壓得比Binding.scala的話,其實也不難,大概一行塞2000個字元就行了吧。

尤 -> 楊

不好意思,啪啪啪 Edit fiddle - JSFiddle <- 連模板在內 135 行,而且模板還帶折行的喲

尤 -> 楊

效能方面,期待你來個比 Inferno 速度更快的跑分,人家用的可是 Virtual DOM 喲,我等著你喲。當然,做不到的話,大方的承認自己是井底之蛙也可以。

尤 -> 楊

呃,之前連結的 jsfiddle 打錯一個字,修正以後的版本:Edit fiddle - JSFiddle ;)

楊 -> 尤

135行真的非常厲害,贊!

不過還是有些美中不足的地方,比如您的寫法犧牲了複用性,把整個應用的全部HTML模板集中在了一起,如果要是個多頁應用,需要複用footer的話,就比較困難。

再比如說,您的寫法,相比ReactJS,缺少了類似PropTypes的Model的型別檢查功能。

我確實被打臉了,畢竟Binding.scala的TodoMVC,如果不想犧牲複用性和型別安全的話,也要126行呢。

我承認我過去小看了Vue,今天讓我刮目相看了,Vue只比Binding.scala多了9行還是很了不起的。

尤 -> 楊

好了,嘴硬有什麼意思呢,我都說了 135 行的模板是帶折行的,不折行這 9 行瞬間就回來了,水分想要多少有多少。你真要比不如比總字元數:Vue 的版本 4117 chars,你改了半天以後的這個新版本 5353 chars… oops,整整比 Vue 多了 30% 的程式碼量。你再努力下?

尤 -> 楊

還有啊,你這新版本最多也就是把模板切成了幾個 partial,handler 和資料全在一個 scope 裡面,明明是強耦合的一堆東西,也好意思叫可複用?

楊 -> 尤

然而,如果逐行對比Vue和Binding.scala的不同寫法,我卻發現,Vue節省的30%的字元數,反而體現了Vue在API設計層面非常臃腫。

楊 -> 尤

把繫結變數渲染成文字:
* Vue:<span>{{data}}<span>
* Binding.scala:<span>{data.bind}</span>

楊 -> 尤

把不繫結的變數渲染成文字:
* Vue:<span>{{* data}}<span>
* Binding.scala:<span>{data}</span>

楊 -> 尤

把繫結變數設定上屬性:
* Vue:<span :class="data"></span
* Binding.scala:<span class={data.bind}></span>

楊 -> 尤

設定事件處理器:
* Vue:<a @click="clickHandler"></a>
* Binding.scala:<a onclick={clickHandler}></a>

楊 -> 尤

條件渲染:
* Vue:<h1 v-if="ok">Yes</h1><h1 v-else>No</h1>
* Binding.scala:{ if (ok.bind) <h1>Yes</h1> else <h1>No</h1> }

楊 -> 尤

條件隱藏:
* Vue:<h1 v-show="ok">Hello!</h1>
* Binding.scala:<h1 style:display={ if (ok.bind) "block" else "none" }>Hello!</h1>

楊 -> 尤

列表渲染:
* Vue:<ul><li v-for="item in items">{{ item.message }}</li></ul>
* Binding.scala:<ul>{ for (item <- items) yield <li>item.message.bind</li> }</ul>

楊 -> 尤

設定條件事件處理器:
* Vue:不支援
* Binding.scala:<a onclick={ if (ok.bind) clickHandler1 else clickHandler2 }></a>

楊 -> 尤

Binding.scala只在Scala原生語法基礎上再提供一個bind語法就支援了上面所有功能,而Vue發明了“:xxx”、“@xxx”、“v-xxx”、“{{* xxx }}”這麼多API和特殊語法、破壞正交性、緊湊性、一致性,功能仍然比Binding.scala更弱。我覺得您為了在擊鍵次數方面戰勝了Binding.scala而付出的代價有點得不償失。

這些問題可能Vue的粉絲不清楚,但尤老師您自己還是得好好想想。我建議尤老師不要試圖列舉所有使用者可能用到的功能。因為一旦使用者需要的功能尤老師您沒想到,Vue就歇菜了。比如您看,Vue就沒辦法根據繫結條件動態改變事件處理器。所以我覺得您可以在Vue 3.0放棄這些臃腫的API,模仿Binding.scala的API重新設計,不再以優化擊鍵次數為設計目的,那麼說服Teambition改用Vue還是挺有希望的。

楊 -> 尤

尤老師對耦合和複用的認識,讓我有點失望啊。

初學程式設計的小朋友都知道提個函式就能複用,尤老師還在追求“元件”這種形式主義的東西。

Binding.scala推薦的方式是直接把partial寫成全域性函式,直接呼叫就可以複用了。

至於handler,和相關的HTML屬於同一個複用單位,必須放在一起才能保證內聚性啊。

您如果要黑的話,唯一的黑點是ScalaFiddle不支援多檔案,所以只能把所有複用單位寫在一個檔案裡。

最後還是感謝一下尤老師的反饋,我調整了一下空行,把相關的handler和HTML寫得近一點,以便體現內聚性。新版本放在ScalaFiddle,麻煩尤老師再幫我指正一下。

尤 -> 楊

你大概不知道 Vue 2 支援手寫 render function 和 jsx… 偶爾可以跳出你的井看看,外面的世界很大的。

楊 -> 尤

尤老師,我就是想教您設計API。

Vue現在的API,90%都是沒有一丁點用的,這樣的設計是不合格的。

您如果想提升一下API的技能,您可以學習一下Binding.scala的API。

楊 -> 尤

尤老師您真的覺得Vue+JSX就像Binding.scala一樣簡潔高效嗎?

您先把您那臃腫的API刪掉90%再說吧。

我覺得您可以想一想,為什麼Binding.scala裡沒有$slots、$children、directive、Component、$parent、$root、$refs、$scopedSlots、$watch、$destroy、$force、key、……所有這些API,然而,Binding.scala功能還比Vue強呢?