大型專案前端架構淺談
update:2019.06.17更新2.4文章連結
目錄:
- 1、綜合
- 1.1、使用場景
- 1.2、核心思想
- 1.3、切入角度
- 1.4、其他
- 2、基礎層設計
- 2.1、自建Gitlab
- 2.2、版本管理
- 2.3、自動編譯釋出Jenkins
- 2.4、純前端版本釋出
- 2.5、統一腳手架
- 2.6、Node中間層
- 2.7、埋點系統
- 2.8、監控和報警系統
- 2.9、安全管理
- 2.10、Eslint
- 2.11、灰度釋出
- 2.12、前後端分離
- 2.13、Mock
- 2.14、定期備份
- 3、應用層設計
- 3.1、多頁和單頁
- 3.2、以應用為單位劃分前端專案
- 3.3、基礎元件庫的建設
- 3.4、技術棧統一
- 3.5、瀏覽器相容
- 3.6、內容平_臺建設
- 3.7、許可權管理平_臺
- 3.8、登入系統設計(單點登入)
- 3.9、CDN
- 3.10、負載均衡
- 3.11、多端共用一套介面
- 4、總結
1、綜合
我在2年之前,寫過一篇中小型專案的前端架構淺談。隨著能力的上升,以及在阿里巴巴工作的經驗,是時候寫一篇大型專案的前端架構分析了。
本篇文章不會更多側重於具體技術實現,而是嘗試從更高角度出發,分析為什麼要這麼做,這些設計能解決什麼問題,成本和收益如何。
由於作者能力有限,可能會有所缺漏或者部分錯誤,歡迎讀者指出。
1.1、適用場景:
本篇文章,適用於單個/多個大型專案、擁有超過10個以上的前端開發的場景。
前端專案的規模不同,成本收益比也會有所差別。通常來說,人員越多、專案複雜度越高,那麼收益/成本的比值越大。
對於人數較少、專案簡單的開發團隊,可能有部分措施不適用,因此應該根據具體情況來選用。
1.2、核心思想:
【1】解決問題:前端架構的設計,應是用於解決已存在或者未來可能發生的技術問題,增加專案的可管理性、穩定性、可擴充套件性。
【2】人效比:對於需要額外開發工作量的事務(本文中存在一些需要一定開發量的內容),我們在決定是否去做的時候,應該考慮到兩個要素:第一個是花費的人力成本,第二個是未來可能節約的時間和金錢、避免的專案風險與資損、提高對業務的支撐能力以帶來在業務上可衡量的更高的價值、以及其他價值。
【3】定性和定量:架構裡設計的內容,一定要有是可衡量的意義的,最好是可以定量的——即可以衡量帶來的收益或減少的成本,至少是可以定性的——即雖然無法用數字闡述收益,但我們可以明確這個是有意義的,例如增加安全性降低風險。
【4】資料敏感:專門寫這一條強調資料作為依據的重要性。當我們需要說服其他部門/上級管理者,以推動我們設計的內容時,只有資料——特別是跟錢有關的資料,才是最有說服力的證明。
由於篇幅所限,本文很難直接給出定量的值,因此建議架構設計者,先確保專案中設計使用2.7裡的埋點系統,根據埋點系統獲取的資料,對專案效果進行定量分析,並以此寫成PPT和其他部門/上級管理者進行協調。
1.3、切入角度:
分為基礎層和應用層。
基礎層偏基礎設施建設,與業務相關性較低。
應用層更貼近使用者,用於解決某一個問題。
部分兩個都沾邊的,根據經驗劃分到其中一個。
1.4、其他
由於已經談到架構層級,因此很多內容,並不僅僅只屬於前端領域,有很多內容是複合領域(前端、後端、運維、測試),因此需要負責架構的人,技術棧足夠全面,對未來發展有足夠的前瞻性。
文章的內容結構為:【專案】—>【解決的問題和帶來的好處】—>【專案的實際意義】
2、基礎層設計
2.1、自建Gitlab
這個是基礎的基礎了。本不應該提的,不過考慮到我最近面試的幾家公司,有的公司(人數並不少)並沒有使用Gitlab,因此專門提一下,並且使用這個的難度非常低。
強烈建議使用Gitlab進行版本管理,自建Gitlab難度並不大,方便管理,包括程式碼管理、許可權管理、提交日誌查詢,以及聯動一些第三方外掛。
意義:
公司程式碼是公司的重要資產,使用自建Gitlab可以有效保護公司資產。
2.2、版本管理
版本管理的幾個關鍵點:
- 釋出後分支鎖死,不可再更改:指當例如0.0.1版本成功釋出後,不可再更改0.0.1分支上的程式碼,否則可能會導致版本管理混亂。
- 全自動流程釋出;指應避免開發者提交後,手動編譯打包等操作,換句話說,開發人員釋出後,將自動釋出到預釋出/生產環境。開發人員不和相關環境直接接觸。實現這個需要參考下面的2.3。
- 多版本並存;指當例如釋出0.0.2版本後,0.0.1版本的程式碼應仍儲存在線上(例如CDN),這樣當出現線上bug時,方便快速回滾到上一個版本。
意義:
提高專案的可控性。
2.3、自動編譯釋出Jenkins
這個工具用於在程式碼釋出後,執行一系列流程,例如自動編譯打包合併,然後再從Gitlab釋出到CDN或者靜態資源伺服器。
使用這個工具,可以讓一般研發人員不關心程式碼傳到Gitlab後會發生什麼事情,只需要專心於開發就可以了。
意義:
讓研發人員專心於研發,和環境、運維等事情脫鉤。
2.4、純前端版本釋出
純前端版本釋出分為兩步:
- 前端釋出到生產環境——此時可以通過外網連結加正確的版本號訪問到新版本的程式碼,但頁面上的資源還是舊版本;
- 前端通過配置工具(或者是直接更新html檔案),將html中引入的資源,改為新版本。
解決的問題是:當前端需要釋出新版本時,可以不依賴於後端(根據實際情況,也可以不依賴於運維)。畢竟有很多需求並不需要後端介入,單純改個前端版本後就要後端釋出一次,顯然是一件非常麻煩的事情。
這個需要專門的工具,用於配置版本釋出,我最近就在寫這個。
意義:
提高發布效率,降低釋出帶來的人員時間損耗(這些都是錢),也可以在前端版本回滾的時候,速度更快。
文章連結:
2.5、統一腳手架
適用場景:有比較多獨立中小專案。好處:
- 可以減少開發人員配置腳手架帶來的時間損耗(特殊功能可以fork腳手架後再自行定製);
- 統一專案結構,方便管理,也降低專案交接時帶來的需要熟悉專案的時間;
- 方便統一技術棧,可以預先引入固定的元件庫;
意義:
提高開發人員在多個專案之間的快速切換能力,提高專案可維護性,統一公司技術棧,避免因為環境不同導致奇怪的問題。
2.6、Node中間層
適用場景:需要SEO且前端使用React、vue,或前端介入後端邏輯,直接讀取後端服務或者資料庫的情況。
- SEO:仁者見仁智者見智,雖然很多公司已經不做了,但通常認為,還是有一定意義的(特別是需要搜尋引擎引流的時候),因此React或者Vue的同構是必須的。並且同構還可以降低首頁白屏時間;
- 前端讀取後端服務/資料庫:好處是提高前端的開發效率和對業務的支援能力,缺點是可能導致P0級故障。
意義:
讓前端可以侵入後端領域,質的提升對業務的支援能力。
2.7、埋點系統
強烈推薦前端做自己的埋點系統。這個不同於後端的日誌系統。
前端埋點系統的好處:
- 記錄每個頁面的訪問量(日周月年的UV、PV);
- 記錄每個功能的使用量;
- 捕捉報錯情況;
- 圖表化顯示,方便給其他部門展示;
埋點系統是前端高度介入業務,把握業務發展情況的一把利劍,通過這個系統,我們可以比後端更深刻的把握使用者的習慣,以及給產品經理、運營等人員提供準確的資料依據。當有了資料後,前端人員就可以針對性的優化功能、佈局、頁面互動邏輯、使用者使用流程。
埋點系統應和業務解耦,開發人員使用時註冊,然後在專案中引入。然後在埋點系統裡檢視相關資料(例如以小時、日、周、月、年為週期檢視)[原創水印-作者:零零水(王冬),微信:qq20004604]。
意義:
資料是money,資料是公司的生命線,資料是最好的武器。
2.8、監控和報警系統
監控和報警系統應基於埋點系統而建立,在如以下場景時[原創水印-作者:零零水(王冬),微信:qq20004604]觸發:
- 當訪問量有比較大的變化(比如日PV/UV只有之前20%以下)時,自動觸發報警,傳送郵件到相關人員郵箱;
- 比如報錯量大幅度上升(比如200%或更高),則觸發報警;
- 當一段時間內沒有任何訪問量(不符合之前的情況),則觸發報警;
- 每過一段時間,自動彙總訪問者/報錯觸發者的相關資訊(例如系統、瀏覽器版本等);
建設這個系統的好處在於,提前發現一些不容易發現的bug(需要埋點做的比較紮實)。有一些線上bug,因為使用者環境特殊,導致無法被開發人員和測試人員發現。但其中一部分bug又因為不涉及資金,並不會導致資損(因此也不會被後端的監控系統所發現),這樣的bug非常容易影響專案裡某個鏈路的正常使用。
意義:
提高專案的穩定性,提高對業務的把控能力。降低bug數,降低資損的可能性,提前發現某些功能的bug(在工單到來之前)。
2.9、安全管理
前端的安全管理,通常要依賴於後端,至於只跟單純有關係的例如dom.innerHTML= 'xxx '這種太基礎,就不提了。
安全管理的很難從架構設計上完全避免,但還是有一定解決方案的,常見安全問題如下:
- XSS注入:對使用者輸入的內容,需要轉碼(大部分時候要server端來處理,偶爾也需要前端處理),禁止使用eval函式;
- https:這個顯然是必須的,好處非常多;
- CSRF:要求server端加入CSRF的處理方法(至少在關鍵頁面加入);
意義:
減少安全漏洞,避免使用者受到損失,避免遭遇惡意攻擊,增加系統的穩定性和安全性。
2.10、Eslint
Eslint的好處很多,強烈推薦使用:
- 降低低階bug(例如拼寫問題)出現的概率;
- 增加程式碼的可維護性,可閱讀性;
- 硬性統一程式碼風格,團隊協作起來時更輕鬆;
總的來說,eslint推薦直接配置到腳手架之中,對我們提高程式碼的可維護性的幫助會很大。可以考慮在上傳到gitlab時,硬性要求eslint校驗,通過的才允許上傳。
意義:
提高程式碼的可維護性,降低團隊協作的成本。
2.11、灰度釋出
灰度釋出是大型專案在釋出時的常見方法,指在釋出版本時,初始情況下,只允許小比例(比如1~5%比例的使用者使用),若出現問題時,可以快速回滾使用老版本,適用於主鏈路和訪問量極大的頁面。
好處有以下幾點:
- 生產環境比開發環境複雜,灰度釋出時可以在生產環境小範圍嘗試觀察新版本是否可以正常執行,即使出問題,也可以控制損失。
- 對於大版本更新,可以先灰度一部分,觀察埋點效果和使用者反饋(即所謂的搶先試用版)。假如效果並不好,那麼回滾到老版本也可以及時止損;
- 當我們需要驗證某些想法或問題的時候,可以先灰度一部分,快速驗證效果如何,然後查漏補缺或者針對性優化;
灰度釋出通常分為多個階段:【1】1%;【2】5~10%;【3】30~50%;【4】全量推送(100%)。灰度釋出一定要允許配置某些IP/賬號訪問時,可以直接訪問到灰度版本。
意義:
降低風險,提高發布靈活度。
2.12、前後端分離
這個並不是指常見的前後端分離,而是指在分配前後端管控的領域。
中小專案常見的情況是後端只提供介面和讓某個url指向某個html,前端負責html、css、js等靜態資源。
但大型專案並不建議這麼做,建議前端負責除html以外的靜態資源,而html交給後端處理,理由有很多:
- 後端進行渲染,方便統一插入一些程式碼和資源,例如埋點js,監控js,國際化文字資源,頁面識別符號等。這些通常是後端通過呼叫某些服務直接寫入的;
- 當頁面需要統一的頭尾時(參考淘寶裡我的淘寶頁面),前端不應該關注這些跟當前頁面無關的東西;
- 某些東西,如果通過html來管理,那麼耦合度太高了,違背瞭解耦和分離的原則;
- 前端版本釋出在後端引入某種功能模組後,可以從單獨的頁面控制前端釋出內容,比更新html更方便,也利於灰度釋出;
意義:
更規範的進行頁面管理,降低頁面和功能的耦合度,減少複雜頁面的環境配置時間。
2.13、Mock
Mock也是常見前端系統之一,用於解決在後端介面未好時,生成返回的資料。
我個人不太建議開發一個專門的系統來Mock,更好的Mock手法是直接嵌入到腳手架之中。思路如下:
- 當在開發環境下,訪問連結通常是localhost:8000/index.html,此時加入字尾 ?debug=true;
- 封裝好的非同步請求在發現當前連結有以上標誌時,認為是測試環境,訪問/userinfo 時,不去讀取線上的資料(因為也讀取不到),去本地環境讀取 src/test_ajax/userinfo.json,並將內容返回給使用者;
- 非同步請求正常拿到資料,在頁面中顯示[原創水印-作者:零零水(王冬),微信:qq20004604];
- 當線上介面可以獲取到資料後,從network裡找到返回的資料,放入/ src/test_ajax/userinfo.json中,此時再次本地除錯的話,相當於使用的是線上的真實資料。
這種處理,可以降低mock的複雜度,隨時更改mock時返回的資料,比單獨開發一個mock系統性價比更高。
意義:
在前後端並行開發時,降低溝通交流成本,方便開發完畢後直接對接。
2.14、定期備份
備份是常被忽略的一件事情,但當我們遇見毀滅性場景時,缺少備份帶來的損失是非常大的,常見場景:
- 伺服器損壞,導致存在該伺服器上的內容全部完蛋;
- 觸發某致命bug或者錯誤操作(例如rm -f),導致檔案和資料全部消失;
- 資料庫出現錯誤操作或出現問題,導致使用者資料、公司資產遭受嚴重損失;
總的來說,沒人想遇見這樣的場景,但我們必須考慮這種極端情況的發生,因此需要從架構層面解決這個問題。常見方法是定期備份、多機備份、容災系統建設等。
意義:
避免在遭遇極端場景時,給公司帶來不可估量的損失。
3、應用層設計
3.1、多頁和單頁
除了特殊場景,通常推薦使用多頁架構。理由如下:
- 多頁專案,頁面和頁面之間是獨立的,不存在互動,因此當一個頁面需要單獨重構時,不會影響其他頁面,對於有長期歷史的專案來說,可維護性、可重構性要高很多;
- 多頁專案的缺點是不同頁面切換時,會有一個白屏時間,但通常來說,這個時間並不長,大部分現有大公司的線上網頁,都是這樣的,因此認為是可以接受的;
- 多頁專案可以單次只更新一個頁面的版本,而單頁專案如果其中一個功能模組要更新(特別是公共元件更新),很容易讓所有頁面都需要更新版本;
- 多頁專案的版本控制更簡單,如果需要頁面拆分,調整部分頁面的使用流程,難度也會更低;
- 灰度釋出更友好;
之前面試的一家,採用了單頁的形式,之前因為種種原因,同時採用了ng和react。由於專案歷史也比較久(3年以上),結果導致目前繼續維護更新的難度很大,即使想部分重構,也很麻煩。
意義:
降低長期專案迭代維護的難度,
3.2、以應用為單位劃分前端專案
在專案比較大的時候,將所有頁面的前端檔案放入到同一個程式碼倉庫裡,我之前參與過一家企業的前端專案開發,發現其就是這麼做的。根據使用經驗來看[原創水印-作者:零零水(王冬),微信:qq20004604],存在很多問題:
- 會極大的增加程式碼的維護難度;
- 專案會變得很醜陋;
- 不方便許可權管理,容易造成頁面誤更改或程式碼洩密;
- 任何人都有權利改任何他能看到的頁面(在合併程式碼的時候,管理人員並不能確定他本次修改的頁面是否是需求裡他應該改的頁面);
- 釋出成本高,即使改一個頁面,也需要釋出所有資源;
因此,我們應該避免這種現象的發生,個人推薦以應用為單位進行開發、釋出。所謂應用即指一個業務涉及到的前後端程式碼,好處很多:
- 方便進行管理,當某個業務有需求變更時,可以只給研發人員該業務前端應用的developer許可權;
- 在需要釋出某業務時,只需要釋出該業務的所屬應用即可;
意義:
規範專案,增加程式碼的安全性,降低專案維護成本。
3.3、基礎元件庫的建設
這個蠻基礎的,對於元件庫的建設,不建議研發人員較少時去做這件事情,專職前端開發人數少於10人時,建議使用比較靠譜的第三方UI庫,例如Antd,這樣價效比更高。
設計基礎元件庫的前提,是要求統一技術棧,這樣才能最大化基礎元件庫的效益。元件庫建議以使用以下參考標準:
- 使用ts;
- 可擴充套件性強;
- 適用程度高;
- 文件清楚詳細;
- 版本隔離,小版本優化加功能,大改需要大版本更新;
- 和UI協調統一,要求UI互動參與進來;
總的來說,建設起來後,利大於弊,但是需要專人維護,因此還是有一定成本的。
意義:
統一不同/相同產品線之間的風格,給使用者更好的體驗,減少單次開發中寫UI元件時浪費的時間和人力,提高開發效率。
3.4、技術棧統一
前端有三大主流框架,還有相容性最強jQuery,以及各種第三方庫,UI框架。因此專案需求如果複雜一些,很容易形成一個大雜燴。因此前端的技術棧必須統一,具體來說,建議實現以下舉措:
- 三大框架選型其一,團隊水平一般推薦Vue、水平較好推薦React,對外專案選React或者ng;
- 需要相容IE8或更老版本時,建議使用jQuery;
- 元件庫自建或者統一選擇一個固定的第三方;
- 一些特殊第三方庫統一使用一個版本,例如需要使用地圖時,固定使用高德或百度或騰訊地圖;
- 基礎設施建設應避免重複造輪子,所有團隊儘量共用,並有專門的前端平_臺負責統一這些東西,對於特殊需求,可以新建,但應當有說服力;
總的來說,技術棧統一的好處很多,可以有效提高開發效率,降低重複造輪子產生的成本。
意義:
方便招人,簡化團隊成員培養成本,以及提高專案的可持續性。
3.5、瀏覽器相容
常見的問題是IE6、7、8,以及部分小眾瀏覽器(PC和手機)產生的奇怪問題。因此應該考慮統一解決方案,避免bug的重複產生。常見解決方案有:
- 配置postcss,讓某些css增加相容性字首;
- 寫一個wepback的loader,處理某些特殊場景;
- 規範團隊程式碼,使用更穩定的寫法(例如移動端避免使用fixed進行佈局);
- 對常見問題、疑難問題,總結解決方案並團隊共享;
- 建議或引導使用者使用高版本瀏覽器(比如chrome);
意義:
避免瀏覽器環境產生的bug,以及排查此類bug所浪費的大量時間。
3.6、內容平_臺建設
為了提高公司內部的溝通效率,總結經驗,以及保密原因。應建設一個內部論壇+部落格站點。其具備的好處如下:
- 可以記錄公司的歷史;
- 研發同學之間分享經驗;
- 總結轉載一些外界比較精品的文章,提高大家的眼界;
- 增加公司內部同學的交流,有利於公司的團隊和文化建設;
- 對某些技術問題可以進行討論,減少因沒有達成共識帶來的溝通損耗;
眾所周知,大型網際網路公司通常都有這樣一個內部論壇和部落格站點。其降低了公司的溝通和交流成本,也增加了公司的技術積累。
意義:
部落格增強技術積累,論壇增強公司內部溝通能力。
3.7、許可權管理平_臺
當公司內部人員較多時,應有一個專門的平_臺,來管理、規範使用者的許可權以及可訪問內容[原創水印-作者:零零水(王冬),微信:qq20004604]。許可權管理平_臺有幾個特點:
- 必然和Server端天然高耦合度,因此需要有專門的控制模組負責處理許可權問題(負責Server端開發處理,或者前端通過中間層例如Node層介入處理);
- 自動化流程控制,即使用者建立、申請、審批、離職自動刪除,都應該是由系統推進並提醒相關人士,必要時應能觸發報警;
- 許可權應有時效性,減少永久性許可權的產生;
- 審批流程應清晰可見,每一階段流程應具體明確;
- 應與公司流程緊密結合,並且提高可修改性,方便公司後期進行流程優化;
意義:
使得公司內部流程正規化、資訊化。
3.8、登入系統設計(單點登入)
當公司內部業務線比較複雜但相互之間的耦合度比較高時,我們應該考慮設計新增單點登入系統。具體來說,使用者在一處登入,即可以在任何頁面訪問,登出時,也同樣在任何頁面都失去登入狀態。SSO的好處很多:
- 增強使用者體驗;
- 打通了不同業務系統之間的使用者資料;
- 方便統一管理使用者;
- 有利於引流;
- 降低開發系統的成本(不需要每個業務都開發一次登入系統和使用者狀態控制);
總的來說,大中型web應用,SSO可以帶來很多好處,缺點卻很少。
意義:
使用者體驗增強,打通不同業務之間的間隔,降低開發成本和使用者管理成本。
3.9、CDN
前端資源的載入速度是衡量使用者體驗的重要指標之一。而現實中,因為種種因素,使用者在載入頁面資源時,會受到很多限制。因此上CDN是非常有意義的,好處如下:
- 使用者來自不同地區,加入CDN可以使使用者訪問資源時,訪問離自己比較近的CDN伺服器,降低訪問延遲;
- 降低伺服器頻寬使用成本;
- 支援視訊、靜態資源、大檔案、小檔案、直播等多種業務場景;
- 消除跨運營商造成的網路速度較慢的問題;
- 降低DDOS攻擊造成的對網站的影響;
CDN是一種比較成熟的技術,各大雲平_臺都有提供CDN服務,價格也不貴,因此CDN的價效比很高。
意義:
增加使用者訪問速度,降低網路延遲,頻寬優化,減少伺服器負載,增強對攻擊的抵抗能力。
3.10、負載均衡
目前來看,負載均衡通常使用Nginx比較多,以前也有使用Apache。當遇見大型專案的時候,負載均衡和分散式幾乎是必須的。負載均衡有以下好處:
- 降低單臺server的壓力,提高業務承載能力;
- 方便應對峰值流量,擴容方便(如舉辦某些活動時);
- 增強業務的可用性、擴充套件性、穩定性;
負載均衡已經是蠻常見的技術了,好處不用多說,很容易理解。
意義:
增強業務的可用性、擴充套件性、穩定性,可以支援更多使用者的訪問。
3.11、多端共用一套介面
目前常見場景是一個業務,同時有PC頁面和H5頁面,由於業務是一樣的,因此應避免同一個業務有多套介面分別適用於PC和H5端。[原創の水印-作者:零零水(王冬),QQ:20004604]因此解決方案如下:
- 後端提供的介面,應該同時包含PC和H5的資料(即單獨對一個存在亢餘數據);
- 介面應當穩定,即當業務變更時,應儘量採取追加資料的形式;
- 只有在單獨一端需要特殊業務流程時,設計單端獨有介面;
多端共用介面,是減少開發工作量,並且提高業務可維護性的重要解決方案。
意義:
降低開發工作量,增強可維護性。
4、總結
由於各個公司具體情況不同,專案也具有特殊性,因此以上設計不可強行套入,應根據自己公司規模、專案進展、人員數量等,先新增比較重要的功能和設計。並需要考慮到長期專案的可維護性和發展需要,對部分基礎設施進行