測(cè):告別膠水代碼,3分鐘搭建CRUD接口)
早上刷 GitHub 趨勢(shì)榜看到一個(gè)后端相關(guān)項(xiàng)目Star 數(shù)已經(jīng)到 94.7k評(píng)論區(qū)最高贊的一句話是“用了它之后我兩周沒(méi)寫(xiě)過(guò)增刪改查接口了。” 我是做前后端分離項(xiàng)目出身的人看到這種標(biāo)題第一反應(yīng)是“又在吹”但點(diǎn)進(jìn)去把文檔和 Demo 都過(guò)了一遍之后我發(fā)現(xiàn)“再也不寫(xiě)膠水代碼”這句話雖然帶點(diǎn)營(yíng)銷(xiāo)味兒背后確實(shí)有實(shí)打?qū)嵉臇|西。這篇就當(dāng)一次拆解這個(gè) 94.7k Star 的全功能后端到底做了什么、3 分鐘跑通是不是真的、哪些場(chǎng)景能直接替代你的后端代碼、哪些場(chǎng)景千萬(wàn)別盲目套進(jìn)去。我會(huì)結(jié)合自己實(shí)際接項(xiàng)目時(shí)踩過(guò)的坑來(lái)講盡量不替 GitHub 主頁(yè)背廣告詞。1. “膠水代碼”為何會(huì)成為后端團(tuán)隊(duì)最大的隱性成本1.1 到底什么算膠水代碼先給膠水代碼畫(huà)個(gè)像不然很多人會(huì)以為我在貶低后端工作。膠水代碼不是業(yè)務(wù)邏輯不是算法也不是性能優(yōu)化而是那堆“不寫(xiě)上就跑不起來(lái)寫(xiě)上了又沒(méi)人會(huì)覺(jué)得你?!钡拇a。拿一個(gè)很常見(jiàn)的場(chǎng)景舉例前端要展示用戶列表后端需要做什么建一張users表寫(xiě)實(shí)體類(lèi)、Dao/Mapper、Service、Controller加參數(shù)校驗(yàn)、異常處理、統(tǒng)一返回格式再配置分頁(yè)查詢(xún)、字段過(guò)濾、跨域最后生成接口文檔。這些代碼單獨(dú)看每一行都很簡(jiǎn)單但一張表一套十張表十套二十張表就是幾百個(gè)文件。我第一次獨(dú)立做后端項(xiàng)目的時(shí)候光搭這套增刪改查模板就花了三天。當(dāng)時(shí)用的還是同事已經(jīng)封裝好的基礎(chǔ)框架三天里大部分時(shí)間都在復(fù)制粘貼、改字段名、加注解干完了自己都覺(jué)得沒(méi)有成就感。傳統(tǒng)后端一張表的成本說(shuō)明數(shù)據(jù)層實(shí)體類(lèi)、Mapper、XML 或注解服務(wù)層業(yè)務(wù)方法、參數(shù)轉(zhuǎn)換、事務(wù)控制控制層路由、鑒權(quán)、分頁(yè)包裝、統(tǒng)一返回配置成本跨域、攔截器、序列化規(guī)則周邊成本接口文檔、單元測(cè)試、模擬數(shù)據(jù)這些就是膠水代碼。它們不是不能寫(xiě)而是數(shù)量大、重復(fù)度高、出錯(cuò)概率還一點(diǎn)不低尤其在字段類(lèi)型改一個(gè)之后幾層文件要同步改漏一處就線上出 bug。1.2 前后端分離之后膠水層還在變大現(xiàn)在項(xiàng)目普遍采用前后端分離前端和后端之間多出來(lái)一層“接口契約”。這層契約本來(lái)應(yīng)該靠接口文檔管理實(shí)際操作里前端要自己封裝請(qǐng)求庫(kù)寫(xiě) mock處理 loading 狀態(tài)、錯(cuò)誤碼、Token 刷新后端要處理 CORS、參數(shù)校驗(yàn)、分頁(yè)格式。同一個(gè)接口兩邊各寫(xiě)一套邏輯任何一邊改了字段另一邊就要跟著改。很多小團(tuán)隊(duì)的現(xiàn)狀是后端同學(xué)每天在寫(xiě) CRUD前端同學(xué)每天在請(qǐng)求 CRUD 的接口并渲染表格。兩邊都在干體力活真正有價(jià)值的業(yè)務(wù)規(guī)則反而被擠到了角落里。這就是為什么“全功能后端”這個(gè)概念能引起這么多人共鳴——大家不是討厭寫(xiě)代碼是討厭寫(xiě)那些不得不寫(xiě)、又體現(xiàn)不出任何業(yè)務(wù)思考的代碼。2. 全功能后端拆解94.7k Star 背后的六個(gè)內(nèi)置能力2.1 核心架構(gòu)從“集成一堆組件”到“開(kāi)箱即用的產(chǎn)品”傳統(tǒng)后端項(xiàng)目的技術(shù)棧是拼出來(lái)的Spring Boot MyBatis Plus Redis MinIO Spring Security組件提供的是“零件”你需要自己設(shè)計(jì)接線方式。全功能后端不一樣它把這些零件做成一個(gè)整體產(chǎn)品你面對(duì)的是“功能”而不是“組件”。這就好比自己裝修和住精裝房的區(qū)別。自己裝修當(dāng)然靈活但是要自己拉電線、鋪水管、裝開(kāi)關(guān)精裝房則是進(jìn)門(mén)就能住住進(jìn)去之后想改哪里再局部拆改。全功能后端把數(shù)據(jù)庫(kù)、認(rèn)證、文件存儲(chǔ)、接口生成、后臺(tái)管理界面全部包含進(jìn)來(lái)你不再需要為它們之間的協(xié)作關(guān)系操心。2.2 全功能后端典型能力一覽以下我從實(shí)際使用體驗(yàn)出發(fā)把這類(lèi)項(xiàng)目最常被用到的能力列成一個(gè)表能力模塊解決了什么傳統(tǒng)方式的工作量數(shù)據(jù)庫(kù)與表管理可視建表、自動(dòng)生成 RESTful 接口建表 SQL 后端類(lèi)文件身份認(rèn)證郵箱密碼登錄、第三方登錄、JWTSpring Security / Shiro 配置權(quán)限控制按角色、按行精細(xì)控制訪問(wèn)權(quán)限表 攔截器 注解文件存儲(chǔ)圖片、附件上傳下載私有/公共訪問(wèn)MinIO / OSS 集成實(shí)時(shí)訂閱數(shù)據(jù)庫(kù)變化實(shí)時(shí)推送到前端WebSocket 服務(wù)端開(kāi)發(fā)后臺(tái)管理界面數(shù)據(jù)瀏覽、用戶管理、配置項(xiàng)編輯單獨(dú)開(kāi)發(fā)一套管理端這套能力覆蓋了“做一個(gè)可用產(chǎn)品的后端”80% 左右的常規(guī)需求。剩下 20% 的復(fù)雜業(yè)務(wù)邏輯再通過(guò)云函數(shù)或者自定義 API 補(bǔ)充。2.3 為什么能 3 分鐘搞定而不是 30 分鐘關(guān)鍵不是操作速度快而是省掉了“生成代碼”這一步。傳統(tǒng)低代碼平臺(tái)通常是根據(jù)表結(jié)構(gòu)生成一套后端代碼你還要下載、導(dǎo)入 IDE、編譯、部署改完代碼還要處理環(huán)境差異。全功能后端直接跳過(guò)代碼生成把表結(jié)構(gòu)定義好的瞬間接口就已經(jīng)在線可用了。我測(cè)試的時(shí)候建了一張test表字段填好、點(diǎn)保存然后直接在瀏覽器地址欄訪問(wèn)/rest/v1/test數(shù)據(jù)就返回了。那一刻確實(shí)有“這活兒是不是已經(jīng)干完了”的恍惚感。3. 我的 3 分鐘跑通實(shí)錄從空項(xiàng)目到可用的增刪改查接口3.1 Step 1創(chuàng)建項(xiàng)目實(shí)例我拿一個(gè)對(duì)團(tuán)隊(duì)友好、支持自助托管的開(kāi)源方案做驗(yàn)證。創(chuàng)建項(xiàng)目這一步和我以前在阿里云買(mǎi)數(shù)據(jù)庫(kù)、自己初始化環(huán)境完全不一樣填一個(gè)項(xiàng)目名稱(chēng)、選一下所在區(qū)域、設(shè)置數(shù)據(jù)庫(kù)密碼剩下的事情全交給平臺(tái)。有個(gè)容易忽略的細(xì)節(jié)這類(lèi)平臺(tái)一般會(huì)同時(shí)分配一個(gè) API URL 和 anon key很多人創(chuàng)建完項(xiàng)目后把 anon key 直接丟在前端代碼里這是可行的但“可用”和“安全”是兩碼事。后面我到權(quán)限那一節(jié)會(huì)詳細(xì)講先記住一句話anon key 只是你的客戶端憑證真正的數(shù)據(jù)保護(hù)靠的是行級(jí)安全策略不是靠 key 保密。3.2 Step 2建表并生成接口我建了一張文章表create table posts ( id bigint generated always as identity primary key, title text not null, content text, author_id uuid not null, created_at timestamptz default now() );在傳統(tǒng)項(xiàng)目里這張表建完還要寫(xiě)實(shí)體、寫(xiě) Mapper、寫(xiě) Service、寫(xiě) Controller至少一兩個(gè)小時(shí)。在這里表建完立刻可以通過(guò) REST API 訪問(wèn)curl -X POST https://你的項(xiàng)目域名/rest/v1/posts \ -H apikey: 你的anon-key \ -H Content-Type: application/json \ -d {title:測(cè)試文章,content:內(nèi)容,author_id:某個(gè)用戶id}返回結(jié)果直接就是新插入的數(shù)據(jù)再配合分頁(yè)參數(shù)select*ordercreated_at.desclimit10一個(gè)帶排序分頁(yè)的列表接口就出來(lái)了。第一次看到這種響應(yīng)速度我還是有點(diǎn)吃驚的。3.3 Step 3前端接入把前端接上去代碼也不再需要自己寫(xiě) axios 封裝官方 SDK 已經(jīng)把查詢(xún)語(yǔ)法封裝好了const { data, error } await supabase .from(posts) .select(*) .order(created_at, { ascending: false }) .limit(10);登錄認(rèn)證同樣走內(nèi)置能力const { data, error } await supabase.auth.signUp({ email: userexample.com, password: password });到這里我的“3 分鐘”就結(jié)束了。如果算上從下載工具到配置環(huán)境的時(shí)間實(shí)際大概是十來(lái)分鐘但這對(duì)于一個(gè)不需要寫(xiě)任何后端代碼的流程來(lái)說(shuō)已經(jīng)很夸張。4. 表面省下的時(shí)間最后都在權(quán)限、遷移和運(yùn)維這里找了回來(lái)4.1 權(quán)限與行級(jí)安全最容易翻車(chē)的區(qū)域全功能后端最大的坑在這里沒(méi)有之一。傳統(tǒng)后端里權(quán)限邏輯寫(xiě)在服務(wù)端代碼中你可以打斷點(diǎn)、可以單測(cè)在全功能后端里權(quán)限邏輯下沉到了數(shù)據(jù)庫(kù)層通過(guò)行級(jí)安全策略控制。很多項(xiàng)目創(chuàng)建之后默認(rèn)對(duì)公眾開(kāi)放讀權(quán)限。也就是說(shuō)你的表是能被任何人通過(guò) REST API 讀走的前提是 he 知道你的項(xiàng)目地址和 anon key。這倆東西在前端代碼里都是公開(kāi)的所以真正的安全防線必須是策略本身。給文章表加上“只能讀寫(xiě)自己的數(shù)據(jù)”的策略通常要寫(xiě)類(lèi)似下面的 SQLcreate policy 用戶管理自己的文章 on posts for all using (auth.uid() author_id) with check (auth.uid() author_id);這里auth.uid()是從 JWT 里解析出來(lái)的當(dāng)前用戶 IDauthor_id是文章表里的字段。這一條策略加上之后別人通過(guò) API 查你的文章列表只會(huì)看到自己的數(shù)據(jù)。如果你跳過(guò)這一步那跟把數(shù)據(jù)庫(kù)密碼貼在公網(wǎng)上沒(méi)什么區(qū)別。我在測(cè)試一個(gè)類(lèi)似產(chǎn)品時(shí)遇到過(guò)兩次因?yàn)椴呗月┡鋵?dǎo)致數(shù)據(jù)全公開(kāi)的情況好在那只是測(cè)試數(shù)據(jù)。這也是我建議所有準(zhǔn)備采用這種方案的人第一件要學(xué)的事。4.2 Schema 遷移與數(shù)據(jù)備份的工程化在控制臺(tái)里手動(dòng)建表、改字段開(kāi)發(fā)階段非常爽生產(chǎn)環(huán)境就是災(zāi)難。團(tuán)隊(duì)里任何一個(gè)人手動(dòng)改了一次表結(jié)構(gòu)其他人的本地環(huán)境就不同步了代碼評(píng)審也看不到這次變更。正確的做法是把結(jié)構(gòu)變更納入版本管理。這類(lèi)平臺(tái)一般支持通過(guò)命令行工具管理遷移腳本你可以把建表、修改字段、創(chuàng)建索引、更新策略全部寫(xiě)成 SQL 文件提交到 Git 里supabase/ migrations/ 0001_create_posts.sql 0002_add_comment_count.sql這樣每次部署執(zhí)行一遍遷移就能保證所有環(huán)境的表結(jié)構(gòu)完全一致。這也是從“會(huì)用”走向“用得專(zhuān)業(yè)”的標(biāo)志。備份也一樣。開(kāi)發(fā)階段容易忽視生產(chǎn)環(huán)境必須開(kāi)啟定時(shí)備份并定期做恢復(fù)演練。恢復(fù)演練一定要做不能只看到“備份成功”的提示就放心真出問(wèn)題的時(shí)候恢復(fù)不回來(lái)等于沒(méi)有備份。4.3 部署形態(tài)SaaS 托管還是自托管全功能后端一般分為兩種使用方式。一種是使用官方托管的云服務(wù)優(yōu)勢(shì)是省運(yùn)維數(shù)據(jù)庫(kù)、備份、升級(jí)都不用自己管適合快速上線。另一種是自托管部署優(yōu)勢(shì)是數(shù)據(jù)完全在自己手里適合有數(shù)據(jù)合規(guī)要求或需要私有化交付的項(xiàng)目。自托管的成本容易被低估。表面上它就是一個(gè)容器編排文件的事情跑起來(lái)之后你還要負(fù)責(zé) PostgreSQL 的版本升級(jí)、定時(shí)備份、監(jiān)控告警、磁盤(pán)擴(kuò)容。如果一個(gè)團(tuán)隊(duì)的運(yùn)維能力有限我建議優(yōu)先考慮托管服務(wù)把精力放在業(yè)務(wù)上。有一個(gè)折中方案也挺常用開(kāi)發(fā)環(huán)境用自托管生產(chǎn)環(huán)境用托管服務(wù)或者反過(guò)來(lái)。只要數(shù)據(jù)模型和權(quán)限策略一致切換成本可以接受。5. 不硬貼什么項(xiàng)目其實(shí)不適合用“全功能后端”5.1 邊界判斷四種不適合的情況雖然有 94.7k Star 背書(shū)但它不是萬(wàn)能藥。以下四類(lèi)情況我勸你別硬套。第一類(lèi)核心業(yè)務(wù)依賴(lài)復(fù)雜事務(wù)。比如訂單支付、庫(kù)存扣減、資金流水這些業(yè)務(wù)需要 ACID 保證跨表跨賬務(wù)的事務(wù)一多自動(dòng)生成的單表接口就不夠用了你最終還是要寫(xiě)服務(wù)層代碼。第二類(lèi)權(quán)限模型非常復(fù)雜。比如一個(gè)文檔系統(tǒng)里有組織、部門(mén)、項(xiàng)目、自定義角色還要支持按字段授權(quán)這時(shí)你會(huì)在數(shù)據(jù)庫(kù)策略里寫(xiě)出一大堆非常難維護(hù)的 SQL還不如用代碼實(shí)現(xiàn)。第三類(lèi)系統(tǒng)需要長(zhǎng)期演進(jìn)且團(tuán)隊(duì)規(guī)模較大。團(tuán)隊(duì)成員一多責(zé)任邊界需要清晰誰(shuí)管表結(jié)構(gòu)、誰(shuí)管接口、誰(shuí)管權(quán)限策略。全功能后端把后端代碼壓縮掉了但“壓縮”不等于“消失”只是從代碼變成配置和 SQL代碼評(píng)審和沖突解決的方式都變了。第四類(lèi)需要深度定制的能力比如特殊消息推送邏輯、自定義的文件處理流程、復(fù)雜的定時(shí)任務(wù)。如果每個(gè)定制都要繞開(kāi)平臺(tái)機(jī)制去實(shí)現(xiàn)那這個(gè)平臺(tái)的便利性就會(huì)被抵消。5.2 混合架構(gòu)把它當(dāng)“底座”而不是“全部”我目前在實(shí)際項(xiàng)目里更建議的做法是混合架構(gòu)身份認(rèn)證、文件存儲(chǔ)、簡(jiǎn)單數(shù)據(jù)管理交給全功能后端復(fù)雜業(yè)務(wù)單獨(dú)保留一個(gè)輕量 API 服務(wù)。比如一個(gè)內(nèi)容管理平臺(tái)認(rèn)證、用戶表、文章表、評(píng)論表用全功能后端負(fù)責(zé)前端直接讀寫(xiě)文章審核流、消息推送、數(shù)據(jù)統(tǒng)計(jì)匯總單獨(dú)寫(xiě)一個(gè)生成任務(wù)服務(wù)用服務(wù)端的密鑰調(diào)用管理 API 或直接操作數(shù)據(jù)庫(kù)。這樣既保住了“不需要寫(xiě)增刪改查膠水代碼”的效率又給復(fù)雜業(yè)務(wù)留了可控的代碼空間。我在一次性搞過(guò)一個(gè)內(nèi)部運(yùn)營(yíng)后臺(tái)數(shù)據(jù)模型有十來(lái)張表團(tuán)隊(duì)里只有我和一個(gè)前端同事。當(dāng)時(shí)如果讓我寫(xiě)一套完整后端少說(shuō)一周用這個(gè)方案半天就搭完了基礎(chǔ)功能剩下時(shí)間全在優(yōu)化數(shù)據(jù)展示和權(quán)限細(xì)節(jié)。最后交付出來(lái)的效果反而比傳統(tǒng)方式更快、更穩(wěn)。但我也遇到過(guò)反例。有個(gè)項(xiàng)目負(fù)責(zé)人看到這類(lèi)工具后決定把已經(jīng)寫(xiě)了半年的后端全部推倒重來(lái)結(jié)果核心流程里有訂單狀態(tài)機(jī)、三方對(duì)接、復(fù)雜事務(wù)折騰一個(gè)月后還是把服務(wù)層寫(xiě)了回來(lái)。工具本身沒(méi)問(wèn)題問(wèn)題出在“它什么都做得很好”和“你現(xiàn)在的場(chǎng)景真的需要它做什么”之間劃了等號(hào)。如果讓我給一句實(shí)在建議先把最擔(dān)心出問(wèn)題的一小塊業(yè)務(wù)拿出來(lái)用全功能后端搭一個(gè)最小驗(yàn)證原型確認(rèn)權(quán)限模型、數(shù)據(jù)隔離、遷移流程都符合你的要求再?zèng)Q定要不要全面鋪開(kāi)。3 分鐘建一個(gè)后端是真的但你的業(yè)務(wù)約束不會(huì)只值 3 分鐘后半段才是真正考驗(yàn)架構(gòu)能力的地方。