計(jì)師進(jìn)階指南:從計(jì)算機(jī)系統(tǒng)原理到架構(gòu)設(shè)計(jì)實(shí)踐)
1. 從“碼農(nóng)”到“架構(gòu)師”軟件設(shè)計(jì)師的角色蛻變很多人一聽(tīng)到“軟件設(shè)計(jì)師”第一反應(yīng)可能就是“寫代碼的”。這個(gè)理解不能說(shuō)錯(cuò)但太片面了。在計(jì)算機(jī)系統(tǒng)的語(yǔ)境下軟件設(shè)計(jì)師這個(gè)角色更像是一個(gè)從藍(lán)圖到施工圖的翻譯官和總工程師。他站在用戶需求、業(yè)務(wù)邏輯和冰冷硬件之間負(fù)責(zé)把那些抽象的想法變成一套能在計(jì)算機(jī)系統(tǒng)上高效、穩(wěn)定、可維護(hù)運(yùn)行的軟件方案。這不僅僅是寫幾行代碼而是涉及從頂層設(shè)計(jì)到具體實(shí)現(xiàn)的完整鏈條。我自己從一線開(kāi)發(fā)轉(zhuǎn)向設(shè)計(jì)崗位的這些年最深的體會(huì)就是一個(gè)優(yōu)秀的軟件設(shè)計(jì)師必須同時(shí)具備“仰望星空”的架構(gòu)視野和“腳踏實(shí)地”的工程能力。他需要理解計(jì)算機(jī)系統(tǒng)從CPU指令、內(nèi)存管理到網(wǎng)絡(luò)通信、存儲(chǔ)介質(zhì)的每一個(gè)層次因?yàn)槟愕拿恳粋€(gè)設(shè)計(jì)決策最終都要落到這些實(shí)實(shí)在在的硬件和系統(tǒng)軟件上并受其約束。為什么這個(gè)角色在今天越來(lái)越重要因?yàn)檐浖到y(tǒng)正變得前所未有的復(fù)雜。單體應(yīng)用時(shí)代一個(gè)資深程序員或許能hold住大部分設(shè)計(jì)。但在微服務(wù)、云計(jì)算、大數(shù)據(jù)和AI驅(qū)動(dòng)的今天系統(tǒng)是分布式的、數(shù)據(jù)是海量的、需求是快速變化的。如果沒(méi)有一個(gè)清晰的、經(jīng)過(guò)深思熟慮的設(shè)計(jì)項(xiàng)目很容易陷入“打補(bǔ)丁”的泥潭代碼腐化性能瓶頸頻出最終導(dǎo)致系統(tǒng)難以維護(hù)和擴(kuò)展。軟件設(shè)計(jì)師的核心價(jià)值就在于通過(guò)前瞻性的設(shè)計(jì)規(guī)避這些風(fēng)險(xiǎn)用合理的成本構(gòu)建出健壯的系統(tǒng)。這要求設(shè)計(jì)師不僅懂技術(shù)更要懂業(yè)務(wù)懂權(quán)衡。比如為了應(yīng)對(duì)高并發(fā)是選擇更復(fù)雜的緩存策略還是直接升級(jí)數(shù)據(jù)庫(kù)這背后是成本、開(kāi)發(fā)周期和未來(lái)可維護(hù)性的綜合考量。2. 計(jì)算機(jī)系統(tǒng)原理軟件設(shè)計(jì)師的底層思維基石很多開(kāi)發(fā)者覺(jué)得學(xué)習(xí)操作系統(tǒng)、計(jì)算機(jī)組成原理這些基礎(chǔ)課只是為了應(yīng)付考試工作中用不上。這其實(shí)是一個(gè)巨大的誤區(qū)。對(duì)于軟件設(shè)計(jì)師而言深入理解計(jì)算機(jī)系統(tǒng)不是“錦上添花”而是“安身立命之本”。你的設(shè)計(jì)水平很大程度上取決于你對(duì)系統(tǒng)底層工作原理的理解深度。這就像建筑師必須懂材料力學(xué)和結(jié)構(gòu)原理一樣否則設(shè)計(jì)出來(lái)的房子可能很好看但一陣風(fēng)就倒了。2.1 內(nèi)存層次結(jié)構(gòu)與緩存設(shè)計(jì)思想計(jì)算機(jī)系統(tǒng)的內(nèi)存是一個(gè)層次結(jié)構(gòu)寄存器、L1/L2/L3緩存、主存RAM、磁盤SSD/HDD。越往上速度越快容量越小成本越高。軟件設(shè)計(jì)師在設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)和算法時(shí)必須要有“緩存友好”的意識(shí)。例如為什么遍歷一個(gè)二維數(shù)組時(shí)按行遍歷a[i][j]通常比按列遍歷a[j][i]快得多這是因?yàn)楝F(xiàn)代CPU的緩存行Cache Line通常是64字節(jié)按行訪問(wèn)能充分利用空間局部性一次緩存加載能命中后續(xù)多個(gè)數(shù)據(jù)而按列訪問(wèn)則會(huì)導(dǎo)致大量的緩存缺失Cache Miss頻繁從速度慢得多的主存中加載數(shù)據(jù)性能急劇下降。在設(shè)計(jì)系統(tǒng)時(shí)這個(gè)原理可以放大到分布式緩存如Redis的應(yīng)用上。你把哪些數(shù)據(jù)放在本地內(nèi)存緩存哪些放在Redis集群哪些必須回源數(shù)據(jù)庫(kù)這需要你根據(jù)數(shù)據(jù)的訪問(wèn)頻率、更新頻率、一致性要求以及對(duì)延遲的敏感度來(lái)設(shè)計(jì)多級(jí)緩存策略。理解CPU緩存機(jī)制能讓你更好地設(shè)計(jì)這些更上層的緩存預(yù)判熱點(diǎn)數(shù)據(jù)減少不必要的網(wǎng)絡(luò)IO和磁盤IO這是提升系統(tǒng)性能最有效的手段之一。2.2 CPU流水線、分支預(yù)測(cè)與算法優(yōu)化CPU并非一條指令執(zhí)行完再執(zhí)行下一條而是采用流水線Pipeline技術(shù)像工廠流水線一樣同時(shí)處理多條指令的不同階段取指、譯碼、執(zhí)行、訪存、寫回。為了進(jìn)一步提高效率CPU還有亂序執(zhí)行Out-of-Order Execution和分支預(yù)測(cè)Branch Prediction等復(fù)雜機(jī)制。這對(duì)我們寫代碼有什么啟示一個(gè)典型的例子是避免在緊密循環(huán)Hot Loop中使用大量的條件分支if-else。因?yàn)镃PU會(huì)嘗試預(yù)測(cè)分支的走向提前加載指令。如果預(yù)測(cè)失敗分支預(yù)測(cè)錯(cuò)誤就需要清空流水線代價(jià)非常高。在高性能計(jì)算場(chǎng)景下有時(shí)可以通過(guò)查表法、位運(yùn)算或者重構(gòu)算法邏輯來(lái)消除分支。比如經(jīng)典的“計(jì)算絕對(duì)值”操作使用位運(yùn)算(x ^ (x 31)) - (x 31)針對(duì)32位整數(shù)可能比條件判斷x 0 ? x : -x更快就是因?yàn)楸苊饬朔种АT谠O(shè)計(jì)算法時(shí)軟件設(shè)計(jì)師需要評(píng)估算法的時(shí)間復(fù)雜度和空間復(fù)雜度這大家都會(huì)。但更進(jìn)一步你需要思考算法的“實(shí)際”性能而不僅僅是“理論”性能。同樣是O(n log n)的排序算法快速排序在大多數(shù)情況下比堆排序更快就是因?yàn)樗木彺婢植啃愿脤?duì)CPU的流水線和緩存更友好。這些微觀層面的考量是區(qū)分普通程序員和資深設(shè)計(jì)師的關(guān)鍵。2.3 I/O模型與系統(tǒng)并發(fā)設(shè)計(jì)軟件系統(tǒng)慢十有八九慢在I/O上磁盤I/O、網(wǎng)絡(luò)I/O。理解計(jì)算機(jī)系統(tǒng)提供的不同I/O模型阻塞、非阻塞、I/O多路復(fù)用、異步I/O是設(shè)計(jì)高并發(fā)系統(tǒng)的前提。為什么Nginx、Redis能輕松處理數(shù)萬(wàn)甚至數(shù)十萬(wàn)的并發(fā)連接核心就在于它們使用了像epollLinux或kqueueBSD這樣的I/O多路復(fù)用技術(shù)。與傳統(tǒng)的多線程/多進(jìn)程模型一個(gè)連接一個(gè)線程相比I/O多路復(fù)用允許單個(gè)線程監(jiān)聽(tīng)大量文件描述符Socket上的事件當(dāng)某個(gè)Socket可讀或可寫時(shí)線程才去處理避免了大量線程上下文切換的開(kāi)銷。作為軟件設(shè)計(jì)師你需要為你的系統(tǒng)選擇合適的并發(fā)模型。是使用多線程還是協(xié)程Coroutine或者是Actor模型這取決于你的業(yè)務(wù)場(chǎng)景。如果是CPU密集型計(jì)算多線程可以利用多核優(yōu)勢(shì)。如果是I/O密集型服務(wù)如Web服務(wù)器、代理網(wǎng)關(guān)那么基于事件循環(huán)Event Loop的異步非阻塞模型如Node.js、Go的goroutine往往是更高效的選擇。你的設(shè)計(jì)必須基于對(duì)操作系統(tǒng)調(diào)度、進(jìn)程/線程上下文切換成本、內(nèi)存共享與鎖競(jìng)爭(zhēng)等底層機(jī)制的深刻理解否則很容易設(shè)計(jì)出一個(gè)“看起來(lái)能跑一上壓力就崩”的系統(tǒng)。3. 軟件設(shè)計(jì)師的核心工作流從需求到藍(lán)圖理解了底層原理我們來(lái)看看軟件設(shè)計(jì)師的日常工作是如何將這些原理落地的。這個(gè)過(guò)程通常不是線性的而是一個(gè)不斷迭代和精化的循環(huán)。3.1 需求分析與抽象建模這是所有設(shè)計(jì)的起點(diǎn)也是最容易出錯(cuò)的地方。業(yè)務(wù)方提出的需求往往是具體、零散甚至矛盾的。軟件設(shè)計(jì)師的第一項(xiàng)任務(wù)就是與產(chǎn)品經(jīng)理、業(yè)務(wù)方深入溝通穿透表面的“用戶想要什么功能”挖掘出深層次的“用戶要解決什么問(wèn)題”以及“業(yè)務(wù)要達(dá)成什么目標(biāo)”。接下來(lái)就是進(jìn)行抽象建模。這是將混沌的現(xiàn)實(shí)世界映射到清晰的軟件概念的關(guān)鍵一步。你需要識(shí)別出系統(tǒng)中的核心實(shí)體Entity、它們的屬性Attribute以及實(shí)體之間的關(guān)系Relationship。常用的工具包括用例圖描述系統(tǒng)為外部用戶提供的功能、類圖描述系統(tǒng)內(nèi)部靜態(tài)結(jié)構(gòu)和狀態(tài)圖描述實(shí)體隨時(shí)間變化的行為。這里有一個(gè)常見(jiàn)的坑過(guò)度設(shè)計(jì)。在早期就試圖建立一個(gè)完美、覆蓋所有細(xì)節(jié)的模型往往會(huì)浪費(fèi)大量時(shí)間因?yàn)樾枨蟊厝粫?huì)變。我的經(jīng)驗(yàn)是采用“演進(jìn)式設(shè)計(jì)”的思路先建立一個(gè)反映核心領(lǐng)域概念的最小化模型確保團(tuán)隊(duì)對(duì)核心業(yè)務(wù)邏輯的理解一致即可。細(xì)節(jié)可以在后續(xù)迭代中隨著需求的明確而逐步豐富。3.2 架構(gòu)風(fēng)格與模式選型有了清晰的領(lǐng)域模型接下來(lái)就要決定系統(tǒng)的骨架——軟件架構(gòu)。你是選擇傳統(tǒng)的單體架構(gòu)Monolithic還是微服務(wù)架構(gòu)Microservices或者是介于兩者之間的模塊化單體Modular Monolith這沒(méi)有銀彈完全取決于你的業(yè)務(wù)規(guī)模、團(tuán)隊(duì)結(jié)構(gòu)和未來(lái)演進(jìn)預(yù)期。對(duì)于初創(chuàng)公司或業(yè)務(wù)非常簡(jiǎn)單的系統(tǒng)單體架構(gòu)簡(jiǎn)單直接開(kāi)發(fā)部署效率高是合理的選擇。但當(dāng)系統(tǒng)復(fù)雜度增長(zhǎng)團(tuán)隊(duì)規(guī)模擴(kuò)大后單體應(yīng)用會(huì)變得臃腫技術(shù)棧升級(jí)困難團(tuán)隊(duì)協(xié)作效率低下。這時(shí)微服務(wù)架構(gòu)通過(guò)將系統(tǒng)拆分為一組小型、自治的服務(wù)每個(gè)服務(wù)圍繞特定業(yè)務(wù)能力構(gòu)建可以帶來(lái)更好的可擴(kuò)展性、技術(shù)異構(gòu)性和團(tuán)隊(duì)自治性。但是微服務(wù)也引入了分布式系統(tǒng)固有的復(fù)雜性服務(wù)發(fā)現(xiàn)、鏈路追蹤、分布式事務(wù)、最終一致性等。作為設(shè)計(jì)師你必須評(píng)估團(tuán)隊(duì)是否具備駕馭這些復(fù)雜性的能力。除了頂層架構(gòu)風(fēng)格還需要在更細(xì)的粒度上應(yīng)用設(shè)計(jì)模式。比如對(duì)于需要?jiǎng)?chuàng)建復(fù)雜對(duì)象的場(chǎng)景可以考慮工廠模式為了解耦發(fā)送者和接收者可以使用觀察者模式或發(fā)布-訂閱模式為了優(yōu)化昂貴對(duì)象的創(chuàng)建可以使用享元模式或?qū)ο蟪亍_@里的關(guān)鍵不是生搬硬套23種設(shè)計(jì)模式而是理解每種模式解決的是什么類型的問(wèn)題創(chuàng)建、結(jié)構(gòu)、行為然后在遇到類似問(wèn)題時(shí)能自然地想到并應(yīng)用合適的模式。模式是工具箱里的工具而不是目標(biāo)本身。3.3 關(guān)鍵技術(shù)決策與折衷權(quán)衡架構(gòu)藍(lán)圖勾勒出來(lái)后就需要填充關(guān)鍵技術(shù)選型。這包括但不限于編程語(yǔ)言與框架是Java Spring生態(tài)的穩(wěn)健還是Go的高并發(fā)簡(jiǎn)潔或是Python在AI/數(shù)據(jù)分析領(lǐng)域的優(yōu)勢(shì)這需要結(jié)合團(tuán)隊(duì)技術(shù)棧、性能要求、開(kāi)發(fā)效率和社區(qū)生態(tài)綜合考慮。數(shù)據(jù)存儲(chǔ)關(guān)系型數(shù)據(jù)庫(kù)MySQL, PostgreSQL還是NoSQLMongoDB, Redis, Elasticsearch是否需要混用數(shù)據(jù)模型如何設(shè)計(jì)索引策略是什么通信協(xié)議服務(wù)間調(diào)用用RESTful API、gRPC還是消息隊(duì)列如Kafka, RabbitMQ它們各自在性能、耦合度、可靠性上有何優(yōu)劣部署與運(yùn)維是否容器化Docker是否采用Kubernetes進(jìn)行編排監(jiān)控、日志、告警體系如何搭建每一個(gè)決策背后都是一次權(quán)衡Trade-off。選擇強(qiáng)一致性的數(shù)據(jù)庫(kù)可能會(huì)犧牲一些寫入性能選擇異步消息隊(duì)列解耦服務(wù)就要接受數(shù)據(jù)最終一致性帶來(lái)的業(yè)務(wù)邏輯復(fù)雜性。軟件設(shè)計(jì)師最重要的能力之一就是向團(tuán)隊(duì)和業(yè)務(wù)方清晰地闡述這些權(quán)衡我們選擇了A方案得到了X好處但需要接受Y代價(jià)。所有的設(shè)計(jì)都是權(quán)衡的結(jié)果不存在完美的方案只有最適合當(dāng)前上下文Context的方案。4. 設(shè)計(jì)質(zhì)量的衡量從理論到實(shí)踐的驗(yàn)證設(shè)計(jì)畫得再漂亮不能落地也是空中樓閣。如何衡量一個(gè)軟件設(shè)計(jì)的好壞我認(rèn)為有幾個(gè)非常實(shí)用的非功能性指標(biāo)它們直接決定了系統(tǒng)未來(lái)的生命力。4.1 可維護(hù)性與代碼腐化防御可維護(hù)性差的系統(tǒng)其開(kāi)發(fā)速度會(huì)隨著時(shí)間指數(shù)級(jí)下降最終成為“遺產(chǎn)系統(tǒng)”沒(méi)人敢動(dòng)。如何設(shè)計(jì)出易于維護(hù)的系統(tǒng)高內(nèi)聚、低耦合這是最根本的原則。模塊內(nèi)部元素聯(lián)系緊密高內(nèi)聚模塊之間依賴清晰、簡(jiǎn)單低耦合。這樣當(dāng)需求變化時(shí)影響的范圍可以被控制在最小。清晰的抽象與封裝將復(fù)雜的實(shí)現(xiàn)細(xì)節(jié)隱藏起來(lái)對(duì)外提供簡(jiǎn)單、穩(wěn)定的接口。這降低了其他模塊的理解成本和使用成本。比如一個(gè)負(fù)責(zé)支付處理的模塊對(duì)外只暴露processPayment(order)方法內(nèi)部可能整合了多家支付渠道的復(fù)雜邏輯但調(diào)用方無(wú)需關(guān)心??蓽y(cè)試性一個(gè)難以編寫單元測(cè)試的設(shè)計(jì)通常也是一個(gè)耦合度高的設(shè)計(jì)。通過(guò)依賴注入Dependency Injection等方式讓模塊易于被隔離和測(cè)試這反過(guò)來(lái)會(huì)促使你的設(shè)計(jì)更加清晰。文檔與注釋這里的文檔不是指事后補(bǔ)的幾百頁(yè)設(shè)計(jì)說(shuō)明書而是在代碼層面就能體現(xiàn)的“自描述性”。良好的命名、清晰的函數(shù)職責(zé)、關(guān)鍵算法邏輯的注釋比任何外部文檔都更有生命力。在實(shí)際項(xiàng)目中我習(xí)慣定期進(jìn)行“代碼評(píng)審”和“架構(gòu)復(fù)審”不僅看功能實(shí)現(xiàn)更看設(shè)計(jì)是否違背了上述原則。一旦發(fā)現(xiàn)“上帝類”職責(zé)過(guò)多的類或“蜘蛛網(wǎng)依賴”就要立即重構(gòu)防止代碼腐化蔓延。4.2 可擴(kuò)展性與性能規(guī)劃系統(tǒng)能否平滑地應(yīng)對(duì)增長(zhǎng)這包括用戶量的增長(zhǎng)伸縮性Scalability和功能復(fù)雜度的增長(zhǎng)擴(kuò)展性Extensibility。水平擴(kuò)展 vs 垂直擴(kuò)展設(shè)計(jì)時(shí)應(yīng)優(yōu)先考慮支持水平擴(kuò)展通過(guò)增加機(jī)器來(lái)提升能力。這意味著你的應(yīng)用應(yīng)該盡可能無(wú)狀態(tài)Stateless將狀態(tài)外置到緩存或數(shù)據(jù)庫(kù)中。這樣當(dāng)流量增長(zhǎng)時(shí)你只需要簡(jiǎn)單地增加應(yīng)用服務(wù)器實(shí)例并通過(guò)負(fù)載均衡器分發(fā)流量即可。性能基準(zhǔn)與容量規(guī)劃在設(shè)計(jì)階段就要對(duì)核心鏈路進(jìn)行性能估算和壓力測(cè)試。例如你的訂單創(chuàng)建API在單機(jī)配置下TPS每秒事務(wù)數(shù)是多少平均響應(yīng)時(shí)間是多少數(shù)據(jù)庫(kù)的QPS每秒查詢數(shù)能否支撐根據(jù)業(yè)務(wù)增長(zhǎng)預(yù)測(cè)你需要提前規(guī)劃什么時(shí)候需要引入緩存什么時(shí)候需要分庫(kù)分表。避免出現(xiàn)“業(yè)務(wù)上線即崩潰”的窘境。異步化與削峰填谷對(duì)于非實(shí)時(shí)性的耗時(shí)操作如發(fā)送郵件、生成報(bào)表、處理圖片一定要設(shè)計(jì)成異步任務(wù)。使用消息隊(duì)列將生產(chǎn)請(qǐng)求和消費(fèi)處理解耦可以避免突發(fā)流量壓垮系統(tǒng)實(shí)現(xiàn)“削峰填谷”讓系統(tǒng)處理能力更加平滑。4.3 可靠性、可用性與容災(zāi)設(shè)計(jì)對(duì)于很多業(yè)務(wù)系統(tǒng)來(lái)說(shuō)可靠性Reliability不出錯(cuò)和可用性Availability能訪問(wèn)是生命線。幾個(gè)9的可用性目標(biāo)直接決定了你的設(shè)計(jì)復(fù)雜度和成本。冗余與消除單點(diǎn)故障SPOF從負(fù)載均衡器、應(yīng)用服務(wù)器、緩存集群到數(shù)據(jù)庫(kù)每一層都不能有單點(diǎn)故障。數(shù)據(jù)庫(kù)需要主從復(fù)制甚至跨機(jī)房的主備切換。故障轉(zhuǎn)移與彈性設(shè)計(jì)當(dāng)某個(gè)實(shí)例或服務(wù)失敗時(shí)系統(tǒng)應(yīng)能自動(dòng)檢測(cè)并切換到備用資源。這需要服務(wù)發(fā)現(xiàn)、健康檢查等基礎(chǔ)設(shè)施的支持。同時(shí)服務(wù)自身要有彈性例如通過(guò)熔斷器Circuit Breaker模式當(dāng)依賴的下游服務(wù)持續(xù)失敗時(shí)主動(dòng)熔斷避免資源耗盡和故障蔓延并給予下游服務(wù)恢復(fù)的時(shí)間。數(shù)據(jù)備份與恢復(fù)定期備份是底線。更重要的是要定期進(jìn)行恢復(fù)演練確保備份的數(shù)據(jù)是有效的恢復(fù)流程是順暢的。只備份不演練等于沒(méi)有備份。5. 從設(shè)計(jì)到實(shí)現(xiàn)貫穿生命周期的設(shè)計(jì)師職責(zé)軟件設(shè)計(jì)師的工作并不是在畫出架構(gòu)圖后就結(jié)束了。一個(gè)負(fù)責(zé)任的設(shè)計(jì)師必須深度參與到后續(xù)的實(shí)現(xiàn)、測(cè)試、部署乃至運(yùn)維階段確保設(shè)計(jì)被正確理解并實(shí)施并根據(jù)反饋持續(xù)演進(jìn)設(shè)計(jì)。5.1 設(shè)計(jì)溝通與團(tuán)隊(duì)賦能再好的設(shè)計(jì)如果只存在設(shè)計(jì)師的腦子里或者精美的PPT里是毫無(wú)價(jià)值的。設(shè)計(jì)師必須是一個(gè)優(yōu)秀的溝通者。你需要向開(kāi)發(fā)團(tuán)隊(duì)清晰地傳達(dá)設(shè)計(jì)意圖、技術(shù)選型的理由、各個(gè)模塊的職責(zé)邊界以及關(guān)鍵的交互流程。我常用的方式包括召開(kāi)設(shè)計(jì)評(píng)審會(huì)邀請(qǐng)核心開(kāi)發(fā)、測(cè)試、運(yùn)維同事一起用白板或圖表逐層講解設(shè)計(jì)并鼓勵(lì)大家提問(wèn)和挑戰(zhàn)。很多潛在問(wèn)題是在這個(gè)環(huán)節(jié)被發(fā)現(xiàn)的。編寫活的設(shè)計(jì)文檔不要寫那種一次成型后就無(wú)人問(wèn)津的Word文檔。我推薦使用像Markdown這樣的格式將設(shè)計(jì)文檔放在代碼倉(cāng)庫(kù)里與代碼一起維護(hù)和更新。文檔中應(yīng)包含清晰的架構(gòu)圖使用如C4模型等標(biāo)準(zhǔn)、核心流程的序列圖、重要的接口定義甚至可以是API的Swagger/OpenAPI描述以及關(guān)鍵的設(shè)計(jì)決策記錄ADR, Architecture Decision Record。ADR特別有用它記錄了某個(gè)重要決策的背景、考慮的多種方案、最終選擇及理由這對(duì)未來(lái)回顧和新人理解系統(tǒng)至關(guān)重要。創(chuàng)建種子項(xiàng)目或腳手架對(duì)于采用新框架、新模式的系統(tǒng)設(shè)計(jì)師最好能親手搭建一個(gè)最簡(jiǎn)化的、可運(yùn)行的“種子項(xiàng)目”Seed Project里面包含了標(biāo)準(zhǔn)的項(xiàng)目結(jié)構(gòu)、配置范例、公共工具類和單元測(cè)試模板。這能極大降低團(tuán)隊(duì)的學(xué)習(xí)成本統(tǒng)一代碼風(fēng)格保證設(shè)計(jì)理念能從一開(kāi)始就落地。5.2 代碼層面的設(shè)計(jì)監(jiān)督與重構(gòu)在開(kāi)發(fā)過(guò)程中設(shè)計(jì)師需要定期查看核心代碼確保實(shí)現(xiàn)沒(méi)有偏離設(shè)計(jì)初衷。這并不是要你去做嚴(yán)格的代碼警察而是通過(guò)Code Review、結(jié)對(duì)編程等方式與開(kāi)發(fā)同學(xué)一起工作。關(guān)注架構(gòu)邊界檢查是否有代碼破壞了模塊之間的邊界導(dǎo)致了不必要的耦合。例如Web層的Controller是否直接繞過(guò)了服務(wù)層去操作數(shù)據(jù)庫(kù)識(shí)別設(shè)計(jì)異味長(zhǎng)的函數(shù)、大的類、復(fù)雜的條件語(yǔ)句、重復(fù)的代碼……這些“代碼壞味道”往往是設(shè)計(jì)需要調(diào)整的信號(hào)。設(shè)計(jì)師要推動(dòng)和指導(dǎo)團(tuán)隊(duì)進(jìn)行及時(shí)的重構(gòu)而不是任由技術(shù)債務(wù)堆積。應(yīng)對(duì)需求變更需求變更是常態(tài)。當(dāng)有重要需求變更時(shí)設(shè)計(jì)師需要評(píng)估其對(duì)現(xiàn)有架構(gòu)的影響并主導(dǎo)設(shè)計(jì)方案的調(diào)整。這可能意味著需要修改接口、拆分服務(wù)或者引入新的設(shè)計(jì)模式。5.3 上線后復(fù)盤與架構(gòu)演進(jìn)系統(tǒng)上線只是一個(gè)新的開(kāi)始。設(shè)計(jì)師必須密切關(guān)注系統(tǒng)的運(yùn)行狀態(tài)。監(jiān)控與度量通過(guò)監(jiān)控系統(tǒng)如Prometheus Grafana收集性能指標(biāo)響應(yīng)時(shí)間、錯(cuò)誤率、吞吐量和業(yè)務(wù)指標(biāo)。通過(guò)日志系統(tǒng)如ELK Stack追蹤異常和用戶行為。這些數(shù)據(jù)是檢驗(yàn)設(shè)計(jì)成敗的客觀依據(jù)。如果發(fā)現(xiàn)某個(gè)接口的95分位響應(yīng)時(shí)間異常高就需要深入分析是數(shù)據(jù)庫(kù)查詢慢了還是緩存失效了抑或是算法復(fù)雜度有問(wèn)題復(fù)盤與迭代每次線上故障或性能瓶頸都是一次寶貴的復(fù)盤機(jī)會(huì)。召集相關(guān)同事用“五問(wèn)法”深挖根因是設(shè)計(jì)時(shí)考慮不周還是實(shí)現(xiàn)有誤或是運(yùn)維操作不當(dāng)將復(fù)盤結(jié)論記錄下來(lái)并落實(shí)到架構(gòu)或流程的改進(jìn)中。持續(xù)演進(jìn)沒(méi)有一成不變的架構(gòu)。隨著業(yè)務(wù)發(fā)展當(dāng)初合適的單體架構(gòu)可能就需要向微服務(wù)演進(jìn)隨著數(shù)據(jù)量暴增簡(jiǎn)單的數(shù)據(jù)庫(kù)主從可能就需要升級(jí)為分庫(kù)分表。軟件設(shè)計(jì)師需要有前瞻性在系統(tǒng)出現(xiàn)嚴(yán)重瓶頸之前就規(guī)劃好架構(gòu)的演進(jìn)路線并帶領(lǐng)團(tuán)隊(duì)平穩(wěn)地實(shí)施架構(gòu)升級(jí)。這條路沒(méi)有終點(diǎn)需要持續(xù)學(xué)習(xí)、不斷思考、勇于實(shí)踐。每一次對(duì)復(fù)雜系統(tǒng)的成功設(shè)計(jì)和解構(gòu)都是對(duì)“軟件設(shè)計(jì)師”這個(gè)角色價(jià)值的最好證明。