2016年1月2日 星期六

2015前端生態發展回顧(二)

原文:https://github.com/kuitos/kuitos.github.io/issues/32
上篇

架構的變化

2015年出現的新的技術及思路,影響最大的就是技術選型及架構了。我們可以從下面幾點來看看它對前端架構上都有哪些影響。

組件化

React的風靡使得組件化的開發模式越來越被廣大開發者關注。首先要肯定的是,組件化是一個非常值得去做的事情,它在工程上會大大提升項目的可維護性及拓展性,同時會帶來一些代碼可複用的附加效果。但這裡要強調的一點是,組件化的指導策略一定是分治(分而治之)而不是複用,分治的目的是為了使得組件之間解耦跟正交,從而提高可維護性及多人協同開發效率。如果以復用為指導原則那麼組件最後一定會發展到一個配置繁雜代碼臃腫的狀態。如果以組件的形態劃分,可以分為兩個類型:基礎控件和業務組件。基礎控件不應包含業務邏輯不然達不到拿來即用的效果,因此它也會表現出可複用的價值,但是根本還是為了提高業務組件的可維護性。至於業務組件,可複用的價值就很低了。
  1. 組件化指的是什麼
    組件化這個詞,在UI這一層通常指“標籤化”,也就是把大塊的業務界面,拆分成若干小塊,然後進行組裝。
    狹義的組件化一般是指標籤化,也就是以自定義標籤(自定義屬性)為核心的機制。這也是我們通常認識的組件。
    廣義的組件化包括對數據邏輯層業務梳理,形成不同層級的能力封裝。它不一定是一個自定義語義標籤:它可以是一個包含邏輯(js)、樣式(css)、模版(html)的功能完備的結構單元,也就是我們常“口口相傳”的模塊(從術語準確性的角度來看模塊這個描述並不合適,應該稱之為組件);它也可以是一個單純的js,比如http組件這種純邏輯單元。嚴格從概念上來講,css跟html是不具備單獨/組合成一個組件的,它們不具備描述邏輯的能力(非圖靈完備)。從這個層面來看,全組件化是沒有任何問題及疑義的。
  2. 是否需要全組件化
    我們通常說的組件指的是狹義上的組件,而且往往我們理解的全組件化也是建立在狹義的組件基礎上的,
    代表框架是React。 React+Flux體系下,它提倡盡可能將頁面作細粒度的組件拆分,組件的數據全部由父級組件通過props傳遞而來。這本身是一件非常有價值的事情,能有效的確保應用狀態的穩定及可預測性,但是應用一旦複雜龐大起來,組件樹變得“枝繁葉茂”導致葉子節點層級過深,當出現數據問題時,我們必須一層層的回溯來定位bug。而且組件樹過於龐大也會增加組件之間的通訊負擔。從狹義的組件來看,我對全組件化是存懷疑態度的,工程上的成本太高是最大的問題,而且大部分開發者很難拿捏合適的組件粒度,容易出現過細/過粗的拆分。很多場景其實並不適合實現成狹義上的組件,它以零散的模板的方式存在更合適。
    但是如果從廣義的組件來看,全組件的意義是很大的,我們需要通過拆分頁面邏輯區塊的方式實現程序的解耦,從而提升應用的可維護性。
綜合來看,我覺得工程上更具可行的全組件化方案應該是:細粒度的基礎組件庫+ 粗粒度的模板/組件。

工程化

工程化是近年前端提到最多的問題之一,而且個人認為是當前前端發展階段最有價值的問題,也是前端開發通往工業化時代的必經之路。這裡不贅述,有興趣的同學看我前陣子整理的一篇文章前端工程化知識點回顧
應用架構層 MVVM & Flux
MVVM想必大部分前端都耳熟能詳了,代錶框架是angular、vue、avalon。 angular在1.2版本之後加入了controllerAs語法,使得controller可以變成一個真正意義上的VM,angular整個架構也才真正能稱之為嚴格的MVVM(之前只能說是帶有雙向綁定的MVC/MVP )。
Flux是facebook隨React一併推出的新的(準確來說其實是改進的,並非原創)架構模型,核心概念是單向數據流。 Flux實質上就是一個演進版的中介者模式,不同的是它同時包裝了action、store、dispatcher、view等概念。關於Flux對應用分層、數據在不同層之間只能單向流轉的方式我是很贊成的。應用的分層在業務稍複雜的應用中都是很有必要的,它更利於應用的伸縮及拓展,副作用是會帶來一定的複雜度(在我看來這點複雜度根本就可以忽略不計)。
今年被黑的最多的前端主流框架莫過於angular了。老實講前端圈真的挺善變的,去年各種大會都在分享angular黑jquery,今年就變成了都在分享react黑angular了。黑的點大致有三:
  1. angular的部分實現太low
  2. 太多Java身上帶來的臭毛病(並沒有在黑Java)
  3. mvvm自身的缺陷
第一點第二點我並無異議。 angular的髒值檢測機制相對於其他mvvm框架的雙向綁定實現方式確實不太優雅,同樣有硬傷的還有失敗的模塊語法及過多過於複雜的概念。但是對於第三點,我有不同的看法。
大多數人黑mvvm會以Facebook那張經典的flux vs mvc的圖為論據,對於雙向綁定造成的數據流紊亂及應用狀態的不確定導致問題定位困難的觀點我是認同的,這一點我也有切身體會,但是單純的這一點就足以否定mvvm麼?就說flux比mvvm高明?
MVVM在富表格型(自造的詞😄)應用開發效率上是高於Flux的,典型的就是一些後台管控平台。而且最重要的是,MVVM跟Flux並不互斥,我們在MVVM中照樣可以引入Flux中的一些機制從而確保應用狀態的穩定。很多時候我們對於框架/架構的孰優孰劣的爭論是沒意義的,拋開業務場景談解決方案都是耍流氓。
業務數據層 Relay & falcor
這一層對大部分前端來說可能是比較新的概念,其實我們可以這樣理解:在一個完整的應用中,業務數據層指的就是數據來源,在angular體系中可以等同於ngResource模塊(準確來說應該是$http)。
Relay是f家推出的在react上應用GraphQL的框架,它的大致思路是:前端通過在應用中定義一系列的schema來聲明需要的接口數據結構,後端配合GraphQL引擎返回相應的數據。整個事情對於前端來說意義簡直是跨時代的,工業化典範!不僅能極大提升前後端協同的開發效率,還能增加前端對於應用完整的掌控力。但是目前來看問題就是實施過於復雜,而且還得後端服務支持,工程成本太高,這一點上Meteor顯然做的更好。
falcor則是Netflix出品的一個數據拉取庫,核心理念是單一數據源,跟Redux的單store概念一致。用法跟Realy類似,也需要前端定義數據schema。 另外還有一個新的W3C標準api:fetch,它的級別等同於XMLHttpRequest,旨在提供比ajax更優雅的資源獲取方式,目前幾個主流瀏覽器支持的都還不錯,也有官方維護的polyfill,幾乎可以確定是未來的主流數據請求api。
業務數據層是前端應用中比較新的概念,它的多元化主要會影響到應用的架構設計,這裡不細講後面再來說。

新的編程範式

函數式編程(FP)

函數式編程(functional programming)是近年比較火爆的一個編程範式,FP基於lambda演算,與以圖靈機為基礎的指令式編程(Java、C++)有著明顯的差異。 lambda演算更關注輸入輸出,更符合自然行為場景,所以看上去更適合事件驅動的web體系,這點我也認同。但問題是,太多開發者看到redux那麼火爆就急著學redux用js去玩函數式,我覺得這個有待商榷。 js作為一個以基於函數(scheme,父親)跟基於對象(Self,母親)的編程語言為藍本設計然後語法又靠近Java(隔壁老王)的“混血”語言,你非得用它去寫函數式,是不是過於一廂情願?尤其是在現在瀏覽器還不支持尾調用優化的情況下,你讓那激增的調用棧可如何是好😂如果你確實鍾情於函數式,可以去玩玩那些更functional的語言(Haskell、Clojure等),而不是從js入手。最近看到一個老外關於js的函數式編程的看法,最後一句總結很精闢:Never forget that javascript hate you.😂

函數式響應型編程(FRP)

函數式響應型編程(functional reactive programming)不是一個新概念,但也不過是近兩年才引入到前端領域的,代表類庫就是ng2在用的rxjs。 FRP關注的是事件及對應的數據流,你可以把它看作是一個基於事件總線(event bus)的觀察者模式,它主要適用於以GUI為核心的交互軟件中。但FRP最大的困難之處在於,如果你想使用這樣的編程範式,那麼你的整個系統必須以reactive為中心來規劃。目前微軟維護的ReactiveX項目已經有各種語言的實現版本,有興趣的同學可以去了解下。

工具鏈的變化

去年最主流的前端構建工具還是grunt&gulp,2015年隨著react的崛起和web標準的快速推進,一切又有了新的變化。
webpack & browserify & jspm
webpack跟browserify本質上都是module bundler,差異點在於webpack提供更強大的loader機制讓其更變得更加靈活。當然,webpack的流行自然還是離不開背後的react跟facebook(可見有個強大的干爹多麼重要)。但是從現在HTTP/2標準的應用及實施進展來看,webpack/browserify這種基於bundle的打包工具也面臨著被歷史車輪碾過的危機,相對的基於module loader的jspm反而更具前景(雖然現在使用前兩者的開發者都多於jspm)。

PostCSS & cssnext

PostCSS作為新一代的css處理器大有取Sass/Less而代之的趨勢,Bootstrap v5也有著基於PostCSS去開發的計劃。但從本質來講它又不算一個處理器,它更像是一個插件平台,能通過配置各種插件從而實現預處理器跟後處理器的效果。 cssnext官方口號是“使用來自未來的語法開發css,就在今天!”,但是cssnext又不是css4,它是一個能讓開發者現在就享受最新的css語法(包括自定義屬性、css變量等)的轉換工具。這一塊筆者還沒有過具體實踐,暫不多言。

寫在最後

從前端的發展現狀來看,未來理想的前端技術架構應該是每一層都是可組裝的,框架這種重型組合的適用場景會越來越局限。原因在於各部件不可拆卸會增加架構的升級代價同時會限制應用的靈活性。舉個例子,我有一套面向pc端的後台管控平台的架構,view層採用angular開發,哪天我要遷移到移動端來,angular性能不行啊,我換成vue就好了。哪天覺得ajax的寫法太挫,把http層替換成fetch就好了。又有一天后端的GranphQL平台搭好了,我把ngResource換成relay就OK了。
這種理想的方式當然是完全正確的方向,但是目前來看它對開發者/架構師的要求還是太高,工業級別上一套帶有約束性的框架還是有相當的需求的(特別是當團隊開發者的水平良莠不齊時。當然我覺得更正確的方式是流程上有一套完整的自動化方案用於確保團隊提交的代碼質量,只是目前基於動態分析的代碼質量檢測工具還沒有出現,而且估計很長一段時間內都不會有)。雖然美好但是組合的方式也不是沒有問題,各種五花八門的搭配容易造成社區的分化跟內耗,一定程度上不利於整個生態圈的發展。
近年前端生態的野蠻發展影響最大的應該就是新產品的技術選型了,亂花迷人眼,我們很難設計出一套適應大部分場景、而且短時間內不會被淘汰的架構。前端的變化太快通常會導致一些技術決策的反复,今天的最佳實踐很可能明天就被視為反模式。難道最合適的態度是各種保留各種觀望,以不變應萬變?在這一點上即使如我這般在技術上一向激進的人都有點畏手畏腳了。那句話怎麼說的來著?從來沒有哪個圈子像今天的前端一樣混亂又欣欣向榮了。有人說2015年或許是大前端時代的元年,目前看來,如果不是2015,那麼它也一定會是2016年。
最後引用計子winter的一句話作為結語吧:
前端一直是一個變化很快的職能,它太年輕,年輕意味著可能性和機會,也意味著不成熟和痛苦。我經常擔心的事情就是,很可能走到最後,我們會發現,我們做了很多,卻還是一無所獲。所幸至今回顧,每年還是總有點不同,也算給行業貢獻了些經驗值吧。


沒有留言:

張貼留言