給2019前端的5個建議

發表於2019-02-08

2019 農曆新年即將到來,是時候總結一下團隊過去一年的技術沉澱。過去一年我們支撐的資料相關業務突飛猛進,其中兩個核心平臺級產品程式碼量分別達到30+萬行和80+萬行,TS 模組數均超過1000個,協同開發人員增加到20+人。由於歷史原因,開發框架同時基於 React 和 Angular,考慮到產品的複雜性、人員的短缺和技術背景各異,我們嘗試了各種方法打磨工具體系來提升開發效率,以下是節選的5項主要方法。

一、基於 Redux 的狀態管理

從2013年React釋出至今已近6個年頭,前端框架逐漸形成 React/Vue/Angular 三足鼎立之勢。幾年前還在爭論單向繫結和雙向繫結孰優孰劣,現在三大框架已經不約而同選擇單向繫結,雙向繫結淪為單純的語法糖。無論你是否承認,框架間的差異越來越小,加上 Ant-Design/Fusion-Design/NG-ZORRO/ElementUI 元件庫的成熟,選擇任一你熟悉的框架都能高效完成業務。

那接下來的核心問題是什麼?我們認為是狀態管理。簡單應用使用元件內 State 方便快捷,但隨著應用複雜度上升,會發現資料散落在不同的元件,元件通訊會變得異常複雜。我們先後嘗試過原生 Redux、分形 Fractal 的思路、自研類 Mobx 框架、Angular Service,最終認為 Redux 依舊是複雜應用資料流處理最佳選項之一。

慶幸的是除了 React 社群,Vue 社群有類似的 Vuex,Angular 社群有 NgRx 也提供了幾乎同樣的能力,甚至 NgRx 還可以無縫使用 redux-devtools 來除錯狀態變化。

給2019前端的5個建議

無論如何優化,始終要遵循 Redux 三原則:

  1. Single source of truth(元件 Stateless,資料來源於 Store)
  2. State is read-only(只能通過觸發 action 來改變 State)
  3. Changes are made with pure functions(Reducer 是純函式)

這三個問題我們是通過自研 iron-redux 庫來解決。

最終我們得到如下扁平的狀態樹。雖龐大但有序,你可以快速而明確的訪問任何資料。

給2019前端的5個建議
Redux 狀態樹

如何減少樣板程式碼?
使用原生 Redux,一個常見的請求處理如下。非常冗餘,這是 Redux 被很多人詬病的原因

使用 iron-redux 後:

程式碼量減少三分之二!!
主要做了這2點:

  1. 引入了預設的 AsyncTuple 型別,就是 {data: [], loading: boolean, error: boolean} 這樣的資料結構;
  2. 使用 AsyncTuple.handleAll 處理 LOADING/SUCCESS/ERROR 這 3 種 action,handleAll 的程式碼很簡單,使用 if 判斷 action.type 的字尾即可,原始碼在這裡

曾經 React 和 Angular 是兩個很難調和的框架,開發中浪費了我們大量的人力。通過使用輕量級的 iron-redux,完全遵循 Redux 核心原則下,我們內部實現了除元件層以外幾乎所有程式碼的複用。開發規範、工具庫達成一致,開發人員能夠無縫切換,框架差異帶來的額外成本降到很低

二、全面擁抱 TypeScript

TypeScript 目前可謂大紅大紫,根據 2018 stateofjs,超過 50% 的使用率以及 90% 的滿意度,甚至連 Jest 也正在從 Flow 切換到 TS。如果你還沒有使用,可以考慮切換,絕對能給專案帶來很大提升。過去一年,我們從部分使用 TS 變為全面切換到 TS,包括我們自己開發的工具庫等。

TS 最大的優勢是它提供了強大的靜態分析能力,結合 TSLint 能對程式碼做到更加嚴格的檢查約束。傳統的 EcmaScript 由於沒有靜態型別,即使有了 ESLint 也只能做到很基本的檢查,一些 typo 問題可能線上出了 Bug 後才被發現。

下圖是一個前端應用常見的4層架構。程式碼和工具全面擁抱 TS 後,實現了從後端 API 介面到 View 元件的全鏈路靜態分析,具有了完善的程式碼提示和校驗能力。

給2019前端的5個建議
前後端協作簡圖

除了上面講的 iron-redux,我們引入 Pont 實現前端取數,它可以自動把後端 API 對映到前端可呼叫的請求方法。

Pont 實現原理:
Pont(法語:橋) 是我們研發的前端取數層框架。對接的後端 API 使用 Java Swagger,Swagger 能提供所有 API 的元資訊,包括請求和響應的型別格式。Pont 解析 API 元資訊生成 TS 的取數函式,這些取數函式型別完美,並掛載到 API 模組下。最終程式碼中取數效果是這樣的:

給2019前端的5個建議
介面名、引數、返回值自動提示

Pont 實現的效果有:

  1. 根據方法名自動匹配 url、method,並且對應到 prams、response 型別完美,並能自動提示
  2. 後端 API 介面變更後,前端相關聯的請求會自動報錯,再也不擔心後端悄悄改介面前端不知曉
  3. 再也不需要前後端介面約定文件,使用程式碼保證前端取數和後端介面定義完全一致

另外 iron-redux 能接收到 Pont 介面響應資料格式,並推匯出整個 Redux 狀態樹的靜態型別定義,Store 中的資料完美的型別提示。效果如下:

給2019前端的5個建議
Redux 狀態樹自動提示

最終 TS 讓程式碼更加健壯,尤其是對於大型專案,編譯通過幾乎就代表執行正常,也給重構增加了很多信心

三、迴歸 Sass/Less

2015 年我們就開始實踐 CSS Modules,包括後來的 styled-components 等,到 2019 年 css-in-js 方案依舊爭論不休,雖然它確實解決了一些 CSS 語言天生的問題,但同時增加了不少成本,新手不夠友好、全域性樣式覆蓋成本高漲、偽類處理複雜、與AntD等元件庫結合有坑。與此同時 Sass/Less 社群也在飛速發展,尤其是 Stylelint 的成熟,可以通過技術約束的手段來避免 CSS 的 Bad Parts。

  1. 全域性汙染:約定每個樣式檔案只能有一個頂級類,如 .home-page{ .top-nav {/**/}, .main-content{ /**/ } }。如果有多個頂級類,可以使用 Stylelint rule 檢測並給出警告。
  2. 依賴管理不徹底。藉助 webpack 的 css-loader,已夠用。
  3. JS 和 CSS 變數共享。關於 JS 和 Sass/Less 變數共享,我們摸索出了自己的解法:

以下為 Webpack 配置,注入變數到 Scss

在 scss 檔案中,可以自己引用變數

四、開發工具覆蓋全鏈路

2019 年,你幾乎不可能再開發出 React/Angular/Vue 級別的框架,也沒必要再造 Ant-Design/Fusion-Design/Ng-Zorro 這樣的輪子。難道就沒有機會了嗎?

當然有,結合你自身的產品開發流程,依舊有很多機會。下面是常規專案的開發流程圖,任何一個環節只要深挖,都有提升空間。如果你能通過工具減少一個或多個環節,帶來的價值更大。

給2019前端的5個建議
產品研發流程

單拿其中的『開發』環節展開,就有很多可擴充套件的場景:

給2019前端的5個建議
前端開發工具流

一個有代表性的例子是,我們開發了國際化工具 kiwi。它同樣具有 TS 的型別完美,非常強大的文案提示,另外還有:

  1. VS Code 外掛 kiwi linter,自動對中文文案標紅,如果已有翻譯文案能自動完成替換
  2. Shell 命令全量檢查出沒有翻譯的文案,批量提交給翻譯人員
  3. Codemod 指令碼自動實現舊的國際化方案向 Kiwi 遷移,成本級低

除了以上三點,未來還計劃開發瀏覽器外掛來檢查漏翻文案,利用 Husky 在 git 提交前對漏翻文案自動做機器翻譯等等。

未來如果你只提供一個程式碼庫,那它的價值會非常侷限。你可以參照上面的圖表,開發相應的擴充套件來豐富生態。如果你是新手,推薦學習下編譯原理和對應的擴充套件開發規範。

五、嚴格徹底的 Code Review

過去的一年,我們一共進行了 1200+ 多次 Code Review(CR),很多同事從剛開始不好意思提 MR 到後來追著別人 Review,CR 成為每個人的習慣。通過 CR 讓專案中任何一行程式碼都至少被兩人觸達過,減少了絕大多數的低階錯誤,提升了程式碼質量,這也是幫助新人成長最快的方式之一。

給2019前端的5個建議
其中一個專案MR截圖

Code Review 的幾個技巧:

  1. No magic
  2. Explicit not implicit
  3. 覆蓋度比深度重要,覆蓋度追求100%
  4. 頻率比儀式感重要,坐公交蹲廁所開啟手機都可以 Review 別人程式碼,不需要專門組織會議
  5. 粒度要儘可能小,一個元件一個方法均可,可以結合 Git Flow
  6. 24h 小時內處理,無問題直接 merge,有問題一定要留 comment,並且提供 action
  7. 對於亟待上線來不及 Review 的程式碼,可以先合併上線,上線後再補充 Review
  8. 需要自上而下的推動,具有完善的規範,同時定期總結 Review 經驗來豐富開發規範
  9. CR 並不只是為了找錯,看到好的程式碼,不要吝嗇你的讚美
  10. 本質是鼓勵開發者間更多的溝通,互相學習,營造技術文化氛圍

總結

以上5點當然不是我們技術的全部。除此之外我們還實踐了移動端開發、視覺化圖表/WebGL、Web Worker、GraphQL、效能優化等等,但這些還停留在術的層面,未來到一定程度會拿出來分享。

如果你也準備或正在開發複雜的前端應用,同時團隊人員多樣技術背景各異,可以參考以上5點,使用 Redux 實現規範清晰可預測的狀態管理,深耕 TypeScript 來提升程式碼健壯性和可維護性,藉助各種 Lint 工具迴歸簡單方便的 CSS,不斷打磨自己的開發工具來保證開發規範高效,並嚴格徹底實行 Code Review 促進人的交流和提升。

Links

  1. Pont:nefe/pont
  2. Kiwi:nefe/kiwi
  3. iron-redux: nefe/iron-redux
  4. The State of JavaScript 2018

如果你覺得本文對你有幫助,請猛擊喜歡鼓勵一下

相關文章