Vue 2 雖然不算是 FP 架構,但透過不一樣寫法,仍可使 Vue 2 接近 FP 讓 Project 更易維護。
Version
Vue 2.6.11
Vuex 3.1.2
Ramda 0.27.0
Challenge of Web
Backend MVC
約在 2015 年,主流的 Web 開發架構仍以後端 MVC 為主:
- PHP / Laravel
- Ruby / Ruby on Rails
- C# / .NET MVC
- Python / Django
這類都是 後端
以 MVC 為主,前端
以 jQuery / Ajax 為輔的架構。
這種架構有幾個挑戰:
- 有於重點在後端,時常必須換頁到後端去,使用者會明顯感受到網頁重新載入,視覺與使用感受較差
- 若想減少換頁到後端,就必須大量使用 jQuery / Ajax,則前端就會有大量 ECMAScript
- 由於 ECMAScript 缺乏 module 概念,實務上常常會看到上千行的 jQuery / ECMAScript,導致維護困難
- 由於 jQuery / ECMAScript 是躲在後端網頁內,因此大部分的 jQuery / ECMAScript 都是由後端工程師撰寫,但由於 ECMAScript 語言特性與後端語言明顯的差異,大部分後端工程師選擇逃避原生 ECMAScript,而改用較容易的 jQuery,此時都是 Web 工程師都是
全端工程師
- 也由於使用 jQuery,導致大部分
全端工程師
並沒有深入研究 ECMAScript,而是認為前端只是控制 HTML / DOM 而已,jQuery 足已,因此沒必要深入研究 ECMAScript,導致一些 ECMAScript 很重要的語言特性被忽略 (first-class function, higher order function、closure、IIFE、function composition …),其實這些 FP 特性,才是 ECMAScript 精華所在
Separation of Frontend and Backend
2015 年開始有一些前端 framework 嶄露頭角,如 AngularJS、React:
- 後端只寫到 API,以 JSON 與前端溝通
顯示邏輯
寫在前端,而不是以 presenter pattern 寫在後端,因此沒有網頁重新載入,視覺與使用感受佳- 前端開始有 component 概念,也開始使用 ES6 的 module 概念,因此不再出現上千行 JavaScript,可重構成 component 與 module,更容易維護
- 由於使用 ES6 與原本 ES5 相比,幾乎是全新語言,有學習門檻
- 前端技術發展迅速,開始有
- Node 生態圈 (NPM、Yarn)
- ECMAScript 每年會更新一版 (2015 ~ 2020)
- Babel / Webpack 編譯打包技術 + ESLint (即使 JavaScript 不編譯,亦可享有編譯的優點)
- 層出不窮的 library
- 層出不窮的 framework (Angular、React、Vue)
- 由於前端技術爆炸,已經不再只有 jQuery,後端也要精通前端已經有難度,因此前後端開始分家,開始有所謂
前端工程師
Evolution of Frontend
相較於 jQuery、前端開始有了新的概念:
- Data Binding:傳統 jQuery 直接控制 DOM;現在前端改為控制 data,現在由 framework 處理 data 與 DOM 的改變
- Functional Programming:由於 ECMAScript 深具 Functional 語言特性 (以 Scheme 為原型),原本 OOP 的 MVC 架構蛻變為 FP 的 Pipeline (單向資料流) 架構 (React 的 Redux、Vue 的 Vuex)
- Webpack Tree-shaking:由於 OOP 大量使用 field,導致 tree-shaking 無法有效發揮,前端開始使用 FP 方式,以 function 取代 class,並使用 FP 的 function composition 取代 OOP 的 DI (Ramda)
可以發現前端的改變:
- 從控制 DOM 轉為控制 data,回歸程式設計的本質
- 由 Object Oriented Programming 轉為 Functional Programming
Vue
Vue 吸取 React 與 Angular 的優點:
- 從 Angular 學到學習門檻較低的 HTML Template,而非 React 的 JSX
- 從 Angular 學到 directive 控制 HTML,而非 React 直接以 ECMAScript 夾雜 HTML
- 從 React 學到 component 概念,使得
顯示邏輯
得以模組化 - 從 React 學到
狀態管理
概念 (Redux) ,讓跨 component 的溝通更加簡單 (Vuex) - Vue 前期學 Angular 較多,後期則明顯向 React 靠攏
儘管如此,Vue 也有自己的缺點:
- Vue 的
data
、computed
、props
、method
… 都必須靠this
存取,這是一種具有 side effect 的寫法,且由於this
的可變性,導致 Vue 重構困難 - Vue 寫法多元,最原始寫法是一種依賴
this
,很像 OOP 又不是 OOP 寫法,後來又開發出 class component,這是正統 OOP,風格很像 Angular,但也由於太偏 OOP,導致大部分人寫 Vue 都使用 OOP 思維,而忘記 ECMAScript 最重要的 Functional 特性 (first-class function、higher order function、closure、IIFE、function composition …) - 將
computed
、method
寫在 Vue instance 內,導致縮排過多
Functional Vue
- Vue 的
data
、computed
、props
、method
本質都是 function,不要將這些寫在 Vue instance 內,而將所有的 function 拉出來,也由於看到的是一條條 function,不是類似 OOP 的 method,有助於發現重複的部分以 higher order function 重構 - 除了 HTML data binding 的資料放在
data
外,不要把data
當成 OOP 的 field 使用,如此可避免使用 side effect 寫法,而改用 pure function 風格 - 將資料從 data 搬到 Vuex 的 state,由於
state
、getter
、mutation
與action
不使用this
,Vue 可徹底從 ES5 的 function expression 解放,全面改用 ES6 的 arrow function,不僅更簡潔,也更適合 higher order function 實現 - 也由於 Vuex 的
computed
、method
本質上都是 function,可以很容易抽成 higher order function,也可以整合 Ramda 這類 functional library,透過 function composition 產生computed
、method
- 也由於
商業邏輯
與顯示邏輯
都集中在 Vuex 的 store,因此各 component 很容易重複使用這些邏輯,且只要state
與getter
有變動,其他 component 資料都會跟著變動 - 由於
邏輯
都在 Vuex 的 store,unit test 可集中火力放在 store 即可 - 也由於所有的 function 都沒有
this
,都是 pure function 沒有 side effect,因此很容易重構到適當 module,不必被 Vue 的component
或mixin
所綁架
Conclusion
- Functional Vue = Vue Component + Vuex + Ramda + ES6 Module