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


