后端Coder如何做好代碼設計?
點擊上方藍色“小哈學Java”,選擇“設為星標”
回復“資源”獲取獨家整理的學習資料!


來源:r6d.cn/C5Ja
說明:生鮮電商屬于一個軟件的產(chǎn)品,那么如何做好代碼設計呢?代碼設計,是程序員做項目時,在coding之前非常重要的一個步驟,可以說關系到整個系統(tǒng)、整個團隊的研發(fā)質(zhì)量和效率。一般說代碼設計,可能涵蓋以下幾種:
整體設計 架構設計 領域模型設計 數(shù)據(jù)庫設計 API設計 代碼實現(xiàn)設計
代碼設計的前提是,項目組成員已經(jīng)完成正式的需求評審,并經(jīng)過充分思考:
這個需求是為什么業(yè)務目標服務的? 這個需求描述的內(nèi)容,是否為服務該目標最合適的方式(包括研發(fā)性價比、項目周期等)? prd本身是否邏輯自洽? 是否每個內(nèi)容點都可實現(xiàn)? 實現(xiàn)的技術方案是什么? 是否做過類似的功能,合并嗎?復用嗎?拆解嗎?
整體設計與架構設計
“項目的整體設計,有時會涵蓋系統(tǒng)架構設計,這里要區(qū)分一下,系統(tǒng)架構設計并不完全等同于代碼架構設計。
”
整體設計首先要考慮的,是當前項目是要做一個全新的項目,還是要做原有項目基礎上改造、迭代;項目組的積累中,是否有可以復用的地方(模塊或成熟方案),是否有可以通過改造以符合新項目需求的可能。
其次再考慮,如果是新起項目,要如何搭建整體實施方案,內(nèi)容一般包括:
硬件部署與資源申請:硬件和資源,是要和業(yè)務需求結合來制定的,比如業(yè)務最大訪問、TPS/QPS等,要切實討論得出一個數(shù)據(jù)范圍,以確定系統(tǒng)是否做高并發(fā)方案。另外還要考慮容災等問題,以此制定系統(tǒng)高可用的設計。
分析項目特別突出的業(yè)務、技術難點:如千人千面的UI和查詢,或靈活配置的業(yè)務模式,類似這種需求的項目,會在模塊模型設計上做額外處理,可能是將各種規(guī)則單獨做一層規(guī)則引擎,也可能是在數(shù)據(jù)建模時增加更多維度;再比如超大的QPS,可能要在整體架構上,添加額外的中間層,異步收集數(shù)據(jù)等功能;還有就是依賴于審核的迭代上線周期(IOS、微信小程序)等,都要在整體設計中考慮進去。
內(nèi)外部信息交換通訊:整體設計系統(tǒng),要明確劃定項目范圍,哪些是本系統(tǒng)的功能,哪些功能、數(shù)據(jù)依賴其它系統(tǒng)或模塊。要明確此次項目對外交互系統(tǒng)的訪問關系和訪問條件。
數(shù)據(jù)的持久化存儲方案,如何選擇硬件,如何選擇軟件,一般有常規(guī)解決方案。特別要考慮和需求結合的一點是業(yè)務數(shù)據(jù)的生命周期,這也是數(shù)據(jù)歸檔方案等重要依據(jù)。
“整體設計中非常重要的一部分是系統(tǒng)架構設計,要在業(yè)務邊界確定的前提下進行。
”
首先,從業(yè)務視角進行拆解功能,定義系統(tǒng)由哪些模塊構成。
其次,根據(jù)業(yè)務復雜度、模塊功能性劃分,選擇合理的軟件架構模式及方案。
比如,業(yè)務需求上,有非常復雜的流程處理,但各個業(yè)務子模塊之間相對獨立,則可以選擇事件驅動型架構,基本上用狀態(tài)機、工作流就可以滿足功能了;再比如做微服務架構設計上,也不一定都做集中式負載均衡,如果整體功能需求對消息流轉要求比較高,則可以考慮中心消息型服務(比如Rocketmq)。
以上兩步更多是從需求上分析,偏近于從業(yè)務角度設計系統(tǒng)。后面兩步要從技術上做架構設計。
下一步要根據(jù)模塊劃分和架構方案選擇合適的開發(fā)語言和技術框架。生產(chǎn)上一般考慮優(yōu)選Java語言+Spring框架,但也有許多混搭的成熟方案,有些基于JVM的開源框架中對多語言的支持還是比較好的。
再下一步要將系統(tǒng)拆解,一般考慮劃分出展現(xiàn)層、(通訊層)服務層、數(shù)據(jù)層,再根據(jù)需求為每一層設計合理的服務及組件。如展現(xiàn)層上web還是mobile,服務層是用Spring Boot還是Spring Cloud做微服務,數(shù)據(jù)層使用Mysql還是Oracle等。另外還有項目服務等通用組件及各種業(yè)務、技術中間件、及整體項目通用的技術方案選型,如日志(ELK等)、監(jiān)控告警,訪問授權,token認證等。
整體設計要在需求明確(不一定所有細節(jié)完全敲定)的前提下盡心,一般形成定案要在正式需求評審會之后。
整體設計由團隊leader或項目owner完成。
整體設計文檔,優(yōu)先考慮使用物理部署圖、邏輯架構圖、業(yè)務流程圖等描述系統(tǒng)架構。
另:特別建議在需求評審會后,首先由研發(fā)lead組織召開設計討論會議。目的是讓項目成員盡早的參與到項目之中,并使用討論到方式,更好的理解項目及整體設計方案。
一般設計討論可用頭腦風暴方式進行會議。有重大分歧時,可以投票表決。
此討論會議召開前,需要leader提前設定議題,會議上設有1名主持人(可leader兼任或者team member輪流擔任),按照議題集中,輪流發(fā)言再集體討論方式得出結論。
主要議題包括:整體設計方向、項目人員大致分工、待解決疑問和處理人。
領域模型設計與數(shù)據(jù)庫設計
在整體架構設計完成后,
要針對已經(jīng)拆分的系統(tǒng)模塊做模型設計,
尤其是在項目需求中有重要功能的部分要重點設計。
領域建模要深度結合需求,從業(yè)務角度出發(fā),用一種自頂而下的方式來建立模型。
領域建模方法很多,最重要的原則是在項目模型建立之前,要先做概念的統(tǒng)一整理,要對特定概念的名詞做專業(yè)命名及能力約束。在此基礎上,再進行重疊功能的歸并和抽象。需要注意的是,此處制定的模型,和業(yè)務需求、數(shù)據(jù)庫設計、代碼類設計,都是一脈相承的,但并不完全等同。比如需求中有訂單Order的概念,在設計訂單Order都有哪些元素構成,可以實現(xiàn)什么操作時會發(fā)現(xiàn),要在數(shù)據(jù)庫和代碼中,拆分為OrderHeader和OrderDetail。
在領域模型中,還有一個重點,是要標注清楚各抽象概念之間的數(shù)據(jù)關系和約束。一般會比較關注數(shù)據(jù)之間是一對一、一對多、多對多等關系,并在此基礎上,結合業(yè)務流程泳道做系統(tǒng)模塊依賴關系圖、數(shù)據(jù)流圖等。
數(shù)據(jù)庫一般結合領域模型設計,是領域模型持久化存儲的映射轉化(ORMapping)。在項目數(shù)據(jù)庫設計中,除了常規(guī)關注的范式、mysql約束等(單獨寫過mysql應用的usage,此文略),額外關注:
1、表字段在整體系統(tǒng)中的規(guī)范定義和統(tǒng)一使用。比如相同的概念,在各個表字段中的定義要一致,(在代碼應用中也應保持一致)。
2、數(shù)據(jù)庫事務的應用方案。
3、冗余字段與代碼簡潔實用的平衡。
4、特別說明,數(shù)據(jù)庫一般僅作數(shù)據(jù)的持久化存儲,不要將業(yè)務邏輯的處理放到數(shù)據(jù)庫中進行。
5、生產(chǎn)業(yè)務數(shù)據(jù)delete,應該僅作邏輯刪除,不做物理刪除。
6、表設計要和性能結合起來,特別當DB成為性能瓶頸時,要特別斟酌索引設計的合理性。
模型設計一般為團隊leader或項目owner完成,數(shù)據(jù)庫設計一般為leader帶領team member一起完成。
數(shù)據(jù)庫設計一般要先于具體功能代碼實現(xiàn),在做此設計后,要針對存儲方案和底層數(shù)據(jù)結構設計,做double check和集中評審,評審內(nèi)容包括存儲介質(zhì)選型、表結構設計能否滿足技術方案、存取性能和存儲空間能否滿足業(yè)務發(fā)展、表或字段之間的辯證關系、字段名稱、字段類型、索引等。在評審一致通過后,沉淀為文檔。
API設計與代碼實現(xiàn)設計
在完成整體設計后,
要將所有功能拆分成獨立可調(diào)用的API。
這里的設計要考慮系統(tǒng)實現(xiàn)和業(yè)務需求的結合。
系統(tǒng)API拆分,一定是從需求實現(xiàn)角度考慮,
基于領域能力做的,且要充分考慮后續(xù)需求的變化演進,
盡量使更多后續(xù)功能變化在既有規(guī)定服務API的框架內(nèi)繼續(xù)演化。
此外還要關注非功能性需求,比如安全性、可用性、可擴展性等。
最后,在這個步驟要關注的點,
除了系統(tǒng)主干正向流程外,還有逆向流程、異常流程、
業(yè)務邊界等方面的接口定義。
API是系統(tǒng)模塊對外提供的服務,現(xiàn)行系統(tǒng)基本滿足前后端分離的框架使用條件,所以一般可以簡單理解為前端和系統(tǒng)交互的入口。但實際系統(tǒng)設計中,API不僅僅提供給前端使用,所以每個API的實現(xiàn)設計是系統(tǒng)模塊設計中非常重要的環(huán)節(jié)。
API的調(diào)用方一般會考慮給展示層多端調(diào)用(web、mobile等),還要考慮相同的API是否可以給其它系統(tǒng)模塊使用,最后一層設計是,是否用相同的API對外提供openAPI服務。設計中應當特別考慮此類API的功能聚合、分離,多場景適用性等。以訂單列表查詢?yōu)槔O計一個訂單列表query接口:
給前端頁面查詢,前端分頁每次傳參。這個場景最大的特點是,查詢頁面會設計較多分類查詢的篩選條件,且此類設計實現(xiàn)經(jīng)常可能是查詢條件直接投射到DB上。
在整體系統(tǒng)中,給其它模塊使用,如用戶模塊或報表模塊。這個場景的特點是,如果其它模塊功能為同步調(diào)用,則QPS不可預測,比如用戶模塊使用了這個訂單query接口,那么這個接口的性能就會成為用戶模塊的瓶頸。還有一種可能是其它模塊用此接口異步訪問同步數(shù)據(jù),就很有可能采用定時任務方式,固定分頁,并發(fā)調(diào)用查詢,如每5分鐘調(diào)用一次,每次調(diào)用并發(fā)20,每個訪問查詢500分頁數(shù)據(jù)。
給openAPI使用。如果開放給前端的query服務提供給開放平臺直接使用或包裝后直接訪問,則容易出現(xiàn)的場景是,每次調(diào)用查詢不確定分頁,很有可能一個大分頁(如十萬)就打到DB上,這樣即使索引匹配也容易造成數(shù)據(jù)庫緩存區(qū)擁堵。遇到這類需求,
3.1 要考慮一個API接口是否可以滿足所有需求,是否對數(shù)據(jù)訪問做權限隔離。即,考慮所有的服務都集中到一個API上,還是定向拆分,將一個內(nèi)部實現(xiàn)core,分別投射到多個API上。
3.2 不同訪問端如果有不同的QPS需求,還都考慮到,單個特大QPS接口,可以橫向合并,即,不根據(jù)業(yè)務約束,而是把所有大訪問的接口拆出來,給到單獨技術架構和硬件部署的服務里。
3.3 是否內(nèi)部實現(xiàn)上一致,是否使用緩存、中間層方案等。
數(shù)據(jù)庫設計尤其是索引設計要和接口設計(尤其是篩選條件)保持一致。
API的設計還有一個維度的考慮,是基于數(shù)據(jù)交互考慮。當兩個系統(tǒng)模塊要使用API交互數(shù)據(jù)時,定義的API要充分考慮使用場景,并做技術選型:
4.1. 數(shù)據(jù)是推還是拉?
4.2. 同步推送還是異步通知回調(diào)?
4.3. 通過接口還是MQ?是否需要削峰?
4.4. 是否需要保證強一致性?
4.5. crontab定時發(fā)起還是任務隊列發(fā)起?需要延時隊列、死信隊列嗎?
API拆分完成后,要做代碼實現(xiàn)設計。此設計主要關注每個API的內(nèi)部實現(xiàn),將一系列領域模型轉換為系統(tǒng)對象的類設計。這里面有3個圖可以輔助設計:
1、如果一個API復雜度較高,調(diào)用鏈路上的涉及對象較多,可以使用時序圖來表達并且明確各調(diào)用環(huán)節(jié)的輸入與輸出,以反映對象間的交互與協(xié)作關系。時序圖對完成設計評審、輔助項目開發(fā)有很大作用。
2、如果某個業(yè)務對象的狀態(tài)較多,可以使用狀態(tài)圖來表達并且明確狀態(tài)變化的各個觸發(fā)條件。首先明確對象有多少種狀態(tài),然后明確兩兩狀態(tài)之間是否存在直接轉換關系,再明確觸發(fā)狀態(tài)轉換的條件是什么。狀態(tài)圖對測試用例有很大幫助。
3、如果系統(tǒng)中模型類超過較多,且存在復雜的依賴關系,可以使用類圖來表達并且明確類之間的關系。類圖對復雜系統(tǒng)設計,尤其是靈活配置、路由映射、設計模式應用等,有一定幫助。
類的設計要充分考慮單一原則。應當優(yōu)先使用聚合/組合的方式來實現(xiàn)。不得已使用繼承的話,要使父類能夠出現(xiàn)的地方子類一定能夠出現(xiàn)。根據(jù)依賴倒置原則,盡量依賴抽象類與接口,有利于系統(tǒng)的擴展與維護。
在設計抽象時,要考慮以下問題:代碼直觀嗎(好的代碼自注釋性很強),它的編寫巧妙嗎?實現(xiàn)細節(jié)可能隱去了嗎?程序編寫是立足于問題域而不是計算機科學或語言結構域嗎?
程序開發(fā)有一個場景比較典型,寫第一版需求時,僅僅是一個簡單功能,實現(xiàn)也比較簡單,但后續(xù)功能增加很多,變化很大,每次在原有類定義基礎上增加功能,倒置代碼冗余,尤其容易造成if-else太多。此時要考慮提前預估功能,做擴展性設計,或者在每次功能迭代中,做小版本重構。比如訂單明細查詢,在定義查詢接口(interface)后,需求要增加一個千人千面功能,不同用戶訪問返回的內(nèi)容條目不一樣。如果用if-else或switch寫,會比較不好管理,代碼也容易混亂,這里可以新設計一個接口,做不同內(nèi)容配置,然后組合使用,或者采用其它設計模式。
設計模式的目的,是輔助程序員更好的實現(xiàn)代碼抽象,將現(xiàn)實業(yè)務邏輯,映射到抽象維度的代碼語言上。一般生產(chǎn)上經(jīng)常用到工廠抽象工廠、模板方法、策略、狀態(tài)等。選擇合適的設計模式和數(shù)據(jù)結構,有助于提升代碼的清晰簡潔度。
這個層次的代碼設計一般交給team member完成,并輸出接口定義、接口詳細設計、包括一些數(shù)據(jù)庫的DDL等。
設計評審與文檔中心
在項目實施之前,設計評審是非常重要的環(huán)節(jié)。研發(fā)lead應該組織內(nèi)部設計討論,每人的接口設計要通過peer或backup的review,更好的方式是通過集中評審。
因為再好的設計,也要確保項目組所有成員,理解正確且一致。這個不僅僅是lead對團隊的灌輸,要確保組員之間對同一個業(yè)務概念的理解也是正確且一致的。要確保每人的接口設計,都符合整體設計需要。要確保項目級別領域定義符合更上層定義(如公司級別命名),要確保項目級別領域定義統(tǒng)一、代碼實現(xiàn)中英文命名統(tǒng)一。大型項目,在dev內(nèi)部設計通過后,也可以由項目經(jīng)理組織產(chǎn)品、研發(fā)、測試各方展開設計評審,此處尤其要和prd結合,為整理測試用例服務。
接口細節(jié)的實現(xiàn)也應當是動手coding之前先做設計,并建議形成文檔,研發(fā)lead要提前組織好開發(fā)文檔中心,整組統(tǒng)一設計文檔格式。
一般常規(guī)內(nèi)容包括:
?新項目背景、或常規(guī)迭代項目里程碑
?項目管理的時間節(jié)點(需求評審時間、設計時間、提測時間、上線時間點)
?本期項目概要設計說明
?分工(API、完成人、預估工時、實際工時等)
?詳細設計:接口實現(xiàn)設計、DB設計、緩存設計等
?上線計劃等等
題外話: 目前小哈正在個人博客(新搭建的網(wǎng)站,域名就是犬小哈的拼音)?www.quanxiaoha.com?上更新《Go語言教程》、《Gin Web框架教程》,畢竟Go自帶天然的并發(fā)優(yōu)勢,后端的同學還是要學一下的,這個教程系列小哈會一直更新下去,歡迎小伙伴們訪問哦~
END
有熱門推薦?
最近面試BAT,整理一份面試資料《Java面試BATJ通關手冊》,覆蓋了Java核心技術、JVM、Java并發(fā)、SSM、微服務、數(shù)據(jù)庫、數(shù)據(jù)結構等等。
獲取方式:點“在看”,關注公眾號并回復?Java?領取,更多內(nèi)容陸續(xù)奉上。
文章有幫助的話,在看,轉發(fā)吧。
謝謝支持喲 (*^__^*)

