比——十年開發(fā)經(jīng)驗(yàn)總結(jié))
做Web開發(fā)十年我經(jīng)手過三套不同的系統(tǒng)架構(gòu)從最早的ASP.NET WebForm拖控件到中途糾結(jié)過要不要全面轉(zhuǎn)向前后端分離最后在一個(gè)混合維護(hù)的老項(xiàng)目里把兩種方案都用到極致。每次有人問我“用VueAPI做前后端分離和以前WebForm那種不分離的方式到底哪個(gè)效率高”我都想先反問一句——你說(shuō)的效率是哪一段的效率寫第一行代碼的速度把一個(gè)系統(tǒng)做完的速度三個(gè)月后加需求的速度還是換人接手之后的上手速度這四者經(jīng)常是撕裂的。很多爭(zhēng)論吵了半天其實(shí)是各說(shuō)各話一個(gè)人在講“我今天就能把頁(yè)面拖出來(lái)”另一個(gè)人在講“我三個(gè)月后改需求要改吐了”。這篇文章我就把兩種方式從開發(fā)、聯(lián)調(diào)、維護(hù)、團(tuán)隊(duì)協(xié)作、業(yè)務(wù)匹配這幾個(gè)維度拆開聊結(jié)合我自己做過的實(shí)際項(xiàng)目說(shuō)清楚哪種場(chǎng)景下選哪種更值以及為什么。1. 先破一個(gè)迷思“效率高”這件事得分三段來(lái)談1.1 開發(fā)期的效率根本不是同一個(gè)效率如果只看“從零開始寫一個(gè)單頁(yè)CRUD”的速度老一代WebForm幾乎是無(wú)敵的。拖一個(gè)GridView配一下數(shù)據(jù)源字段綁定、分頁(yè)、編輯、刪除一套下來(lái)可能就半小時(shí)。換到VueAPI你得先搭工程、配代理、定接口、寫Mock、寫前端表單校驗(yàn)、對(duì)接后端CURD第一次上手沒個(gè)一兩天摸不完整條鏈路。但這個(gè)“快”有強(qiáng)烈的局限性——它快在你有現(xiàn)成控件、現(xiàn)成腳手架、現(xiàn)成操作習(xí)慣的時(shí)候。一旦頁(yè)面開始復(fù)雜比如要做動(dòng)態(tài)表格合并、樹狀聯(lián)動(dòng)、富文本上傳、多級(jí)彈窗嵌套WebForm那套服務(wù)器控件反而成了最大的枷鎖。你要么去找第三方控件庫(kù)付費(fèi)買現(xiàn)成的要么就在Render階段手?jǐn)]HTML拼接字符串那種日子我經(jīng)歷過真的不叫效率叫湊合。1.2 聯(lián)調(diào)期的效率前后端分離的隱性優(yōu)勢(shì)在這里爆發(fā)老項(xiàng)目最痛苦的一個(gè)階段不是開發(fā)是前后端聯(lián)調(diào)。WebForm時(shí)代雖然沒有“聯(lián)調(diào)”這個(gè)說(shuō)法因?yàn)榍昂蠖硕荚谝粋€(gè)工程里但正因?yàn)槎荚谝粋€(gè)工程里你改了前端樣式要重新編譯整個(gè)站點(diǎn)你修了一個(gè)服務(wù)端事件影響的可能是頁(yè)面狀態(tài)、ViewState、回發(fā)路徑。最折磨人的是你想把一個(gè)頁(yè)面拆給另一個(gè)同事做除非把整個(gè)文件復(fù)制一份否則兩個(gè)人的改動(dòng)永遠(yuǎn)在同一個(gè)頁(yè)面文件里打架。VueAPI模式雖然引入了聯(lián)調(diào)成本但這個(gè)成本是“顯性”的而且是可以并行壓平的。后端把接口定義好Mock數(shù)據(jù)一出前端就可以獨(dú)立開發(fā)前端等真實(shí)接口后端也完全不阻塞。兩邊只需要守著Swagger或者接口文檔同步就行。1.3 維護(hù)期的效率可能是最容易被低估的分水嶺做開發(fā)的人常年面對(duì)一個(gè)現(xiàn)實(shí)一個(gè)系統(tǒng)的生命周期里初始編碼的時(shí)間往往是短頭后期維護(hù)、加需求、查Bug才是長(zhǎng)尾。WebForm的ViewState一旦變得臃腫——那種一個(gè)頁(yè)面跟幾百KB的隱藏字段別的公司真見過——線上性能排查能把你逼瘋。頁(yè)面回發(fā)的機(jī)制也導(dǎo)致調(diào)試?yán)щy你無(wú)法直觀地通過Network面板定位到底是事件觸發(fā)的鏈路哪一段出了問題。VueAPI在這方面的效率優(yōu)勢(shì)太明顯了。數(shù)據(jù)流清晰、組件邊界明確、接口和界面完全解耦新增一個(gè)頁(yè)面往往只是增加一套組件和一組API調(diào)用對(duì)既有代碼的影響面極小。模塊之間互相踩腳的概率比起WebForm時(shí)代低得多。2. 兩種架構(gòu)的運(yùn)行機(jī)制決定了它們各自的“快”是怎么來(lái)的2.1 WebForm的“快”建立在封裝的代價(jià)之上WebForm的開發(fā)商模式可以這樣理解微軟幫你把所有HTTP細(xì)節(jié)都包裝成了類似“WinForm的事件驅(qū)動(dòng)模型”你拖一個(gè)Button控件雙擊寫一個(gè)Onclick就能處理提交完全不用管請(qǐng)求是怎么發(fā)出去的、狀態(tài)是怎么保留的。問題也出在這里。為了模擬“無(wú)狀態(tài)HTTP下的有狀態(tài)桌面程序體驗(yàn)”WebForm引入了ViewState、PostBack、生命周期事件鏈等一堆補(bǔ)償機(jī)制。頁(yè)面每次交互都要把整個(gè)表單狀態(tài)序列化到隱藏字段里回傳到服務(wù)器服務(wù)器經(jīng)過Init、Load、PostBack處理、Render再把整個(gè)頁(yè)面重新渲染一次。這套機(jī)制的研發(fā)成本極高但代價(jià)就是性能開銷大、HTML不可控、前端體驗(yàn)笨重。我印象最深的一個(gè)真實(shí)案例是某個(gè)老后臺(tái)系統(tǒng)的一個(gè)復(fù)雜頁(yè)面薪酬錄入界面一個(gè)頁(yè)面四五十個(gè)控件ViewState超大。用戶每次點(diǎn)保存都要等兩三秒那個(gè)菊花轉(zhuǎn)完。后來(lái)檢查一下ViewState序列化后接近1MB而真正需要提交的字段可能連十分之一都不到。這種場(chǎng)景下WebForm的“高效開發(fā)”已經(jīng)被巨大的運(yùn)維和體驗(yàn)債務(wù)給完全吞掉了。2.2 VueAPI的“慢”是在支付架構(gòu)清晰化的前期費(fèi)用VueAPI本質(zhì)上就是把Web的“頁(yè)面展示”和“數(shù)據(jù)邏輯”徹底拆開前端只負(fù)責(zé)拿數(shù)據(jù)渲染界面后端只管暴露數(shù)據(jù)接口。每一次交互都是一次獨(dú)立的HTTP請(qǐng)求前端拿到JSON后自己決定怎么展示。數(shù)據(jù)流來(lái)自哪里、流向哪里、經(jīng)過哪些組件全部可追蹤、可打點(diǎn)、可緩存。這種架構(gòu)的初期成本主要在三個(gè)方面第一工程搭建成本。Vite、Webpack、路由、狀態(tài)管理、代理、環(huán)境變量、代碼規(guī)范一堆配置都要人肉去初始化。第二接口定義成本。設(shè)計(jì)一套穩(wěn)定、語(yǔ)義清晰的API比直接寫服務(wù)端頁(yè)面里的方法調(diào)用要費(fèi)更多腦子。字段怎么命名、狀態(tài)碼怎么設(shè)計(jì)、錯(cuò)誤怎么返回、權(quán)限怎么控制都得提前想清楚。第三聯(lián)調(diào)溝通成本。前端依賴后端接口后端依賴前端反饋這中間的溝通協(xié)調(diào)確實(shí)存在損耗特別是當(dāng)兩邊的技術(shù)負(fù)責(zé)人對(duì)接口文檔不重視的時(shí)候。但注意了這三項(xiàng)成本都只在“第一次搭建”和“需求初期”出現(xiàn)。系統(tǒng)一旦跑起來(lái)架子搭好接口風(fēng)格統(tǒng)一后續(xù)每個(gè)新功能的邊際成本會(huì)迅速下降。Vue做組件復(fù)用API做數(shù)據(jù)復(fù)用寫一個(gè)新頁(yè)面往往就是組裝幾個(gè)新組件、調(diào)幾個(gè)新接口的事。3. 三段式效率對(duì)比開發(fā)、聯(lián)調(diào)、維護(hù)到底誰(shuí)快誰(shuí)慢我自己用同一個(gè)“后臺(tái)用戶管理模塊”做過一個(gè)非正式的對(duì)比測(cè)試分別用WebForm和VueAPI實(shí)現(xiàn)記錄一下不同階段的耗時(shí)差異。結(jié)果很難用一句話說(shuō)清但可以整理成一個(gè)參考表對(duì)比維度WebForm不分離VueAPI分離我實(shí)操中的感受從零實(shí)現(xiàn)簡(jiǎn)單CRUD24小時(shí)610小時(shí)WebForm初期確實(shí)快但有“控件依賴”實(shí)現(xiàn)復(fù)雜交互頁(yè)35天起步12天可控復(fù)雜場(chǎng)景Vue完勝WebForm會(huì)陷入拼HTML泥潭前后端并行開發(fā)極難頁(yè)面文件沖突方便接口約定后可獨(dú)立團(tuán)隊(duì)規(guī)?!?人時(shí)這是決定性的查Bug定位問題靠斷點(diǎn)ViewState過程繁瑣瀏覽器NetworkVue DevTools可精確到組件Vue的錯(cuò)誤定位效率至少翻倍加一個(gè)新頁(yè)面復(fù)制老頁(yè)面改風(fēng)險(xiǎn)高耦合新增組件API調(diào)用邊界清晰WebForm的復(fù)制粘貼模式越復(fù)制越亂性能排查與優(yōu)化被ViewState和回發(fā)機(jī)制拖累請(qǐng)求粒度清晰可針對(duì)性優(yōu)化老系統(tǒng)普遍被性能債拖垮團(tuán)隊(duì)新成員上手概念多生命周期難理解前端看組件后端看接口各管一攤新人上手速度VueAPI更快3.1 單人開發(fā)模式WebForm還有存在的合理性我說(shuō)句公道話如果一個(gè)項(xiàng)目只有一個(gè)人開發(fā)頁(yè)面量幾十個(gè)以內(nèi)邏輯不復(fù)雜不追求什么交互體驗(yàn)部署環(huán)境也固定比如內(nèi)網(wǎng)某個(gè)Windows服務(wù)器那用WebForm確實(shí)能更快出活。工具鏈簡(jiǎn)單CtrlF5就能跑起來(lái)數(shù)據(jù)庫(kù)連接放在配置里不用管跨域發(fā)布就是拷個(gè)文件。這些年我接觸過不少企業(yè)內(nèi)部的小型管理系統(tǒng)排班、耗材登記、會(huì)議室預(yù)約、培訓(xùn)報(bào)名很多都是老程序員用WebForm快速寫出來(lái)的。這類系統(tǒng)的特點(diǎn)就是活不多、界面簡(jiǎn)單、沒有專業(yè)前端參與、不用考慮移動(dòng)端適配。在這些場(chǎng)景下強(qiáng)行上前后端分離反而是一種效率浪費(fèi)——你花兩天搭腳手架的時(shí)間人家整個(gè)頁(yè)面都已經(jīng)能跑起來(lái)了。3.2 團(tuán)隊(duì)協(xié)作模式前后端分離的并行效率優(yōu)勢(shì)明顯一旦開發(fā)人數(shù)超過兩個(gè)情況就完全不同了。不分離架構(gòu)下一個(gè)頁(yè)面文件只能一個(gè)人改兩個(gè)人同時(shí)改就得合并沖突。更麻煩的是前端同事要等后端同事寫完整個(gè)服務(wù)端方法才能有時(shí)間調(diào)頁(yè)面后端同事又可能因?yàn)轫?yè)面調(diào)整被反復(fù)打斷兩邊的工作互相阻塞誰(shuí)都沒法專心做事。這種開發(fā)節(jié)奏表面上每天都有產(chǎn)出實(shí)際的有效輸出打個(gè)五折都不夸張。前后端分離后最常見的協(xié)作方式是先說(shuō)好接口格式后端出Mock數(shù)據(jù)前端開工寫組件后端按優(yōu)先級(jí)逐個(gè)完成真實(shí)接口進(jìn)度上兩邊可以完全脫鉤并行等到真實(shí)接口陸續(xù)好了再把前端拼接起來(lái)就行。我在實(shí)施一個(gè)采購(gòu)管理系統(tǒng)的重構(gòu)項(xiàng)目時(shí)團(tuán)隊(duì)里四個(gè)人兩個(gè)前端兩個(gè)后端用VueAPI的方式跑完了一個(gè)完整模塊。前后端全程只需要在早會(huì)上同步半小時(shí)但一個(gè)星期就把包括審批流程、物料臺(tái)賬、供應(yīng)商管理在內(nèi)的主要功能做出來(lái)了。如果放在老WebForm架構(gòu)里至少要翻一倍時(shí)間。4. 比工具更重要的隱藏變量人、團(tuán)隊(duì)與業(yè)務(wù)形態(tài)4.1 團(tuán)隊(duì)水平參差時(shí)工具適配比“理論最優(yōu)”更關(guān)鍵技術(shù)的選擇永遠(yuǎn)不能脫離人的因素。一個(gè)全是老VB/WebForm技術(shù)棧的團(tuán)隊(duì)你強(qiáng)行引入VueAPI光是學(xué)習(xí)成本和團(tuán)隊(duì)抵觸情緒就能拖垮項(xiàng)目進(jìn)度。反之一個(gè)習(xí)慣了現(xiàn)代前端框架的團(tuán)隊(duì)你讓他們回頭去維護(hù)WebForm的頁(yè)面生命周期他們也會(huì)痛苦不堪。比較現(xiàn)實(shí)的情況是團(tuán)隊(duì)里都是老一代.NET開發(fā)對(duì)前端生態(tài)不熟項(xiàng)目又急那就別折騰老實(shí)的WebForm或Razor頁(yè)面比什么都穩(wěn)妥。團(tuán)隊(duì)里有專職前端或者年輕人主導(dǎo)那就優(yōu)先選VueAPI。長(zhǎng)期來(lái)看這套技術(shù)棧的招聘供給量遠(yuǎn)大于WebForm以后找人接手也容易得多。效率的評(píng)估里有一項(xiàng)隱形的指標(biāo)叫“上手成本”。WebForm的上手成本已經(jīng)被微軟的新技術(shù)路線沖散得差不多了現(xiàn)在一個(gè)新人打開一個(gè)WebForm項(xiàng)目面對(duì)那套事件驅(qū)動(dòng)模型往往比直接看Vue組件更懵。4.2 業(yè)務(wù)形態(tài)的分水嶺表單密集型 vs 交互密集型 vs 內(nèi)容展示型不是所有業(yè)務(wù)都適合前后端分離這是我做過多個(gè)項(xiàng)目后沉淀下來(lái)的判斷。如果是“表單密集型”業(yè)務(wù)——大量的傳統(tǒng)表單CRUD字段多流程固定沒有太多實(shí)時(shí)交互WebForm這類服務(wù)端渲染方案仍然有其價(jià)值。這種業(yè)務(wù)的效率瓶頸不在前端交互而在后端數(shù)據(jù)處理的正確性和速度前端越簡(jiǎn)單越好。如果是“交互密集型”業(yè)務(wù)——比如復(fù)雜的表格行內(nèi)編輯、拖拽排序、多級(jí)聯(lián)動(dòng)選擇、實(shí)時(shí)計(jì)算那就務(wù)必選VueAPI。這種業(yè)務(wù)在老式不分離架構(gòu)下做起來(lái)就是噩夢(mèng)每一個(gè)點(diǎn)擊事件都要整頁(yè)回發(fā)或局部刷新代碼耦合嚴(yán)重邏輯分散在多個(gè)事件方法里改一處崩三處。如果是“內(nèi)容展示型”業(yè)務(wù)——比如門戶網(wǎng)站、文章系統(tǒng)、數(shù)據(jù)大屏這類需求更依賴SEO、首屏速度和頁(yè)面直達(dá)。純前端渲染在SEO上有先天劣勢(shì)但這種項(xiàng)目本身適合引入Nuxt等方案而不是回到WebForm。從最終效果來(lái)看VueAPI依然能通過預(yù)渲染和SSR的配套方案搞定。4.3 別忘了“需求變更頻率”這個(gè)終極變量很多系統(tǒng)做完以后真正的效率殺手是需求變更。一個(gè)做好的功能過兩天產(chǎn)品經(jīng)理說(shuō)要加個(gè)字段、改個(gè)布局、加一條判斷。WebForm改需求有多痛苦經(jīng)歷過的人都懂。前端和后端邏輯混在一個(gè)文件里牽一發(fā)而動(dòng)全身。改動(dòng)一個(gè)展示邏輯可能影響ViewState關(guān)聯(lián)的狀態(tài)可能觸及DataBinding的刷新流程狂加一堆判斷分支最后頁(yè)面越來(lái)越大、越來(lái)越硬。VueAPI有幾個(gè)實(shí)實(shí)在在的應(yīng)對(duì)手段前端組件化改動(dòng)局部樣式幾乎不影響其它組件接口獨(dú)立后端接口新增字段不會(huì)破壞前端舊邏輯前端構(gòu)建和熱更新讓改效果所見即所得。這套打法在需求像韭菜一樣一茬一茬長(zhǎng)出來(lái)的業(yè)務(wù)里是效率的放大器。5. 算一筆總賬什么情況下選VueAPI什么情況下選不分離我把自己這些年做過的項(xiàng)目按“業(yè)務(wù)復(fù)雜度”和“團(tuán)隊(duì)情況”兩個(gè)維度做了一個(gè)選型判斷這里分享給大家參考。更傾向于選WebForm/不分離方式的情況團(tuán)隊(duì)用微軟技術(shù)棧多年短時(shí)間內(nèi)無(wú)法補(bǔ)前端缺口項(xiàng)目單人維護(hù)功能簡(jiǎn)單以表格表單為主部署在老舊內(nèi)網(wǎng)服務(wù)器對(duì)前端體驗(yàn)不敏感系統(tǒng)生命周期已接近尾聲只需要做小修小補(bǔ)更傾向于選VueAPI的情況團(tuán)隊(duì)有專職前端或者可以接受前后端崗位分工業(yè)務(wù)存在大量交互邏輯、動(dòng)態(tài)展示和數(shù)據(jù)聯(lián)動(dòng)系統(tǒng)有長(zhǎng)期演進(jìn)計(jì)劃后續(xù)會(huì)不斷加模塊、改流程項(xiàng)目要考慮移動(dòng)端或多端復(fù)用比如同一套API要服務(wù)PC后臺(tái)和手機(jī)H5可以嘗試的折中路線不要在“徹底不分離”和“徹底前后端分離”之間走極端。在實(shí)際項(xiàng)目里我做得最多的是混合架構(gòu)——老模塊保持服務(wù)端渲染不動(dòng)新模塊用Vue掛載到頁(yè)面局部。一個(gè)頁(yè)面里用Vue Forms或Element UI做復(fù)雜表格服務(wù)端只提供一個(gè)API接口繞開WebForm那套生命周期。這種漸進(jìn)式改造效率上很可觀風(fēng)險(xiǎn)也低。我在做某個(gè)物流訂單后臺(tái)的升級(jí)時(shí)就把訂單列表和詳情頁(yè)改成了VueAPI而原本的車輛管理、司機(jī)管理模塊繼續(xù)保持舊的多頁(yè)回發(fā)模式。改造后的訂單處理模塊操作員處理一單的效率提升了近三倍而其它模塊的開發(fā)維護(hù)成本一點(diǎn)沒增加。這期間我做的最重要的決策是不要指望一口氣把所有系統(tǒng)推翻重來(lái)。5.1 關(guān)于“效率”的另一種計(jì)量運(yùn)維與部署很多人對(duì)比這兩種架構(gòu)時(shí)會(huì)把運(yùn)維和部署成本忽略掉。實(shí)際上這一塊也會(huì)顯著影響長(zhǎng)期效率。WebForm部署簡(jiǎn)單一次性發(fā)布整個(gè)站點(diǎn)IIS虛擬目錄一配就完事。但每次發(fā)布都要把整個(gè)站點(diǎn)停下來(lái)哪怕你只改了前端一個(gè)腳本也得重啟整個(gè)應(yīng)用弄得運(yùn)維時(shí)間永遠(yuǎn)卡在風(fēng)控窗口期。VueAPI的部署則天然支持前后端分離獨(dú)立發(fā)布。前端是純靜態(tài)資源可以走CDN發(fā)布靜態(tài)文件不用重啟后端進(jìn)程后端是多組獨(dú)立API服務(wù)更新了某一個(gè)服務(wù)也不會(huì)影響其它服務(wù)。而且前端資源可以強(qiáng)制按版本緩存回滾起來(lái)也比整站發(fā)布從容得多。5.2 關(guān)于“效率”的更深一層計(jì)量面試與招聘市場(chǎng)不提招聘市場(chǎng)是耍流氓——因?yàn)槟阏胁坏饺诵示褪橇?。在今天的就業(yè)市場(chǎng)上WebForm相關(guān)的崗位需求逐年萎縮會(huì)那套老技術(shù)的更多是存量開發(fā)者。而Vue前后端分離幾乎是新項(xiàng)目標(biāo)配人才供給量、學(xué)習(xí)資料、社區(qū)活躍度、招聘薪資預(yù)期全部成熟。從“項(xiàng)目能不能持續(xù)找到人維護(hù)”的角度看VueAPI的長(zhǎng)期穩(wěn)定性和可持續(xù)發(fā)展遠(yuǎn)比WebForm更具保障。我跟一些做技術(shù)管理的朋友聊過他們最怕的不是項(xiàng)目復(fù)雜而是項(xiàng)目里全是那些網(wǎng)上找不到參考資料、社區(qū)已經(jīng)涼透的技術(shù)棧。WebForm正逐漸走進(jìn)那個(gè)區(qū)域。6. 我的真實(shí)結(jié)論和決策經(jīng)驗(yàn)如果單純回答標(biāo)題里的問題——“哪種方式效率更高”我的答案是在2024年及以后的大多數(shù)新項(xiàng)目場(chǎng)景里VueAPI的前后端分離模式總體效率是顯著更高的。但有一條前提你的團(tuán)隊(duì)結(jié)構(gòu)、人員技能、業(yè)務(wù)形態(tài)要匹配。否則即便架構(gòu)再先進(jìn)落地不好也是空轉(zhuǎn)。這種“效率”不是體現(xiàn)在第一行代碼的編寫速度上而是體現(xiàn)在整個(gè)系統(tǒng)生命周期的總擁有成本上。越復(fù)雜的系統(tǒng)、越長(zhǎng)的維護(hù)周期、越大的團(tuán)隊(duì)規(guī)模VueAPI的優(yōu)勢(shì)越明顯。最后分享一個(gè)我用了很多年的決策思路遇到選型糾結(jié)時(shí)拿出來(lái)用一下你先問自己做這個(gè)系統(tǒng)你是在“做完就行”還是在“持續(xù)演進(jìn)”前者怎么順手怎么來(lái)WebForm也好、VueAPI也好能交付就贏了。后者你必須選一個(gè)能陪你走很遠(yuǎn)的架構(gòu)——數(shù)據(jù)流清晰、組件可復(fù)用、接口穩(wěn)定、團(tuán)隊(duì)可擴(kuò)展。VueAPI在這套標(biāo)準(zhǔn)下的得分幾乎是全面領(lǐng)先的。技術(shù)在迭代舊的方式并不等于錯(cuò)的方式但如果你在做新項(xiàng)目手里又一個(gè)懂前端的隊(duì)友我真找不到任何理由再回到WebForm那套重回發(fā)的模式里去了。