的核心:從業(yè)務(wù)需求到系統(tǒng)設(shè)計的思考路徑)
剛轉(zhuǎn)后端那年我電腦里存著幾十個框架的 Demo每個都能跑起來。直到一次需求評審業(yè)務(wù)方說要做一個“數(shù)據(jù)大屏”我們對著一堆指標(biāo)爭論了兩周才終于搞清楚他要的是老板來視察時能看到的動態(tài)數(shù)字。那一刻我意識到后端開發(fā)的核心從來不是框架和中間件而是一條從業(yè)務(wù)需求到系統(tǒng)設(shè)計的思考路徑。這條路徑踩得深不深直接決定系統(tǒng)是解決問題的工具還是制造問題的源頭。需求的真相藏在對話的縫隙里業(yè)務(wù)方描述需求時用的詞帶著自己的語境。他說“加一個導(dǎo)出功能”你以為是 Excel 導(dǎo)出但他真正想要的是每天自動把報表發(fā)到郵箱。這些沒說出來的部分才是需求的核心。業(yè)務(wù)方說的永遠(yuǎn)不是需求而是他腦中對解決方案的一次快照。你要做的是把快照拆開逐個角落問清楚誰看這個導(dǎo)出數(shù)據(jù)導(dǎo)出多少量多久一次網(wǎng)絡(luò)斷了怎么辦權(quán)限如何控制這些問題看似瑣碎但每一個都能改變設(shè)計。后端工程師最怕聽到“需求很清楚”這種話因為清楚往往是錯覺。提需求的人想要的是結(jié)果而你最該問的是結(jié)果長什么樣。需求評審不是走過場而是用提問剝洋蔥直到露出真實的業(yè)務(wù)目標(biāo)。這里有一個殘酷的事實大多數(shù)需求在第一次描述時都是錯的包括業(yè)務(wù)方自己的理解。抽象是取舍的藝術(shù)需求理解透了下一步是把業(yè)務(wù)還原成系統(tǒng)模型。這里的關(guān)鍵是抽象。抽象不是把現(xiàn)實世界照搬進(jìn)數(shù)據(jù)庫而是刻意忽略一些細(xì)節(jié)保留關(guān)鍵關(guān)系和不變屬性。比如用戶這個概念在登錄場景是賬號和密碼在訂單場景是收貨地址和支付方式在風(fēng)控場景是行為軌跡。同一個用戶不同上下文里抽象完全不同。沒有完美的抽象只有當(dāng)前成本最小的抽象。很多系統(tǒng)做砸是因為一開始想“全都要”把實體設(shè)計得無比龐大結(jié)果每個功能都綁手綁腳。好的抽象應(yīng)該讓新需求像填空壞的抽象讓新需求像拆墻。好的抽象讓新需求像填空壞的抽象讓新需求像拆墻。你可以常問自己如果明天要加一個用戶類型我的模型需要改幾張表如果答案超過兩張抽象可能有問題。抽象還是一門遺忘的藝術(shù)忘掉那些和當(dāng)前業(yè)務(wù)無關(guān)的枝節(jié)才能讓系統(tǒng)呼吸。數(shù)據(jù)是系統(tǒng)的骨架流程是血肉系統(tǒng)設(shè)計最實在的落腳點是數(shù)據(jù)模型和狀態(tài)流程。拿到需求先畫出核心實體之間的關(guān)系再為每個實體畫出生命周期。訂單狀態(tài)的遷移——待支付、已支付、已取消、退款中——每一個邊都是一條業(yè)務(wù)規(guī)則。狀態(tài)機不畫清楚線上必出鬼。我記得一個支付系統(tǒng)因為沒考慮超時關(guān)閉導(dǎo)致用戶取消訂單后仍然可以支付資金對不上賬。如果當(dāng)初把狀態(tài)機畫在一張紙上這些坑都能避免。數(shù)據(jù)字段同樣要問來源這個字段是用戶填的還是系統(tǒng)生成的它的有效性由誰來保障會不會有多處寫入不會回答數(shù)據(jù)來源和流向的系統(tǒng)設(shè)計都是空中樓閣。數(shù)據(jù)庫表不是草稿紙每一列都應(yīng)有明確的主人。數(shù)據(jù)一致性在后端尤其棘手分布式系統(tǒng)里你不得不引入冪等、重試、對賬但這些都應(yīng)該由業(yè)務(wù)需求觸發(fā)而不是為了技術(shù)炫技。接口不是 URL而是契約數(shù)據(jù)模型定了就要定義系統(tǒng)對外的接口。接口不是方法的羅列而是與調(diào)用方之間的契約。接口的命名比代碼注釋重要一百倍。命名一旦定義所有調(diào)用方都基于它溝通糟糕的命名讓人不敢調(diào)用良好的命名讓團(tuán)隊不用看文檔也能猜對。設(shè)計接口時先約定請求與響應(yīng)的結(jié)構(gòu)再談實現(xiàn)。最好把錯誤碼也一同設(shè)計讓調(diào)用方知道怎么處理而不是只看到一個 500。還要考慮冪等尤其支付、通知、消息類接口。后端設(shè)計得差不是代碼亂是接口讓人不敢動。不要將數(shù)據(jù)庫表直接暴露出去要構(gòu)建面向場景的響應(yīng)模型避免內(nèi)部改動波及外部。接口版本要規(guī)劃兼容策略但更重要的是一開始就謹(jǐn)慎避免不必要的破壞性變更。契約的意義在于它是團(tuán)隊協(xié)作的錨點錨點穩(wěn)了船才不會飄走。架構(gòu)是演化出來的不是設(shè)計出來的沒有一套架構(gòu)能一步到位業(yè)務(wù)在變團(tuán)隊在變流量也在變。后端架構(gòu)更像一棵樹不斷長出新的枝干而不是一棟一次性澆筑的大樓。但成長需要方向所以設(shè)計時要有意識地區(qū)分可逆決策和不可逆決策??赡娴谋热缛罩靖袷健⒑瘮?shù)命名隨意一點不可逆的比如數(shù)據(jù)庫分庫分表、跨服務(wù)數(shù)據(jù)共享必須慎重。把不可逆的決策留到最后是架構(gòu)演化的第一原則。許多團(tuán)隊一上來就拆微服務(wù)、引入高可用集群結(jié)果業(yè)務(wù)還沒驗證運維已經(jīng)累垮。系統(tǒng)不會死于欠設(shè)計只會死于過度設(shè)計。我這里說的欠設(shè)計是面對真實需求的無力而不是對未來臆想的無視。給系統(tǒng)留出演化空間比如模塊間用接口隔離比預(yù)先鋪一堆組件更實際。架構(gòu)師該做的不是預(yù)測未來而是讓未來發(fā)生時改動仍然可控。邊界即權(quán)力當(dāng)系統(tǒng)需要多個模塊或多團(tuán)隊協(xié)作時邊界設(shè)計就成了核心。邊界劃分本質(zhì)上是權(quán)力分配數(shù)據(jù)由誰寫接口由誰定流程由誰驅(qū)動。劃分不清的邊界最終都會變成撕扯不清的鍋。一個經(jīng)典場景是“下單”和“庫存”。訂單服務(wù)扣庫存庫存服務(wù)也扣庫存看似都行一旦超賣就是事故兩邊互相推諉。按業(yè)務(wù)領(lǐng)域劃分邊界每個領(lǐng)域的內(nèi)部規(guī)則和存儲完全自治對外只暴露經(jīng)過設(shè)計的事件。訂單完成時發(fā)布事件庫存服務(wù)監(jiān)聽事件來扣減誰也不會越界。依賴倒置不是算法是團(tuán)隊溝通的規(guī)則。邊界寫進(jìn)代碼里成為無法繞過的檢查比依賴人的自覺可靠得多。設(shè)計邊界時也要尊重業(yè)務(wù)的語言體系不要在庫存領(lǐng)域談?wù)撚唵蔚摹跋聠谓痤~”那會讓人糊涂。技術(shù)選型是一場負(fù)債管理架構(gòu)骨架有了技術(shù)棧的選擇就提上日程。很多人喜歡追新但選型不是選美而是在選擇未來要背的負(fù)債。沒有最好的技術(shù)只有最貴的遷移成本。引入一個中間件意味著團(tuán)隊要學(xué)習(xí)、運維要監(jiān)控、故障要排查。所以選型之前先量化需求并發(fā)量級、數(shù)據(jù)規(guī)模、延遲要求、一致性要求。能用數(shù)據(jù)庫解決的事情不要引入緩存能用消息隊列解決的事情不要引入服務(wù)網(wǎng)格。能簡單就不要復(fù)雜能少一個中間件就少一個故障點。同時要做技術(shù)決策記錄把選擇理由和權(quán)衡寫下來讓后來者知道當(dāng)時為什么這么定而不是看到一段代碼一頭霧水。技術(shù)選型還必須考慮團(tuán)隊的現(xiàn)實一個沒人會的技術(shù)哪怕再好也沒人維護(hù)最后變成遺產(chǎn)。選型是面向整個系統(tǒng)生命周期的不是面向簡歷的。需求變更的應(yīng)對設(shè)計得再好也攔不住需求變化。后端工程師的態(tài)度應(yīng)該是擁抱變化而不是抗拒。但擁抱不是被動改代碼而是用設(shè)計讓變化成本可控。在需求中找出大概率會變動的維度比如計費規(guī)則、渠道類型、優(yōu)惠策略為它們設(shè)置擴展點。比如用策略模式封裝規(guī)則或者用事件驅(qū)動解耦響應(yīng)方。為不存在的未來預(yù)留接口是最昂貴的浪費。擴展點只能加在真實業(yè)務(wù)的波動處而不是憑空想象。當(dāng)需求變更到來時先問影響范圍再決定改動方案。如果能只改一個類就絕不動三個表。真正的設(shè)計彈性體現(xiàn)在改一行代碼能完成需求而不是新增一個框架。需求變更是一場壓力測試它檢驗的不是代碼寫得多快而是當(dāng)初的抽象是否貼近業(yè)務(wù)本質(zhì)。那些被變更打垮的系統(tǒng)通常不是代碼太爛而是設(shè)計的核心邏輯沒有扎在業(yè)務(wù)深處。那次數(shù)據(jù)大屏需求我們只用了一張定時刷新的圖表頁配合一個簡單的聚合查詢。業(yè)務(wù)方很滿意因為他要的只是“讓老板看著舒服”。我沒有展示任何高并發(fā)技巧但那次經(jīng)歷讓我完成了從“會寫代碼”到“會做設(shè)計”的轉(zhuǎn)變。后端開發(fā)的本質(zhì)是一場與“不確定性”的持續(xù)談判。需求是不確定的技術(shù)選型是不確定的架構(gòu)演化也是不確定的。你所能做的就是不斷加深對業(yè)務(wù)的理解并用克制的設(shè)計去應(yīng)對。代碼只是思考的副產(chǎn)品。真正的后端核心是一條清晰、謙遜、充滿取舍的思考路徑這條路值得用整個職業(yè)生涯去走。