非常全面的前端協作規範(長文建議先收藏)

  • 2019 年 10 月 6 日
  • 筆記

原文作者:掘金 _sx_

原文鏈接:https://juejin.im/post/5d3a7134f265da1b5d57f1ed

萬字長文,繼續刷新我的文章長度記錄,涉及前端開發的方方面面。本文將持續更新和完善, 文章部分觀點可能比較武斷或不完整,歡迎評論和補充,一起完善該文章. 謝謝

筆者長期單槍匹馬在前端領域廝殺(言外之意就是團隊就一個人),自己就是規範。隨着公司業務的擴展,擴充了一些人員,這時候就要開始考慮協作和編碼規範問題了。本文記錄了筆者在制定前端協作規範時的一些思考,希望能給你們也帶來一些幫助.

一個人走的更快,一群人可以走得更遠,前提是統一的策略,還要不斷地反省和優化。

以下是目錄概覽, 看出這是一篇浩浩蕩蕩的長文

  • 1 工作流規範
    • 1.1.1 版本規範
    • 1.1.2 版本控制系統規範
    • 1.1.3 提交信息規範
    • 1.1 開發
    • 1.2 構建規範
    • 1.3 發佈工作流規範
    • 1.4 持續集成
    • 1.5 任務管理
  • 2 技術棧規範
    • 2.1 技術選型
    • 2.2 迎接新技術
  • 3 瀏覽器兼容規範
    • 3.1 確定兼容策略
    • 3.2 確定瀏覽器分級
    • 3.3 獲取統計數據
  • 4 項目組織規範
    • 4.1 通用的項目組織規範
    • 4.2 目錄組織的風格
    • 4.3 腳手架和項目模板
  • 5 編碼規範
    • 5.1 Javascript
    • 5.2 HTML
    • 5.3 CSS
    • 5.4 代碼格式化
    • 5.5 集大成的
    • 5.6 特定框架風格指南
    • 5.7 Code Review
  • 6 文檔規範
    • 6.1 建立文檔中心
    • 6.2 文檔格式
    • 6.3 定義文檔的模板
    • 6.4 討論即文檔
    • 6.5 注釋即文檔
    • 6.6 代碼即文檔
  • 7 UI設計規範
  • 8 測試規範
    • 8.1 測試的流程
    • 8.2 單元測試
  • 9 異常處理、監控和調試規範
    • 9.1 異常處理
    • 9.2 日誌
    • 9.3 異常監控
  • 10 前後端協作規範
    • 10.1 協作流程規範
    • 10.2 接口規範
    • 10.3 接口文檔規範
    • 10.4 接口測試與模擬
  • 11 培訓/知識管理/技術沉澱
    • 11.1 新人培訓
    • 11.2 營造技術氛圍
  • 12 反饋

CHANGELOG

  • 2019.7.28 新增技術選型
  • 2019.7.29 新增瀏覽器統計數據獲取
  • 2019.9.6 建立技術氛圍一節 新增面試題庫

什麼是規範?

規範,名詞意義上:即明文規定或約定俗成的標準,如:道德規範、技術規範等。動詞意義上:是指按照既定標準、規範的要求進行操作,使某一行為或活動達到或超越規定的標準,如:規範管理、規範操作.

為什麼需要規範?

  • 降低新成員融入團隊的成本, 同時也一定程度避免挖坑
  • 提高開發效率、團隊協作效率, 降低溝通成本
  • 實現高度統一的代碼風格,方便review, 另外一方面可以提高項目的可維護性
  • 規範是實現自動化的基礎
  • 規範是一個團隊知識沉澱的直接輸出

規範包含哪些內容?

如文章標題,前端協作規範並不單單指『編碼規範』,這個規範涉及到前端開發活動的方方面面,例如代碼庫的管理、前後端協作、代碼規範、兼容性規範;

不僅僅是前端團隊內部需要協作,一個完整的軟件生命周期內,我們需要和產品/設計、後端(或者原生客戶端團隊)、測試進行協作, 我們需要覆蓋這些內容.

下面就開始介紹,如果我是前端團隊的Leader,我會怎麼制定前端規範,這個規範需要包含哪些內容?

1 工作流規範

1.1 開發

1.1.1 版本規範

項目的版本號應該根據某些規則進行迭代, 這裡推薦使用語義化版本規範, 通過這個規範,用戶可以了解版本變更的影響範圍。規則如下:

  • 主版本號:當你做了不兼容的 API 修改,
  • 次版本號:當你做了向下兼容的功能性新增,
  • 修訂號:當你做了向下兼容的問題修正。

1.1.2 版本控制系統規範

大部分團隊都使用git作為版本庫,管理好代碼也是一種學問。尤其是涉及多人並發協作、需要管理多個軟件版本的情況下,定義良好的版本庫管理規範,可以讓大型項目更有組織性,也可以提高成員協作效率.

比較流行的git分支模型/工作流是git-flow, 但是大部分團隊會根據自己的情況制定自己的git工作流規範, 例如我們團隊的分支規範

Git 有很多工作流方法論,這些工作流的選擇可能依賴於項目的規模、項目的類型以及團隊成員的結構.

比如一個簡單的個人項目可能不需要複雜的分支劃分,我們的變更都是直接提交到 master 分支;

再比如開源項目,除了核心團隊成員,其他貢獻者是沒有提交的權限的,而且我們也需要一定的手段來驗證和討論貢獻的代碼是否合理。所以對於開源項目 fork 工作流更為適合.

了解常見的工作流有利於組織或創建適合自己團隊的工作流, 提交團隊協作的效率:

  • 簡單的集中式
  • 基於功能分支的工作流
  • Git Flow ?
  • Fork/Pull Request 工作流

1.1.3 提交信息規範

組織好的提交信息, 可以提高項目的整體質量. 至少具有下面這些優點:

  • 格式統一的提交信息有助於自動化生成CHANGELOG
  • 版本庫不只是存放代碼的倉庫, 它記錄項目的開發日誌, 它應該要清晰表達這次提交的做了什麼. 這些記錄應該可以幫助後來者快速地學習和回顧代碼, 也應該方便其他協作者review你的代碼
  • 規範化提交信息可以促進提交者提交有意義的、粒度合適的'提交'. 提交者要想好要怎麼描述這個提交,這樣被動促進了他們去把控提交的粒度

社區上比較流行的提交信息規範是Angular的提交信息規範, 除此之外,這些也很不錯:

  • Atom
  • Ember
  • Eslint
  • JQuery

另外這些工具可以幫助你檢驗提交信息, 以及生成CHANGELOG:

  • conventional-changelog – 從項目的提交信息中生成CHANGELOG和發佈信息
  • commitlint – 檢驗提交信息
  • commitizen – ?簡單的提交規範和提交幫助工具,推薦
  • standard-changelog – angular風格的提交命令行工具

1.2 構建規範

對於團隊、或者需要維護多個項目場景,統一的構建工具鏈很重要, 這套工具應該強調"約定大於配置",讓開發者更專註於業務的開發。筆者在<為什麼要用vue-cli3?>文章中提出了vue-cli3更新有很多亮點,非常適合作為團隊構建工具鏈的基礎:

  • 首先這類工具是推崇'約定大於配置'。即按照他們的規範,可以實現開箱即用,快速開發業務. 在團隊協作中這點很重要,我們不推薦團隊成員去關心又臭又長的webpack構建配置
  • vue-cli3抽離了cli service層,可以獨立更新工具鏈。也就是說項目的構建腳本和配置在一個獨立的service項目中維護,而不是像以前一樣在每個項目目錄下都有webpack配置和依賴. 這樣做的好處是獨立地、簡單地升級整個構建鏈
  • 靈活的插件機制。對於團隊的定製化構建應該封裝到插件中,這樣也可以實現獨立的更新。

我們可以選擇第三方CLI, 當然也定製自己的構建鏈,按照上面說的這個構建鏈應該有以下特點:

  • 強約定,體現團隊的規範。首先它應該避免團隊成員去關心或更改構建的配置細節,暴露最小化的配置接口。 另外構建工具不僅僅是構建,通常它還會集成代碼檢查、測試等功能
  • 方便升級。尤其是團隊需要維護多個項目場景, 這一點很有意義

下面是社區上比較流行的構建工具. 當然,你也可以根據自己的團隊情況開發自己的CLI, 但是下面的工具依然很有參考價值

  • create-react-app – ?零配置開始React開發
  • vue-cli – ?零配置、漸進增強的項目構建CLI
  • parcel – 零配置的Web應用打包工具
  • Fusebox – 高速易用的打包工具
  • microbundle – 零配置, 基於Rollup,適合用於打包『庫』

1.3 發佈工作流規範

發佈工作流指的是將『軟件成品』對外發佈(如測試或生產)的一套流程, 將這套流程規範化後,可以實現自動化.

舉個例子, 一個典型的發佈工作流如下:

  • 代碼變更
  • 提交代碼變更到遠程版本庫
  • 程序通過CI測試(例如Travis變綠)
  • 提升package.json中的版本
  • 生成CHANGELOG
  • 提交package.json和CHANGELOG.md文件
  • 打上Tag
  • 推送

如果你遵循上面的規範,那麼就可以利用社區上現有的工具來自動化這個流程. 這些工具有:

  • conventional-changelog-cli
  • conventional-github-releaser
  • 實際上自己開發一個也不是特別難的事情.

1.4 持續集成

將整套開發工作流確定下來之後, 就可以使用持續集成服務來自動化執行整個流程。比如一個典型的CI流程:

持續集成是什麼,有什麼意義呢?

我們需要持續集成拆成兩個詞分別來理解, 什麼是持續? 什麼是集成?

持續(Continuous), 可以理解為'頻繁'或者『連續性』. 不管是持續集成還是敏捷開發思維、看板,都認為『持續』是它們的基礎。

舉一個通俗的例子,比如代碼檢查,『持續的』的代碼檢查就是代碼一變動(如保存,或者IDE實時檢查、或者提交到版本庫時)就馬上檢查代碼,而『非持續』的代碼檢查就是在完成所有編碼後,再進行檢查。對比兩者可以發現,持續性的代碼檢查可以儘早地發現錯誤,而且錯誤也比較容易理解和處理,反之非持續性的代碼檢查,可能會發現一堆的錯誤,失之毫釐謬以千里,錯誤相互牽連,最終會變得難以收拾。

『持續』的概念,可以用於軟件開發的方方面面,本質上就是把傳統瀑布式的軟件開發流程打碎,形成一個個更小的開發閉環,持續地輸出產品,同時產品也持續地給上游反饋和糾正。

那什麼是『集成』呢?狹義的集成可以簡單認為是『集成測試』吧. 集成測試可以對代碼靜態測試、單元測試、通過單元測試後可以進行集成測試,在應用組成一個整體後在模擬環境中跑E2E測試等等。也就是說,在這裡進行一系列的自動化測試來驗證軟件系統。

廣義的持續集成服務,不僅僅是測試,它還衍生出很多概念,例如持續交付、持續部署,如下圖

OK, 總結一下為什麼持續集成的好處:

  • 儘早發現錯誤,快速試錯。越早發現錯誤,處理錯誤的成本越低
  • 自動化工作流,減少人工干預。人類比機器容易犯錯, 而且機器擅長做重複的事情

對於持續集成規範一般會定義這些內容:

  • 執行的環境. 比如容器、Node版本、操作系統等等
  • 觸發的條件。比如定時觸發、在哪個分支觸發、會觸發什麼任務等等
  • 執行的任務
  • 劃分持續集成的階段. 比如
    • 檢查:包括單元測試和代碼lint. 所有push到版本庫的代碼都會跑這個階段. 一般可以在提交title中包含[ci skip]來跳過這個階段
    • 構建: 對前端項目進行構建. 只有打上版本tag的提交或release分支會跑構建任務
    • 發佈: 將前端的構建結果進行交付/發佈. 只有打上版本tag的提交或者release分支在構建成功後會跑發佈任務
  • 定義持續集成腳本模板

常用的CI服務:

  • Github
    • Travis CI
    • CircleCI
    • 完整列表
  • GitLab: Gitlab-CI
  • 通用
    • Jenkins

擴展

  • 持續集成是什麼

1.5 任務管理

作為前端Leader少不了任務管理。看板是目前最為流行的任務管理工具,它可以幫助我們了解項目的進度、資源的分配情況、還原開發現場.

筆者畢業第一年在一家很小的外包公司中工作,初生牛犢不怕虎,我竟然給老闆推銷起了看板和敏捷項目管理,想要改善項目管理這塊效率低下問題,老闆表示很支持,但是其他成員積極性並不高, 結果當然是失敗的。

當時還起草了一份『看板實施細則』, 所以任務管理這一塊也算小有心得吧.

說說一些比較好用的工具吧:

  • 基於issue看板 – 可以基於Gitlab或Github的Issue來做任務管理,它們都支持看板。很Geek,推薦
  • Tower – 專門做看板任務管理的。小團隊基本夠用。我們現在就使用這款產品
  • teambition – 和Tower差不多,沒有深入使用過
  • Trello – 顏值高.

2 技術棧規範

筆者現在所在的公司之前前端技術棧就非常混亂,Vue、React和AngularJS三大框架都有, 而且風格相差也很大. 當時我就想收包裹走人. 關於技術棧不規範的下場可以參考印度的飛機: <為什麼印度的飛機頻繁被摔?>

很少有人能精通這三個框架的,更別說是一個團隊。

三大框架跟編程語言一樣都有自己的設計哲學,這跟庫是不一樣, 一個庫的替換成本很低;而框架的背後是一個架構、一個生態。每個框架背後牽涉着開發思維、生態系統、配套工具、最佳實踐、性能調優。要精通和熟練一個框架需要付出的成本是很高。

所以說團隊的開發效率是基於穩定且熟練的技術棧的。穩定的技術棧規範有利於團隊協作和溝通; 另外如果團隊精通這個技術棧,當出現問題或者需要深入調優, 會相對輕鬆。

前端技術棧規範主要包含下面這些類型:

  • 編程語言 – Typescript或Javascript
  • UI框架及其配套生態, 以及備選方案。其背後的生態非常龐大:
    • UI框架
    • 路由
    • 狀態管理
    • 組件庫
    • 國際化
    • 動畫
    • 服務端渲染
    • 腳手架、CLI工具
    • 組件測試
  • 樣式. 包含了命名規範、預處理器、方法論等等
  • 動畫引擎
  • QA. 包含了測試、Lint、格式化工具、監控
  • 項目構建工具流. 例如webpack、vue-cli
  • 包管理器。npm、yarn
  • 項目管理工具
  • 時間處理。例如Moment.js
  • 模板引擎
  • 開發工具
  • 後端開發框架
  • 工具庫
  • 開發/調試工具
  • 等等

可以參考一下我們團隊的技術棧規範

2.1 技術選型

如何從零對團隊的技術棧進行規範, 或者說怎麼進行選型呢?舉個例子, 先確定備選項, 你現在要選Vue還是選React(一個可能引起論戰的主題)?

恰好前幾天在SegmentFault回答了一個問題: <什麼時候用vue什麼時候用react?>, 我講了一個我們幾年前是如何決定要使用React還是Vue的例子(注意結果不重要!):

<談談技術選型的注意事項>這篇文章寫得非常好,給了我一些啟發。結合上面的回答的例子, 來講一講在對相關技術進行選型的一些方法(評分項):

  • 選擇你最熟悉的技術。上面說到團隊如果熟悉該技術,則可以很好地控制使用過程中的風險,方便對程序進行調優。所以成員熟悉、或至少Leader熟悉程度,是技術選型的一個打分項。 我們團隊最終選擇React的一個原因,就是我們熟悉它,它已經在現有的幾個應用中良好的運行了,所以 React + 1
  • 選擇擁有強大生態和社區支撐的開源技術。有強大的生態和社區意味着,很多東西你不需要重複去造輪子,或者遇到問題可以很快解決,有更多的選擇。從公司層面、使用活躍的技術也比較好招人。 上面的例子也提到了這點,幾年前React的生態是強於Vue的,所以 React + 1
  • 選擇成長期的技術。<談談技術選型的注意事項>裏面有一句話:'選擇一個技術的最低標準是,技術的生命周期必須顯著長於項目的生命周期' 我們選擇的技術應該是向前發展的、面向未來的, 這是選型的基本原則。所以我們一般不會去選擇那些'過氣'的技術,比如AngularJS(1.x)、Backbone. 因為現在有更好的選擇,不必過於保守。 『向前』還意味着Leader要能夠預判該技術未來走向,這裡有很多參考因素,比如大廠的支撐、目前社區的活躍度、開發活躍度等等 React、Vue都非常有動力,比如React最近的React Hook、還有未來的ConcurrentMode、Async Rendering… 在這點上Vue和React打成平手吧
  • API的穩定性。比較典型的例子就是Angular和Python,API不穩定會導致社區的割裂,也會導致項目升級成本變高、或者無法升級, 最終成為技術債。 不過值得慶幸的是因為有這麼多歷史教訓,現在開源項目在API變更上面是非常謹慎的,參考[譯] Vue 最黑暗的一天事件. 這點上React和Vue依舊打平
  • 基礎設施配合。一個技術往往不是孤立存在的,它需要和其他技術相互配合,這種技術之間的融合度也是需要考慮的。 這個根據團隊使用情況來定,比如我們團隊統一使用Typescript,Vue跟Typescript配合使用其實不理想,所以 React + 1
  • 業務考慮 <談談技術選型的注意事項> 提到一點就是『學會從業務端開始思考』. 意思就是選型需要充分地理解業務,理解用戶需求,當下需要解決的首要問題,以及可能的風險有哪些,再將目標進行分解,進行具體的技術選型、模型設計、架構設計. 一個典型的例子就是10年前火遍世界的Rails, 後端是使用Rails還是Java/C#/PHP這些傳統後端技術? 很多初創公司(如Github、Gitlab、Twitter)選擇了前者,他們需要快速開發原型、快速佔領市場, Rails開發很爽很快啊, 這種選型就是符合『業務需求的』。 那麼前端好像跟業務離得有點遠? 隨着『大前端』的發展,我們的工作對公司業務的影響只會越來越大。 比如上面提到的React Native,我們當時有考慮在移動端應用React Native技術,實現客戶端的跨平台,這就是業務影響啊。這時候React是不是又要 +1? 同理還有什麼服務端渲染、Serverless等等,期待前端的地位會越來越高

綜上,在這個案例中,React是勝出的。

擴展:

  • 談談技術選型
  • 談談技術選型的注意事項

2.2 迎接新技術

當然,對於團隊而言也要鼓勵學習新的技術、淘汰舊的技術棧。因為一般而言新的技術或解決方案,是為了更高的生產力而誕生的。當團隊容納一個新的技術選型需要考慮以下幾點:

  • 學習成本。考慮團隊成員的接納能力。如果成本小於收穫的利益,在團隊裏面推行估計阻力會比較大
  • 收益。是否能夠解決當前的某些痛點
  • 考慮風險。一般我們不能將一個實驗階段的技術使用的生產環境中

就我們團隊而言,每個成員都有自己感興趣的方向和領域,所以我們可以分工合作,探索各自的領域,再將成果分享出來,如果靠譜的話則可以在實驗項目中先試驗一下,最後才推廣到其他項目.

3 瀏覽器兼容規範

前端團隊應該根據針對應用所面對的用戶情況、應用類型、開發成本、瀏覽器市場統計數據等因素,來制定自己的瀏覽器兼容規範,並寫入應用使用手冊中.

有了瀏覽器兼容規範,前端開發和兼容性測試就有理有據,避免爭議; 同時它也是前端團隊的一種對外聲明,除非特殊要求,不符合瀏覽器兼容規範的瀏覽器,前端開發人員可以選擇忽略。

3.1 確定兼容策略

漸進增強還是優雅降級. 這是兩個不同方向策略,漸進增強保證低版本瀏覽器的體驗,對於支持新特性的新瀏覽器提供稍好的體驗;優雅降級則是相反的,為現代瀏覽器提供最好的體驗,而舊瀏覽器則退而求之次,保證大概的功能.

選擇不同的策略對前端開發的影響是比較大的,但是開發者沒有選擇權。確定哪種兼容策略,應該取決於用戶比重,如果大部分用戶使用的是現代瀏覽器,就應該使用優雅降級,反之選擇漸進增強.

3.2 確定瀏覽器分級

YUI就曾提出瀏覽器分級原則,到今天這個原則依然適用。簡單說就是將瀏覽器劃分為多個等級,不同等級表示不同的支持程度. 比如我們團隊就將瀏覽器劃分為以下三個等級:

  • 完全兼容: 保證百分百功能正常
  • 部分兼容: 只能保證功能、樣式與需求大致一致。對於一些不影響主體需求和功能的bug,會做降低優先級處理或者不處理。
  • 不兼容: 不考慮兼容性

一般而言, 根據瀏覽器市場分佈情況、用戶佔比、開發成本等因素劃分等級.

舉個例子,下面是我們對管理系統的兼容規範:

3.3 獲取統計數據

百度統計是中文網站使用最為廣泛的、免費的流量分析平台. 如上圖,通過這些統計平台可以獲取到終端真實的瀏覽器使用情況, 點擊查看示例。

如果公司沒有開發自己監控服務,還是建議使用這些免費的,有大廠支持的監控工具:

  • 百度統計
  • 友盟
  • Google Analytics 需要kx上網

可以從這些地方獲取通用的瀏覽器統計數據:

  • 百度流量研究院:主要提供國內瀏覽器統計
  • statcounter: 國際瀏覽器統計
  • 瀏覽器發佈年份統計

確定瀏覽器是否支持某個特性:

  • caniuse
  • MDN

4 項目組織規範

項目組織規範定義了如何組織一個前端項目, 例如項目的命名、項目的文件結構、版本號規範等等。尤其對於開源項目,規範化的項目組織就更重要了。

4.1 通用的項目組織規範

一個典型的項目組織規範如下:

  • README.md: 項目說明, 這個是最重要。你必須在這裡提供關於項目的關鍵信息或者相關信息的入口. 一般包含下列信息:
    • 簡要描述、項目主要特性
    • 運行環境/依賴、安裝和構建、測試指南
    • 簡單示例代碼
    • 文檔或文檔入口, 其他版本或相關資源入口
    • 聯繫方式、討論群
    • 許可、貢獻/開發指南
  • CHANGELOG.md: 放置每個版本的變動內容, 通常要描述每個版本變更的內容。方便使用者確定應該使用哪個版本. 關於CHANGELOG的規範可以參考keep a changelog
  • package.json: 前端項目必須. 描述當前的版本、可用的命令、包名、依賴、環境約束、項目配置等信息.
  • .gitignore: 忽略不必要的文件,避免將自動生成的文件提交到版本庫
  • .gitattributes: git配置,有一些跨平台差異的行為可能需要在這裡配置一下,如換行規則
  • docs/: 項目的細化文檔, 可選.
  • examples/: 項目的示例代碼,可選.
  • build: 項目工具類腳本放置在這裡,非必須。如果使用統一構建工具,則沒有這個目錄
  • dist/: 項目構建結果輸出目錄
  • src/: 源代碼目錄
  • tests/: 單元測試目錄. 按照Jest規範, __tests__目錄通常和被測試的模塊在同一個父目錄下, 例如: /src __tests__/ index.ts a.ts index.ts a.ts 複製代碼
  • tests: 全局的測試目錄,通常放應用的集成測試或E2E測試等用例
  • .env*: 項目中我們通常會使用環境變量來影響應用在不同運行環境下的行為. 可以通過dotEnv來從文件中讀取環境變量. 通常有三個文件: 基本上這些文件的變動的頻率很少,團隊成員應該不要隨意變動,以免影響其他成員。所以通常會使用.env.*.local文件來覆蓋上述的配置, 另外會設置版本庫來忽略*.local文件.
    • .env 通用的環境變量
    • .env.development 開發環境的環境變量
    • .env.production 生成環境的環境變量

對於開源項目通常還包括這些目錄:

  • LICENSE: 說明項目許可
  • .github: 開源貢獻規範和指南
    • CONTRIBUTING: 貢獻指南, 這裡一般會說明貢獻的規範、以及項目的基本組織、架構等信息
    • CODE_OF_CONDUCT: 行為準則
    • COMMIT_CONVENTION: 提交信息規範,上文已經提及
    • ISSUE_TEMPLATE: Issue的模板,github可以自動識別這個模板
    • PULL_REQUEST_TEMPLATE: PR模板

任意一個優秀的開源項目都是你的老師,例如React、Vue…

4.2 目錄組織的風格

上面只是一個通用的項目組織規範,具體源代碼如何組織還取決於你們使用的技術棧和團隊喜好。網上有很多教程,具體可以搜索怎麼組織XX項目. 總結一下項目組織主要有三種風格:

  • Rails-style: 按照文件的類型劃分為不同的目錄,例如componentsconstantstypingsviews. 這個來源於Ruby-on-Rails框架,它按照MVC架構來劃分不同的目錄類型,典型的目錄結構如下: app models # 模型 views # 視圖 controllers # 控制器 helpers # 幫助程序 assets # 靜態資源 config # 配置 application.rb database.yml routes.rb # 路由控制 locales # 國際化配置 environments/ db # 數據庫相關 複製代碼
  • Domain-style: 按照一個功能特性或業務創建單獨的目錄,這個目錄就近包含多種類型的文件或目錄. 比如一個典型的Redux項目,所有項目的文件就近放置在同一個目錄下: Users/ Home/ components/ actions.js actionTypes.js constants.js index.js model.js reducer.js selectors.js style.css index.js rootReducer.js 複製代碼
  • Ducks-style: 優點類似於Domain-style,不過更徹底, 它通常將相關聯的元素定義在一個文件下。Vue的單文件組件就是一個典型的例子,除此之外Vuex也是使用這種風格: <template> <div id="app"> <h1>My Todo App!</h1> <TodoList/> </div> </template> <script> import TodoList from './components/TodoList.vue' export default { components: { TodoList } } </script> <style lang="scss"> @import './variables.scss'; /* … */ </style> 複製代碼

大部分情況下, 我們都是使用混合兩種方式的目錄結構,例如:

src/    components/      # ? 項目通用的『展示組件』      Button/        index.tsx    # 組件的入口, 導出組件        Groups.tsx   # 子組件        loading.svg  # 靜態資源        style.css    # 組件樣式      ...      index.ts       # 到處所有組件    containers/      # ? 包含'容器組件'和'頁面組件'      LoginPage/     # 頁面組件, 例如登錄        components/  # 頁面級別展示組件,這些組件不能復用與其他頁面組件。          Button.tsx # 組件未必是一個目錄形式,對於一個簡單組件可以是一個單文件形式. 但還是推薦使用目錄,方便擴展          Panel.tsx        reducer.ts   # redux reduces        useLogin.ts  # (可選)放置'邏輯', 按照?分離邏輯和視圖的原則,將邏輯、狀態處理抽取到hook文件        types.ts     # typescript 類型聲明        style.css        logo.png        message.ts        constants.ts        index.tsx      HomePage/      ...      index.tsx      # ?應用根組件    hooks/           # ?可復用的hook      useList.ts      usePromise.ts    ...    index.tsx        # 應用入口, 在這裡使用ReactDOM對跟組件進行渲染    stores.ts        # redux stores    contants.ts      # 全局常量  複製代碼

框架官方很少會去干預項目的組織方式,讀者可以參考下面這些資源來建立自己項目組織規範:

  • Redux 常見問題:代碼結構
  • react-boilerplate
  • vuex 項目結構
  • React組件設計實踐總結02 – 組件的組織

4.3 腳手架和項目模板

在將項目結構規範確定下來後,可以創建自己的腳手架工具或者項目模板,用於快速初始化一個項目或代碼模板。

相關資源:

  • yeoman – 老牌的項目腳手架工具
  • plop – 代碼生成輔助CLI
  • hygen – 類似於plop
  • generact – 生成React組件, 大部分組件的文件結構差不多, 這個工具就是幫助你生成這些重複的代碼
  • babel-code-generator – 利用babel來實現更高級的代碼編輯和自動生成

5 編碼規範

網絡上大部分『前端規範』指的都是編碼規範, 這是一種『狹義』的前端規範.

統一的編碼規範對團隊項目的長遠維護不無裨益. 一致性的代碼規範可以增強團隊開發協作效率、提高代碼質量、減少遺留系統維護的負擔。

最直接的好處就是避免寫出糟糕的代碼, 糟糕的代碼與新手和老手關係不大,我也見過好處工作很多年的『資深』工程師寫出噁心的代碼. 這樣的代碼隨着項目的迭代會變得難以控制。

現代的Lint工具已經非常先進,幾乎可以約束各種編碼行為. 比如約束一個文件的長度、函數的複雜度、命名規範、注釋規範、接口黑名單、DeadCode、檢查簡單的邏輯錯誤…

每一個程序員心目中對『好代碼』都有自己的主見,統一的編碼規範可以像秦始皇統一戰國一樣,避免不必要的論戰和爭議。

其實與其自己建立前端編碼規範,筆者推薦選擇社區沉澱下來的規範. 這方面的資源非常多,所以本文也不武斷地提出自己的規範建議. 推薦下面這些資源:

5.1 Javascript

  • Lint工具
    • ESLint – ?目前是社區最流行的、通用的Javascript Lint工具,Lint界的Babel。支持定製插件、preset。如果不想折騰可以選擇它的一些預定義配置
    • TSLint – Typescript Lint工具。不過即將廢棄了, 推薦使用ESLint
  • 規範
    • JavaScript Standard Style – ? 零配置的、『標準』的Javascript編碼規範. 底層基於Eslint。目前不支持Typescript
    • Airbnb JavaScript Style Guide – Airbnb的編碼規範,業界標杆
  • 類型檢查. 暫時將它們歸類到這裡,因為它們同屬於『靜態測試』
    • Typescript – ? Javascript語言的超集,這是一門『新』的語言,而不是簡單的類型檢查器. 不過它也支持原生Javascript的類型檢查
    • Flow – Facebook出品的類型檢查器,語法和Typescript類似. 個人推薦使用Typescript

5.2 HTML

  • Lint工具
    • HTMLHint
    • bootlint
  • 規範
    • Code Guide

5.3 CSS

  • Lint工具
    • stylelint – ? 通用的CSS編碼檢查工具,支持最新的CSS語法、CSS-in-js、以及其他類CSS語法(如SCSS、Less). 它也有預定義配置,推薦使用
  • 規範
    • Airbnb CSS / Sass Styleguide
    • Code Guide
    • 更多
  • 方法論
    • BEM – ? BEM命名規範
    • OOCSS
    • smacss

關於CSS可以學習Bootstrap這些傳統UI框架,他們的代碼組織性非常好, 值得學習

5.4 代碼格式化

  • Prettier – ? 關於代碼格式化的所有東西都交給它吧!

基本上,所有代碼格式相關的工作都可以交給Prettier來做,在這個基礎上再使用Eslint覆蓋語義相關的檢查

5.5 集大成的

  • isobar 前端代碼規範及最佳實踐
  • 凹凸實驗室代碼規範
  • 百度FEX規範
  • 老牌的NEC規範 – 有點老

5.6 特定框架風格指南

  • vue-style-guide
  • Airbnb React/JSX Style Guide
  • React組件設計實踐總結 – 自薦一下筆者寫的React組件設計相關實踐

5.7 Code Review

上述的Lint工具和類型檢查器, 可以約束代碼風格、避免低級的語法錯誤。但是即使通過上面的Lint和類型檢查,代碼也可能未必是『好代碼』。

很多代碼設計的『最佳實踐』是無法通過具象化的自動化工具或文檔覆蓋的, 這時候,'經驗'或者'群體智慧'就派上用場了. 比如Code Review階段會檢查這些東西:

  • 編程原則、設計思想. 例如符合SOLID原則? 是否足夠DRY?接口設計是否簡潔易擴展、
  • 模塊耦合程度、代碼重複
  • 代碼健壯性。是否存在內存泄露、是否線程安全、是否有潛在性能問題和異常、錯誤是否被處理
  • 代碼的性能和效率。
  • 是否有沒有考慮到的場景?

如果你們是第一次推行Code Review, 可以建立一個檢查列表,對照着進行檢查。熟練後,心中自然無碼。

Code Review有很多好處,比如:

  • Code Review可以讓其他成員都熟悉代碼。這樣保證其他人都可以較快地接手你的工作,或者幫你解決某些問題
  • 提高代碼質量。毫無疑問. 一方面是主動性的代碼質量提升,比如你的代碼需要被人Review,會自覺盡量的提高代碼質量;另一方面,其他成員可以檢查提交方的代碼質量
  • 檢查或提高新成員的編程水平。培養新人時,由於不信任它們提交的代碼,我們會做一次Review檢查代碼是否過關。另一方面這是一次真實的案例講解, 可以較快提高他們的能力

Code Review有兩種方式: 一個提交時、一個是定時:

  • 提交時. 大部分開源項目採用這種方式。通俗講就是Pull Request。只有代碼通過測試、和其他成員的Review才可以合進正式版本庫。這種方式也稱為『阻塞式』代碼檢查,一般配合GitFlow使用。
  • 定時. 在項目完結後、項目的某個裡程碑、或者固定的時間(每天、每個星期..). 團隊成員聚在一起,回顧自己寫的代碼, 讓其他成員進行審查

Code Review是比較難以推行的,不過這個也要看你們團隊的情況,向我們錢少活多的團隊,很少的時間去立馬去兼顧其他成員的代碼. 這時候定時Review會更有用,因為看起來更『節省時間』.

提交時Review則可以針對新人,比如你不信任他們的代碼或者希望幫助他們提高編碼能力。

相關資源:

  • Code Review最佳實踐
  • 是否要做Code Review?與BAT資深架構師爭論之後的思考
  • 一些Code Review工具

6 文檔規範

文檔對於項目開發和維護、學習、重構、以及知識管理非常重要。

和寫測試一樣、大部分開發人員會覺得寫文檔是一件痛苦的事情,不過只有時間能夠證明它的價值。比如對於人員流動比較大的公司,如果有規範的文檔體系,轉交工作就會變動非常輕鬆.

廣義的文檔不單指『說明文件』本身,它有很多形式、來源和載體,可以描述一個知識、以及知識形成和迭代的過程。例如版本庫代碼提交記錄、代碼注釋、決策和討論記錄、CHANGELOG、示例代碼、規範、傳統文檔等等

6.1 建立文檔中心

我們公司是做IM的,所以之前我們優先使用'自己的'通訊工具來分享文檔,這種方式有很大問題:

  1. 如果沒有存檔習慣(比如後端的API文檔,因為由後端維護,一般不會主動去存檔), 文檔就可能丟失,而且通訊工具是不會永久保存你的文檔的。當丟失文件就需要重新和文檔維護者索要
  2. 糟糕的是文檔維護者也是自己手動在本地存檔的,這樣導致的問題是: 如果工作轉交,其他開發者需要花費一點時間來查找; 丟失了就真的沒了
  3. 每一次文檔更新要重新發一份, 這很麻煩,而且可能出現漏發的情況, 導致前後不一致.
  4. 關於知識的學習、以及有意義的討論記錄無法歸檔。

上面介紹的是一種非常原始的文檔共享方式,很多小團隊就是這麼乾的。

對於項目本身的文檔建議放置在關聯項目版本庫裏面,跟隨項目代碼進行迭代, 當我們在檢索或跟蹤文檔的歷史記錄時,這種方式是最方便的。

然而很多應用是跨越多個團隊的,每個團隊都會有自己的文檔輸出(比如需求文檔、系統設計文檔、API文檔、配置文檔等等),而且通常也不會在一個版本庫里。這時候文檔就比較分散。所以一個統一的文檔中心是很有必要。

我們公司現在選擇的方案是Git+Markdown,也就是說所有的文檔都放置在一個git版本庫下。之前也考慮過商業的方案,譬如石墨文檔、騰訊文檔, 但管理層並不信任這些服務。

大概的git項目組織如下:

規範/  A應用/    產品/    設計/    API文檔/    測試/    其他/  B應用/  複製代碼

Git版本庫(例如Gitlab)有很多優勢,例如歷史記錄跟蹤、版本化、問題討論(可以關聯issue、或者提交)、多人協作、搜索、權限管理(針對不同的版本庫或分組為不同人員設置權限)等等。

Git+Markdown可以滿足開發者的大部分需求。但是Git最擅長的是處理純文本文件、對於二進制是無能為力的,無法針對這些類型的文檔進行在線預覽和編輯。

所以Git+Markdown並不能滿足多樣化的文檔處理需求,比如思維導圖、圖表、表格、PPT、白板等需求. 畢竟它不是專業的文檔處理工具。所以對於產品、設計人員這些富文檔需求場景,通常會按照傳統方式或者更專業的工具對文檔進行管理.

6.2 文檔格式

毫無疑問,對於開發者來說,Markdown是最適合的、最通用的文檔格式。支持版本庫在線預覽和變更歷史跟蹤。

下面這些工具可以提高Markdown的開發效率:

  • 可視化編輯器
    • Visual Code: 大部分代碼編輯都支持Markdown編輯和預覽
    • Mou: Mac下的老牌編輯器
    • typora: 跨平台的Markdown編輯器,推薦
  • markdownlint: 編碼檢查器
  • 擴展(Visual Studio Code):
    • Markdown All in One: All you need to write Markdown (keyboard shortcuts, table of contents, auto preview and more)
    • Markdown TOC: markdown 目錄生成,我最常用的markdown插件
  • 圖表繪製工具:
    • drawio 基於Web的圖表繪製工具、也有離線客戶端
    • KeyNote/PPT 臨時繪圖也不錯

6.3 定義文檔的模板

關於如何寫好文檔,很難通過標準或規範來進行約束,因為它的主觀性比較強, 好的文檔取決於編輯者的邏輯總結能力、表達能力、以及有沒有站在讀者的角度去思考問題。

所以大部分情況下,我們可以為不同類型的文檔提供一個模板,通過模板來說明一個文檔需要包含哪些內容, 對文檔的編寫者進行引導.

例如一個API文檔可能需要這些內容:

  • 接口的索引
  • 接口的版本、變更記錄
  • 用法和整體描述, 認證鑒權等等
  • 描述具體的接口
    • 功能說明
    • 方法名稱或者URI
    • 參數和返回值定義
    • 調用示例
    • 注意事項等等

具體規範內容因團隊而異,這裡點到為止.

擴展:

  • 中文技術文檔的寫作規範
  • React RFC模板

6.4 討論即文檔

一般情況下,對於一個開源項目來說除了官方文檔,Issues也是一個很重要的信息來源。在Issue中我們可以獲取其他開發者遇到的問題和解決方案、給官方反饋/投票、關注官方的最新動態、和其他開發者頭腦風暴唇槍舌戰等等。

所以相對於使用IM,筆者更推薦Issue這種溝通模式,因為它方便歸檔組織,索引和查找。而IM上的討論就像流水一樣,一去不復返。

當然兩種工具的適用場景不一樣,你拿IM的使用方式來使用Issue,Issue就會變得很水。Issue適合做有意義的、目的明確的討論。所以要譴責一下在Github Issue上灌水的開發者。

關於Issue有很多妙用,推薦閱讀這篇文章<如何使用 Issue 管理軟件項目?>

現在很多開源項目都引入了RFC(請求意見稿)流程(參考React採用新的RFC流程, 以及Vue 最黑暗的一天), 這讓開發者有『翻身農奴、當家做主』的感覺,任何人都可以參與到一個開源項目重大事件的決策之中。每個RFC會說明決策的動機、詳細設計、優缺點。除了官方文檔之外,這些RFC是很有價值的學習資料。

我覺得如果不涉及機密,團隊應該要讓更多人參與到項目的設計和決策中,對於新手可以學到很多東西,而對於發起者也可能有考慮不周的情況。

那對於企業應用開發, Issue有用嗎?

當然有用, 比如我們可以將這類話題從IM轉移到Issue:

  • 設計方案
  • 決策/建議
    • 新功能、新技術引入
    • 重構
    • 性能優化
    • 規範
  • 問題討論
  • 重大事件
  • 計劃或進度跟蹤

另外Issue通常通過標籤來進行分類,方便組織和檢索:

6.5 注釋即文檔

必要和適量的注釋對閱讀源代碼的人來說就是一個路牌, 可以少走很多彎路.

關於注釋的一些準則,<阿里巴巴Java開發手冊>總結得非常好, 推薦基於這個來建立注釋規範。另外通過ESlint是可以對注釋進行一定程度的規範。

6.6 代碼即文檔

現在有很多種工具支持從代碼中解析和生成文檔, 這可以給開發者簡化很多文檔維護的工作。

舉個例子,我們經常會遇到修改了代碼,但是文檔忘記同步的情況。通過『代碼即文檔』的方式至少可以保持文檔和代碼同步更新;另外很多工具會分析代碼的數據類型,自動幫我們生成參數和返回值定義,這也可以減少很多文檔編寫工作以及出錯率。

比如可以通過下面注釋方式來生成組件文檔:

import * as React from 'react';  import { Component } from 'react';    /**   * Props注釋   */  export interface ColumnProps extends React.HTMLAttributes<any> {    /** prop1 description */    prop1?: string;    /** prop2 description */    prop2: number;    /**     * prop3 description     */    prop3: () => void;    /** prop4 description */    prop4: 'option1' | 'option2' | 'option3';  }    /**   * 對組件進行注釋   */  export class Column extends Component<ColumnProps, {}> {    render() {      return <div>Column</div>;    }  }  複製代碼

相關的工具有:

  • API文檔
    • jsdoc Javascript文檔注釋標準和生成器
    • tsdoc Typescript官方的注釋文檔標準
    • typedoc 基於tsdoc標準的文檔生成器
    • Typescript
    • Javascript
  • 後端接口文檔
    • Swagger Restful接口文檔規範
    • GraphQL: 這個有很多工具,例如graphiql, 集成了Playground和文檔,很先進
    • Easy Mock 一個可視化,並且能快速生成模擬數據的服務
  • 組件文檔
    • vue-styleguidist
    • 有更好的工具請評論告訴我
    • Docz
    • Styleguidist
    • StoryBook 通用的組件開發、測試、文檔工具
    • React
    • Vue

7 UI設計規範

這是一個容易被忽略的規範類型。筆者就深受其苦,我們公司初期UI並不專業,沒有所謂的設計規範,這就導致他們設計出來的產品都是東借西湊,前後不統一,多個應用之間的組件不能復用。這搞得我們不得不浪費時間,寫很多定製化樣式和組件,為他們的不專業買單.

關於UI設計規範的重要性有興趣的讀者可以看這篇文章<開發和設計溝通有多難?- 你只差一個設計規範>.

簡單總結一下UI設計規範的意義:

  • 提供團隊協作效率(產品和開發)
  • 提高組件的復用率. 統一的組件規範可以讓組件更好管理
  • 保持產品迭代過程中品牌一致性

建立一個定義良好的設計規範需要UI設計和開發的緊密配合,有時候也可以由我們前端來推動。

比如很多開源的UI框架,一開始都是開發者YY出來的,並沒有設計參與,後來組件庫慢慢沉澱成型,UI設計師才介入規範一下。

如果你們團隊不打算制定自己的UI設計規範,則推薦使用現成的開源組件庫:

  • Ant Design
  • Material-UI
  • Element UI
  • WeUI
  • Microsoft Fabric

這些開源組件庫都經過良好的設計和沉澱, 而且配套了完善的設計原則、最佳實踐和設計資源文件(Sketch 和 Axure),可以幫助業務快速設計出高質量的產品原型。

8 測試規範

測試是保障代碼質量的重要手段,但是很少有人願意在這裡花太多時間。

比如筆者,我很少會去給業務代碼和組件寫單元測試,除非自己對代碼非常沒有信心,按照我的理念寫測試不如將代碼寫得更簡單一點,比如把一個函數拆分為更小的函數,保持單一職責。

但是對於一些底層、共享的代碼模塊還是有測試的必要的。

我在不知道測試什麼?這些是你需要知道的軟件測試類型和常識文章中,列舉了一些開發者需要關注的測試類型和常識, 如果按照測試的階段進行分類,大概是這樣子的:

其中前端開發者需要關注的主要有以下幾種測試類型:

  • 單元測試: 對獨立的軟件模塊進行測試
    • UI組件測試: 包括了快照(Snapshot)測試
  • 集成測試: 在單元測試的基礎上,將模塊組合起來,測試它們的組合性
  • E2E測試: 在完整、真實的運行環境下模擬真實用戶對應用進行測試。主要測試前端和後端的協調性
  • 兼容性測試: 上面提到了瀏覽器兼容規範,在將版本提交給測試/發佈之前,需要確保能符合兼容性要求
  • 性能測試: 測試和分析是否存在性能問題
  • 其他:
    • 安全測試
    • SEO測試

因為對於小公司來說整個軟件開發流程可能沒有那麼規範,比如很難構建一個完整的端對端測試環境,這些都不是前端團隊可以操作的範圍, 所以自動化測試很難推行。但是可以根據團隊和業務情況逐步進行開展。

可實施性比較高的, 也比較簡單是單元測試,所以本文也重點關注單元測試.

8.1 測試的流程

首先要定義一個合適的軟件測試流程, 合適的測試流程可以降低開發和測試團隊之間的溝通協作成本、提高測試效率。例如我們團隊目前的測試流程:

8.2 單元測試

單元測試有很多好處, 比如:

  • 提高信心,適應變化和迭代. 如果現有代碼有較為完善的單元測試,在代碼重構時,可以檢驗模塊是否依然可以工作, 一旦變更導致錯誤,單元測試也可以幫助我們快速定位並修復錯誤
  • 單元測試是集成測試的基礎
  • 測試即文檔。如果文檔不能解決你的問題,在你打算看源碼之前,可以查看單元測試。通過這些測試用例,開發人員可以直觀地理解程序單元的基礎API
  • 提升代碼質量。易於測試的代碼,一般都是好代碼

測什麼?

業務代碼或業務組件是比較難以實施單元測試的,一方面它們比較多變、另一方面很多團隊很少有精力維護這部分單元測試。所以通常只要求對一些基礎/底層的組件、框架或者服務進行測試, 視情況考慮是否要測試業務代碼

測試的準則:

  • 推薦Petroware的Unit Testing Guidelines, 總結了27條單元測試準則,非常受用.
  • 另外<阿里巴巴的Java開發手冊>中總結的單元測試準則, 也不錯,雖然書名是Java,準則是通用的.

單元測試指標:

一般使用測試覆蓋率來量化,儘管對於覆蓋率能不能衡量單元測試的有效性存在較多爭議。

大部分情況下還是推薦儘可能提高覆蓋率, 比如要求語句覆蓋率達到70%;核心模塊的語句覆蓋率和分支覆蓋率都要達到100%. 視團隊情況而定

擴展:

  • 測試覆蓋(率)到底有什麼用?

相關工具

  • Headless Browsers: 無頭瀏覽器是網頁自動化的重要運行環境。常用於功能測試、單元測試、網絡爬蟲
    • puppeteer
    • Headless Chromium
  • 測試框架
    • 組件測試
    • testing-library ?
    • Enzyme
    • Jest ?Facebook的單元測試框架. 零配置, 支持組件快照測試、模塊Mock、Spy. 一般場景, 單元測試學它一個就行了
    • Intern
  • 單元測試
    • AVA
    • Jasmine
    • Mocha
    • Tape
  • 斷言庫
    • Chai
    • expect.js
    • should.js
  • Mock/Stubs/Spies
    • sinon.js
  • 代碼覆蓋率
    • istanbul
  • 基準測試
    • benchmark.js
    • jsperf.com

9 異常處理、監控和調試規範

很多開發者常常誤用或者輕視異常的處理, 合理有效的異常處理可以提高應用的健壯性和可用性,另外還可以幫助開發者快速定位異常.

9.1 異常處理

<阿里巴巴的Java開發手冊>中總結的異常處理規範對JavaScript的異常處理也很有參考意義,比如:

  • 異常不要用來做流程控制,條件控制。
  • 捕獲異常是為了處理它,不要捕獲了卻什麼都不處理而拋棄之,如果不想處理它,請將該異常拋給它的調用者。最外層的業務使用者,必須處理異常,將其轉化為用戶可以理解的內容。
  • catch時請分清穩定代碼和非穩定代碼,穩定代碼指的是無論如何不會出錯的代碼。對於非穩定代碼的catch儘可能進行區分異常類型,再做對應的異常處理。不要對大段代碼進行try-catch

然後再根據JavaScript本身的異常處理特點總結一些規範行為, 例如:

  • 不要throw非Error對象
  • 不要忽略異步異常
  • 全局監控Javascript異常

資源:

  • 從1000+個項目中總結出來的前10個JavaScript錯誤, 以及如何避免它們
  • Javascript異常處理『權威』指南
  • 前端異常處理最佳實踐

9.2 日誌

對於前端來說,日誌也不是毫無意義(很多框架性能優化建議在生產環境移除console)。尤其是在生產現場調試代碼時,這時候可貴的控制台日誌可以幫助你快速找到異常的線索.

不過通常我們只要保留必要的、有意義的日誌輸出,比如你不應該將console.log放到一個React渲染函數中、或者放到一個循環中, DDos式的日誌信息並不能幫助我們定位問題,反而會影響運行的性能. 所以需要一個規範來約束日誌輸出行為, 比如:

  • 避免重複打印日誌
  • 謹慎地記錄日誌, 劃分日誌級別。比如生產環境禁止輸出debug日誌;有選擇地輸出info日誌;
  • 使用前綴對日誌進行分類, 例如: [User] xxxx
  • 只記錄關鍵信息, 這些信息可以幫助你診斷問題

擴展資源

  • debug 適合Node.js和瀏覽器的debug日誌工具, 支持動態開啟日誌打印
  • vConsole 移動端調試利器

9.3 異常監控

因為程序跑在不受控的環境,所以對於客戶端應用來說,異常監控在生產環境是非常重要的,它可以收集各種意料之外生產環境問題,幫助開發者快速定位異常。

異常監控通常會通過三種方式來收集異常數據:

  1. 全局捕獲。例如使用window.onerror, 或者unhandledrejection
  2. 主動上報。在try/catch中主動上報.
  3. 用戶反饋。比如彈窗讓用戶填寫反饋信息.

和日誌一樣,不是所有『異常』都應該上報給異常監控系統,譬如一些預料之內的『異常』,比如用戶輸入錯誤、鑒權失敗、網絡錯誤等等. 異常監控主要用來上報一些意料之外的、或者致命性的異常.

要做好前端的異常監控其實並不容易,它需要處理這些東西:

  • 瀏覽器兼容性。
  • 碎片收集(breadcrumbs)。收集『災難』現場的一些線索,這些線索對問題診斷很重要。例如當前用戶信息、版本、運行環境、打印的日誌、函數調用棧等等
  • 調用棧的轉換。通常在瀏覽器運行的壓縮優化過的代碼,這種調用棧基本沒什麼可讀性,通常需要通過SourceMap映射到原始代碼. 可以使用這個庫: source-map
  • 數據的聚合。後端監控系統需要對前端上報的信息進行分析和聚合

對於小團隊未必有能力開發這一套系統,所以推薦使用一些第三方工具。例如

  • Sentry ?免費基本夠用
  • FunDebug 付費增強

擴展:

  • 前端異常監控解決方案研究
  • 搭建前端監控系統

10 前後端協作規範

前端是Web的一個細分領域,往往不能脫離後端而存在。所以和後端協作的時間是最長的.

10.1 協作流程規範

前後端團隊經過長期的合作,一般可以總結出一條對於雙方開發效率最優的協作流程. 將這個落實為規範,後面的團隊成員都遵循這個步調進行協作。

一個典型的前後端協作流程如下:

  1. 需求分析。參與者一般有前後端、測試、以及產品. 由產品主持,對需求進行宣貫,接受開發和測試的反饋,確保大家對需求有一致的認知
  2. 前後端開發討論。討論應用的一些開發設計,溝通技術點、難點、以及分工問題.
  3. 設計接口文檔。可以由前後端一起設計;或者由後端設計、前端確認是否符合要求
  4. 並行開發。前後端並行開發,在這個階段,前端可以先實現靜態頁面; 或者根據接口文檔對接口進行Mock, 來模擬對接後端接口
  5. 在聯調之前,要求後端做好接口測試
  6. 真實環境聯調。前端將接口請求代理到後端服務,進行真實環境聯調。

10.2 接口規範

首先應該確定下來的是接口規範。其實使用哪種接口標準是其次,重要的是統一,且要滿足前後端的開發效率要求.

筆者不建議後端去定義自己的接口標準,而應該去選擇一些通用的、有標準定義接口形式, 例如:

  • RESTful: RESTful是目前使用最為廣泛的API設計規範, 基於HTTP本身的機制來實現. 筆者個人是比較喜歡這個API規範,但是我發現很多開發者並不能真正(或者說沒心思)理解它,設計出來的接口,跟我想像的相差甚遠。換句話說,對於RESTful,開發者之間很難達成一致的理解,容易產生分歧。 因為是使用最廣泛的API形式,所以社區上有很多工具來對RESTful接口進行文檔化、測試和模擬.
  • JSONRPC 這是一種非常簡單、容易理解的接口規範。相對於RESTful我更推薦這個,簡單則不容易產生分歧,新手也可以很快接受.
  • GraphQL ?更為先進、更有前景的API規範。但是你要說服後端配合你使用這種標準可能很有難度

接口設計需要注意的點:

  • 明確區分是正常還是異常, 嚴格遵循接口的異常原語. 上述接口形式都有明確的異常原語,比如JSONRPC,當出現異常時應該返回錯誤對象響應,而不是在正常的響應體中返回錯誤代碼. 另外要規範化的錯誤碼, HTTP響應碼就是一個不錯的學習對象
  • 明確數據類型。很多後端寫的接口都是string和number不分的,如果妥協的話、前端就需要針對這個屬性做特殊處理,這也可能是潛在的bug
  • 明確空值的意義。比如在做更新操作是,空值是表示重置,還是忽略更新?
  • 響應避免冗餘的嵌套。
  • 接口版本化,保持向下兼容。就像我們上文的『語義化版本規範』說的,對於後端來說,API就是公共的接口. 公共暴露的接口應該有一個版本號,來說明當前描述的接口做了什麼變動,是否向下兼容。現在前端代碼可能會在客戶端被緩存,例如小程序。如果後端做了break change,就會影響這部分用戶。

10.3 接口文檔規範

後端通過接口文檔向前端暴露接口相關的信息。通常需要包含這些信息:

  • 版本號
  • 文檔描述
  • 服務的入口. 例如基本路徑
  • 測試服務器. 可選
  • 簡單使用示例
  • 安全和認證
  • 具體接口定義
    • 方法名稱或者URL
    • 方法描述
    • 請求參數及其描述,必須說明類型(數據類型、是否可選等)
    • 響應參數及其描述, 必須說明類型(數據類型、是否可選等)
    • 可能的異常情況、錯誤代碼、以及描述
    • 請求示例,可選

人工維護導致的問題:

上文『代碼即文檔』就提到了人工維護接口文檔可能導致代碼和文檔不同步問題。

如果可以從代碼或者規範文檔(例如OpenAPI這類API描述規範)中生成接口文檔,可以解決實現和文檔不一致問題, 同時也可以減少文檔編寫和維護的投入.

10.4 接口測試與模擬

為了做到高效率的前後端並行開發,接口的測試與模擬是必要的。

  • 前端要求後端在聯調之前,需要測試驗證好自己的接口是否可以正常工作。而不是在聯調期間,把前端當『接口測試員』,阻塞接口聯調進度
  • 另外前端需要在後端接口未準備好之前,通過接口模擬的方式,來編寫業務邏輯代碼。

針對接口測試與模擬,存在下圖這樣一個理想的模型:

一切從定義良好的接口文檔出發,生成Mock ServerMock Client, Mock Server給前端提供模擬數據,而Mock Client則輔助後端對它們的接口進行測試.

資源:

  • RESTful
    • Swagger 這是最為接近上面理想模型的一個解決方案
    • JSON Server 快速生成JSON mock服務器
    • Easy Mock 可視化的、在線的接口mock服務
  • GraphQl
    • GraphQL Faker
    • graphql-tools
  • 模擬數據生成
    • faker.js ?強大的模擬數據生成工具,支持Node和瀏覽器
    • Mock.js 數據生成和模擬工具

11 培訓/知識管理/技術沉澱

我覺得一個團隊的知識管理是非常重要的. 你要問一個剛入行的新手加入團隊希望得到什麼?很多人的回答是'學習', 希望自己的技術可以更加精進, 錢倒還是其次。

然而現實是目前很多公司的氛圍並不是這樣的,一天到晚寫業務代碼、工作量大、每天做重複的事情,而且還加班,工作多年技術也沒感覺有多少進步, 確實會讓人非常沮喪。包括筆者也是這樣的。

所以為了改善這種情況,我來聊聊最近在『小團隊』做的一些嘗試.

11.1 新人培訓

如果團隊有規範的新成員培訓手冊,可以節省很多培訓的時間,避免每次重複口述一樣的內容。培訓手冊包含以下內容:

產品架構與組織架構. 介紹公司背景和產品,一般組織的團隊結構和產品的架構是相關聯的. 以筆者所在公司為例, 主要產品是即時通信:

產品研發流程: 介紹產品開發和迭代會涉及到的流程、以及團隊之間的協作銜接,例如:

  • 工作範圍: 團隊成員的職責範圍
  • 建立資源索引: 開發需要設計到的資源,比如各種文檔地址、研發系統入口(例如gitlab、bug跟蹤系統、文件共享、發佈平台、開發/測試環境、監控系統)、協作規範等等。將這些資源整理好可以減少不必要的溝通成本
  • 規範: 即本文的主體'前端協作規範'。有規範可循,可以讓成員以較快的速度入手開發、同時也減少培訓成本投入。

培訓手冊將可以文檔具象化的內容整理為文檔,和上文說到的Code Review一樣,一些東西無法通過文檔來說明,所以我們一般會搭配一個『培訓導師』,在試用期間,一對一輔導。

11.2 營造技術氛圍

  • 鼓勵成員寫技術博客,或者建立自己的團隊專欄. 寫一篇好的文章不容易
  • 鼓勵參與開源項目
  • 建立面試題庫 組織一起解一些面試題或算法題,加深對知識點的理解
  • 定期的專題分享. 鼓勵團隊成員定期進行專題學習和研究,編寫技術博客,並將學習的成果分享給其他成員. 這是一種抱團取暖的學習方式,旨在幫助團隊成員一起學習和成長。 比如開發老手可以分享自己的經驗,研究更深層次的技術;新手則可以研究某些開發技巧、新技術,例如CSS Grid,svg動畫等等。推薦團隊成員有個明確的研究領域,這樣分工合作可以學習到更多東西. 專題怎麼來?
    • 專題請求. 可以請求其他成員完成專題,比如比較深的知識,可以要求團隊比較有經驗的進行學習分享
    • 學習總結.
    • 項目回顧
    • 難點攻克
    • 項目規範
    • 工具使用
  • 落實和完善開發規範. 規範本身就是團隊知識沉澱的一種直接輸出
  • 圖書分享. 和離散的文章或教程相比,圖書的知識會比較系統,另外很多經典的圖書是要靜下來好好欣賞的。
  • 鼓勵重構和持續優化代碼
  • 抽象一套基礎庫或框架,減少重複工作, 提高工作效率. 不加班先從提高工作效率開始