預(yù)測2024年之后的前端開發(fā)模式
大家好,我卡頌。
最近AIGC?(AI Generated Content,利用AI?生成內(nèi)容)非常熱,技術(shù)圈也受到了很大沖擊。目前來看,利用LLM?(Large Language Model,大語言模型)輔助開發(fā)還停留在非常早期的階段,主要應(yīng)用是「輔助編碼」,即「用自然語言輸入需求,模型輸出代碼」。更近一步的探索也僅僅是在此基礎(chǔ)上的一層封裝(比如copilot X?、cursor)。
但即使在如此早期階段,也對開發(fā)者的心智產(chǎn)生極大震撼,「AI讓程序員失業(yè)」這樣的論調(diào)甚囂塵上。
LLM的爆發(fā)對前端意味著什么?本文嘗試預(yù)測一波2024年之后的前端開發(fā)模式,這個預(yù)測遵循如下原則:
- 尊重技術(shù)客觀發(fā)展規(guī)律。以當(dāng)前已有技術(shù)為基礎(chǔ)預(yù)測,而不是將預(yù)測建立在某種虛無縹緲的高端技術(shù),或者假想某些技術(shù)突破重大瓶頸。
- 尊重人性。程序員只是謀生的職業(yè),新的開發(fā)模式即使再厲害,如果讓程序員賺不到錢,那也是很難推廣開的。
范式遷移的本質(zhì)
為了預(yù)測未來,先看看我們是如何走到現(xiàn)在的。
在前端開發(fā)領(lǐng)域,我們經(jīng)歷了從jQuery為代表的「面向過程編程」向前端框架為代表的「狀態(tài)驅(qū)動」模式的遷移。
當(dāng)問到「該選Vue還是React開發(fā)?」,這樣的問題會引起很大爭議,但如果問到「該選jQuery還是框架開發(fā)?」,這樣的問題就不會有太多爭議。
為什么前端領(lǐng)域普遍接受了這種范式的遷移?在我看來,有兩個原因:
1、開發(fā)效率提高
這一點毋需多言,相信前端同學(xué)都有體會。
2、門檻提高
?「面向過程編程」是非常淺顯易懂的開發(fā)模式。君不見,曾經(jīng)的前端靠一本「鋒利的jQuery」就能打天下。相比之下,「狀態(tài)驅(qū)動」就有一定學(xué)習(xí)門檻。
當(dāng)一項有一定門檻的技術(shù)(這里指前端框架)變?yōu)樾袠I(yè)事實上的標(biāo)準(zhǔn)時,行業(yè)門檻就提升了,這為從業(yè)者構(gòu)筑了行業(yè)壁壘。
事實上,正是由于:
- web應(yīng)用復(fù)雜度提高
- 前端框架的流行
才讓后端工程師工作職責(zé)中的view層,分化出前端工程師這一職業(yè)。
對于前端領(lǐng)域來說,只有同時平衡了「提效」與「提高門檻」的技術(shù),才會被市場(這里的消費者指前端工程師)接受。
舉個反例,Angular全家桶的模式雖然提高了開發(fā)效率,但是同時,門檻提高太多了。
而且更糟的是,Angular?中的很多概念都是從「后端」遷移而來,作為一款前端框架,對后端更親和且門檻高,這對本身就是從后端view層中分化出的前端工程師來說,是比較排斥的。
再舉個反例 —— Vue?。有同學(xué)會說,Vue這么流行的前端框架,你說他是反例?
還是從「提效」與「提高門檻」的角度看,Vue?提效的同時,由于其模版語法、響應(yīng)式更新等特性,他是降低了開發(fā)門檻的,這意味著使用Vue時:
- 同樣是開發(fā)業(yè)務(wù),老前端與新前端差距不大
- 必要時后端經(jīng)過簡單的學(xué)習(xí),也能接手部分需求
重申一下,我并不是說Vue不好,相反,他是很優(yōu)秀的前端框架。這里只是從人性的角度分析,并且這個分析很有可能是主觀、帶有偏見的。
再看個正面例子 —— React Hooks?。Hooks?對開發(fā)效率、組件復(fù)用性以及他對React未來發(fā)展的影響這里不贅述了。主要聊聊「提高門檻」:
- 一方面,什么時候封裝自定義Hook,如何封裝自定義Hook,如何規(guī)避Hook的坑,老前端與新前端有比較大的差異
- 更重要的是,后端改改JSX還行,要改基于Hooks的組件邏輯,是有一定難度的
既提效,又提高門檻,我認(rèn)為這才是Hooks在前端領(lǐng)域火熱的原因。
同樣的原因,從人性的角度,我很看好Vue Composition API
所以,前端編程范式遷移的本質(zhì)是:把握「提高效率」與「提高門檻」之間的平衡。
這個結(jié)論會成為后面預(yù)測未來開發(fā)模式的依據(jù)。
當(dāng)范式無法再遷移時
當(dāng)前端框架成為事實上的標(biāo)準(zhǔn)后很長一段時間,業(yè)界也在不斷探索新的開發(fā)范式。
有一種開發(fā)模式每過幾年都會被搬出來炒一遍,他就是「低代碼」。用我們上面的結(jié)論來分析下:在市場選擇的情況下,先拋開「低代碼是否能提高效率」不談,顯然他的目的是「降低門檻」。
從人性的角度出發(fā),他就很難在程序員群體中自發(fā)傳播開。
那么,如果沒有新的范式出現(xiàn),會發(fā)生什么事情?會內(nèi)卷。
我們會發(fā)現(xiàn),這幾年前端的發(fā)展軌跡,就是在重復(fù)一件事:
- 圍繞前端框架周邊,不斷探索各細(xì)分領(lǐng)域的最佳實踐
- 當(dāng)探索出最佳實踐后,就把他集成到框架中
舉個例子,React Router?作為React技術(shù)棧中「路由」這一細(xì)分領(lǐng)域的一個開源庫,經(jīng)過長期迭代,逐漸成為主流路由方案之一。
React Router?團(tuán)隊基于React Router?開發(fā)出Remix?這一React框架。
這么做,在沒有新的范式出現(xiàn)前,也能基于當(dāng)前范式(前端框架),達(dá)到上述2個目的:
- 提高效率:框架集成了最佳實踐,開發(fā)效率更高
- 提高門檻:除了學(xué)習(xí)React,還得學(xué)習(xí)新的上層框架
類似的,各種CSS?解決方案(比如tailwind css)也是同樣的道理:
- 提高效率:提高CSS編寫效率
- 提高門檻:新的概念、語法需要學(xué)習(xí)
那么,未來圍繞「提高效率」與「提高門檻」的平衡,前端開發(fā)模式會如何發(fā)展呢?
從考慮范式到考慮流程
首先,我認(rèn)為,在有限的未來,不會出現(xiàn)新的更先進(jìn)的范式能讓前端領(lǐng)域普遍認(rèn)可并大規(guī)模遷移(就像從jQuery到前端框架的遷移)。
那么,為了提高效率,除了「改變范式」與「范式內(nèi) 內(nèi)卷」兩個選擇外,還有個選擇 —— 讓整個開發(fā)流程提效。
從需求文檔到最終代碼,存在4級抽象:
- PM用自然語言編寫的需求文檔
- 需求評審時,PM給開發(fā)描述需求后,開發(fā)腦海里形成的業(yè)務(wù)邏輯
- 開發(fā)根據(jù)業(yè)務(wù)邏輯劃分各個模塊或組件
- 開發(fā)實現(xiàn)各個模塊或組件的具體代碼
當(dāng)前我們使用LLM?輔助編程時(比如以chatGPT為例),主要是用自然語言輸入模塊或組件業(yè)務(wù)邏輯,再讓模型輸出具體代碼。也就是借助模型自動完成從3到4級抽象的轉(zhuǎn)變。
比如說下圖我們讓chatGPT實現(xiàn)一個計時器:
這個計時器可能是我們需求中的某個模塊,在此chatGPT幫我們完成了從抽象3(實現(xiàn)一個計時器組件)到抽象4(計時器組件的代碼)。
如果僅僅到這一步,只能說這是個更高效的輔助工具,并不能達(dá)到「整個開發(fā)流程提效」的程度。為了達(dá)到這種程度,我們需要讓LLM幫我們完成從抽象1到4的整個過程。
LLM如何完成4級抽象轉(zhuǎn)換
接下來我們來看,基于當(dāng)前已有的模型,如何完成抽象1到抽象4的自動轉(zhuǎn)換。
首先,來看抽象1(PM用自然語言編寫的需求文檔)。chatGPT當(dāng)前已經(jīng)掌握基礎(chǔ)的理解能力,所以他是能夠理解需求文檔的含義的。
下圖是我從網(wǎng)上找的某需求文檔中的登錄功能流程圖:
以當(dāng)前主流的GPT-3.5?舉例,雖然GPT-3.5?不能理解圖片(不能理解需求文檔中的流程圖),但我們可以將流程圖用文字描述出來(最新的GPT-4已經(jīng)擁有「理解圖片含義」的能力)。
上述登錄功能流程圖可以用文字概括為:
- 打開App后有3個選項,分別是“賬號密碼登錄”、“快捷登錄”、“第三方登錄”。
- 選擇“第三方登錄”,進(jìn)入第三方,同意授權(quán)后登錄成功。
- 選擇“快捷登錄”,輸入手機(jī)號和驗證碼并選擇身份,點擊登錄后登錄成功。
- 選擇“賬號密碼登錄”,輸入手機(jī)號,如果已注冊,輸入密碼,點擊登錄后登錄成功。
- 選擇“賬號密碼登錄”,輸入手機(jī)號,如果未注冊,進(jìn)入注冊頁,輸入手機(jī)號,如果手機(jī)號已注冊,回到“賬號密碼登錄”。
- 選擇“賬號密碼登錄”,輸入手機(jī)號,如果未注冊,進(jìn)入注冊頁,輸入手機(jī)號,如果手機(jī)號未注冊,填寫手機(jī)號、驗證碼、密碼、姓名、選擇身份,點擊注冊,完畢。
抽象1到抽象2
如何完成從抽象1到抽象2(業(yè)務(wù)邏輯)的轉(zhuǎn)變呢?換句話說,如何用一種介于「自然語言與實際代碼」之間的規(guī)范描述業(yè)務(wù)邏輯?
這種規(guī)范應(yīng)該擁有完備的數(shù)據(jù)結(jié)構(gòu)(類似JSON?、XML),因為這樣會帶來很多好處:
- 相比于自然語言,用規(guī)范的數(shù)據(jù)結(jié)構(gòu)表示的業(yè)務(wù)邏輯能夠傳達(dá)更準(zhǔn)確的意圖。
- 業(yè)務(wù)需求的不斷增多,僅僅對應(yīng)數(shù)據(jù)結(jié)構(gòu)體積的增大,即使再復(fù)雜的業(yè)務(wù),只需要分批將業(yè)務(wù)邏輯代表的數(shù)據(jù)結(jié)構(gòu)投喂給模型,模型就能完全理解我們的業(yè)務(wù)。
- 數(shù)據(jù)結(jié)構(gòu)可以保存在變量中,通過變量名就能指代業(yè)務(wù)邏輯,無需再用自然語言大段的向模型描述業(yè)務(wù)邏輯。
我們可以利用SCXML?(State Chart XML)格式。SCXML?是由W3C?定義的一種「表示狀態(tài)機(jī)」的XML格式,他能夠表示狀態(tài)之間的變化。
前端應(yīng)用的本質(zhì)其實就包括兩部分:
- 狀態(tài)的變化。
- 狀態(tài)到視圖的映射。
其中「狀態(tài)到視圖的映射」框架已經(jīng)幫我們做了。所以,只要能表示「狀態(tài)的變化」,其實就能表示業(yè)務(wù)邏輯。
現(xiàn)在,我們讓chatGPT?將流程圖翻譯為SCXML格式:
得到如下結(jié)構(gòu)(你不用細(xì)看,了解個大概就行):
至此,我們完成了抽象1到抽象2的轉(zhuǎn)變。
抽象2到抽象3
SCXML格式?jīng)]法直接在JS代碼中使用。為了用代碼實現(xiàn)邏輯,我們需要使用遵循SCXML規(guī)范的庫。xstate是JS中比較流行的狀態(tài)機(jī)開源庫。
所以接下來我們讓chatGPT將上述SCXML格式轉(zhuǎn)換為xstate語法:
得到結(jié)果(同樣,具體代碼你不用在意,了解我想表達(dá)的轉(zhuǎn)換意思就行):
這段代碼我們可以直接粘貼到xstate的可視化編輯器[1]中查看:
圖中初始狀態(tài)可以轉(zhuǎn)移到3個狀態(tài)(這些狀態(tài)都是chatGPT生成的),其中:
- QUICK_LOGIN —— 快捷登錄
- ACCOUNT_LOGIN —— 賬號密碼登錄
- THIRD_PARTY_LOGIN —— 第三方登錄
每個狀態(tài)接下來的變化邏輯都清晰可見。比如,當(dāng)進(jìn)入ACCOUNT_LOGIN狀態(tài)后,后續(xù)會根據(jù)是否登錄(UNREGISTERED、REGISTERED)進(jìn)入不同邏輯:
也就是說,chatGPT理解了需求文檔想表達(dá)的業(yè)務(wù)邏輯后,將業(yè)務(wù)邏輯轉(zhuǎn)換成代碼表示。
讀者可將上述xstate代碼復(fù)制到可視化編輯器中看到效果。
抽象3到抽象4
接下來,我們只需要讓chatGPT?根據(jù)上述xstate狀態(tài)機(jī)生成組件代碼即可。
這時有同學(xué)會問:chatGPT?對話有token限制,沒法生成太多代碼怎么辦?
實際上,這可能并不是壞事。在我曾經(jīng)供職的一家公司,前端團(tuán)隊有條不成文的規(guī)矩 —— 如果一個組件超過200行,那你就應(yīng)該拆分他。
同樣的,如果chatGPT?生成的組件超過了token限制,那么應(yīng)該讓他拆分新的組件。
拆分組件的前提是 —— chatGPT?需要懂業(yè)務(wù)邏輯。顯然,他已經(jīng)懂了xstate數(shù)據(jù)結(jié)構(gòu)所代表的業(yè)務(wù)邏輯。
更妙的是,我們可以讓chatGPT?將「SCXML格式轉(zhuǎn)換而來的xstate數(shù)據(jù)結(jié)構(gòu)」保存在一個變量中,在后續(xù)對話中,我們用一個變量名就能指代他背后所表示的業(yè)務(wù)邏輯(這里保存在變量m中)。
當(dāng)我們要生成業(yè)務(wù)組件代碼時,讓chatGPT從模塊中導(dǎo)出m實現(xiàn)組件邏輯:
對于實際場景下比較復(fù)雜的需求,經(jīng)過從抽象1到抽象3的轉(zhuǎn)換,我們會得到「代表業(yè)務(wù)邏輯的不同變量」,比如:
- signin變量代表登錄邏輯。
- login變量代表注冊邏輯。
- PopupAD變量代表彈窗廣告邏輯。
如果彈窗廣告的邏輯和是否登錄相關(guān),那么要實現(xiàn)彈窗廣告組件代碼只需要告訴chatGPT:
根據(jù)signin?、PopupAD?實現(xiàn)彈窗廣告的react?組件,其中signin?變量由xxx?模塊導(dǎo)出,PopupAD?變量由yyy導(dǎo)出。
如果你司使用其他框架,只需將其中react換成其他框架名即可。當(dāng)大家還在爭論哪個框架更優(yōu)秀時,LLM已經(jīng)悄悄幫開發(fā)者實現(xiàn)了「框架自由」。
新開發(fā)模式的優(yōu)勢
讓我們從「提高效率」與「提高門檻」的角度分析這種新開發(fā)模式的優(yōu)勢。
提高效率
首先,這種新模式能顯著提高開發(fā)效率。本質(zhì)來說,他將前端工程師從「實現(xiàn)需求」的角色轉(zhuǎn)變?yōu)椤竢eview代碼」的角色。
極端的講,當(dāng)需求評審會結(jié)束的那一刻,第一版前端代碼就生成了。
其次,他能解放部分測試同學(xué)的生產(chǎn)力(搶部分測試同學(xué)的活兒)。對于維護(hù)過屎山代碼的同學(xué),肯定遇到過這樣的場景:明明只是改動一個小需求,測試問你改動影響的范圍,你自己都不清楚會有多大影響,為了穩(wěn)妥起見只能讓測試覆蓋更大的回歸測試范圍。
在使用基于狀態(tài)機(jī)的開發(fā)模式后,任何改動會造成的影響在狀態(tài)圖中都清晰可見。同時,由于代碼邏輯的實現(xiàn)基于狀態(tài)機(jī),可以據(jù)此自動生成端到端的測試用例,模型也能根據(jù)狀態(tài)機(jī)描述的邏輯自己補足其他單測。
提高門檻
接下來,我們從「提高門檻」的角度分析。
首先,能夠?qū)δP蜕傻拇a進(jìn)行查漏補缺本身就要求開發(fā)者有一定前端開發(fā)水平。
其次,這種開發(fā)模式引入了新的抽象層 —— 狀態(tài)機(jī),這無疑會增加上手門檻。
但這都不是最重要的,最重要的是 —— 這套模式強(qiáng)迫前端開發(fā)需要更懂業(yè)務(wù)。
以前,拿到產(chǎn)品的需求文檔后,你可以在做的過程中遇到不懂的再問產(chǎn)品。使用新的開發(fā)模式后,你必須很懂業(yè)務(wù),做到「在需求評審時就能指出需求文檔中不合理的地方」。
因為當(dāng)需求評審結(jié)束后,你會將這份需求文檔投喂給模型直接生成業(yè)務(wù)代碼(中間會經(jīng)歷「生成SCXML」、「生成xstate數(shù)據(jù)結(jié)構(gòu)」、「保存xstate變量」、使用變量生成組件代碼)。
當(dāng)大家技術(shù)水平旗鼓相當(dāng)時,「懂業(yè)務(wù)」才是前端的核心競爭力。
綜上,這套開發(fā)模式在極大提高效率的同時提高了門檻,我認(rèn)為在未來很有可能成為主流前端開發(fā)模式。
參考資料
[1]xstate的可視化編輯器:https://stately.ai/viz。